Poschitat
Программист 1С ?
А еще есть #array+1
Тащемта sizeof не функция, а оператор, и считает он не длину массива, а количество байтов в любой поеботе, включая массив...
.length тоже не функция/метод, а совершение доступа к полю массива.
Ну, в шарпе это реализовано как вызов геттера/сеттера. А обращаться к полям - нельзя. Инкапсуляция-с.
Гы, а в джаве это как раз поле. Final-ное, правда, присваивать ему ничего нельзя, так что с инкапсуляцией проблем в общем тут нет...
таки да,а есть еще и расширение для linq с лямбда выражением в параметрах
> а количество байтов в любой поеботе, включая массив...
Только для статических массивов, которые в текущей области видимости известны именно как массив. В противном случае - размер указателя.
// OK
int a[4];
sizeof(a);
// OK
void foo(int a[4]){sizeof(a);}
// FAIL - будет размер указателя
void foo(int* a){sizeof(a);}
Только для статических массивов, которые в текущей области видимости известны именно как массив. В противном случае - размер указателя.
// OK
int a[4];
sizeof(a);
// OK
void foo(int a[4]){sizeof(a);}
// FAIL - будет размер указателя
void foo(int* a){sizeof(a);}
Технически, в C указатель и не является массивом. Если ты передаешь массив интов в функцию, которая принимает указатель на инт, массив decay-нется до указателя на свой первый элемент. Вообще, если я правильно помню, массив decay-ится до этого указателя практически при любом использовании, за исключением sizeof (ну и ситуации с указателем-на-массив, типа такого: int func(int (*arr)[10]) и func(&arr), но это уже наркомания).
Кстати, твой второй пример неправильный - 4-ка там будет проигнорирована, и это будет эквивалентно void foo(int a[]){sizeof(a);}, и, соответственно, эквивалентно void foo(int *a){sizeof(a);}, то бишь тебе тоже выдаст размер указателя. Можешь проверить.
Кстати, твой второй пример неправильный - 4-ка там будет проигнорирована, и это будет эквивалентно void foo(int a[]){sizeof(a);}, и, соответственно, эквивалентно void foo(int *a){sizeof(a);}, то бишь тебе тоже выдаст размер указателя. Можешь проверить.
Правда ваша про второй пример. Где-то давно читал про какой-то трюк, как это обойти, видимо, попутал. Сам таких извращений не использую.
Что ты имеешь в виду под "обойти"? Если ты про передачу чего-то, на что можно вызвать sizeof, то тут применим трюк с указателем на массив, о котором я упомянул (int func(int (*arr)[10]) , пример: https://ideone.com/n3GUke). Это имеет свои применения - можно таким образом прописать, что твоя функция принимает массив только конкретного размера. Например, таким образом удобно прописывать матрицу как массив массивов (указатель на массив[ы]).
Если ты про то, чтобы передавать массив by-value, то можно запхать его в struct или union и уже их передавать by-value. Это иногда очень полезно, например, может быть удобно иметь union с uint32_t и массивом из 4 uint8_t, и его таким манером передавать в функции. Получится, что ты технически передаешь массив by-value!
Если ты про то, чтобы передавать массив by-value, то можно запхать его в struct или union и уже их передавать by-value. Это иногда очень полезно, например, может быть удобно иметь union с uint32_t и массивом из 4 uint8_t, и его таким манером передавать в функции. Получится, что ты технически передаешь массив by-value!
что-то вы заплели простой вопрос. Массив в C трактуется как указатель только в одном контексте - в качестве формального параметра функции. На самом деле это и есть указатель на первый элемент фактического массива, а возможность описать его в функции как массив - чисто для удобства и выразительности. В любом другом контексте (static, auto, extern, компонент struct) массив - это именно массив, и sizeof учитывает его размерность, как бы она ни задавась - явно или через длину инициатора (если размерность никак не задана, например в extern, то это incomplete type, и применение sizeof некорректно). Более того, начиная с C99 допускаются variable length arrays, и sizeof в общем случае вычисляется уже на этапе выполнения.
Вот пример (компилируется gss -std=c99 ...):
#include
#include
static float farr[23];
typedef long la[80];
extern double exarr[];
extern double exarr_def[4];
static void f1(int n, short lfarr[77]) {
struct {
double d[n];
int n;
} s;
printf("In f1(): sz(%u)=%u\n", n, sizeof(s)); // n * sizeof(double) + sizeof(int)
// >= n * 8 + 4
printf("In f1(): sz(lfarr)=%u\n", sizeof(lfarr)); // sizeof(short *) == 4 || 8
}
int main(int ac, char **av) {
short lfarr[77];
static long long ll[] = {1, 2, 3};
if (ac != 2) {
fprintf(stderr, "Usage: %s num\n", av[0]);
exit(1);
}
f1(atoi(av[1]), lfarr);
printf("sz(farr)=%u\n", sizeof(farr)); // 23 * sizeof(float) == 92
printf("sz(lfarr)=%u\n", sizeof(lfarr)); // 77 * sizeof(short) == 154
printf("sz(char [20]))=%u\n", sizeof(char [20])); // 20 * sizeof(char) == 20
printf("sz(long)=%u\n", sizeof(long)); // sizeof(long) == 8
printf("sz(la)=%u\n", sizeof(la)); // 80 * sizeof(long) == 640
printf("sz(long long)=%u\n", sizeof(long long)); // sizeof(long long) == 8
printf("sz(ll)=%u\n", sizeof(ll)); // 3 * sizeof(long long) == 24
// printf("sz(exarr)=%u\n", sizeof(exarr)); // unknown
printf("sz(exarr_def)=%u\n", sizeof(exarr_def)); // 4 * sizeof(double) == 32
}
Вот пример (компилируется gss -std=c99 ...):
#include
#include
static float farr[23];
typedef long la[80];
extern double exarr[];
extern double exarr_def[4];
static void f1(int n, short lfarr[77]) {
struct {
double d[n];
int n;
} s;
printf("In f1(): sz(%u)=%u\n", n, sizeof(s)); // n * sizeof(double) + sizeof(int)
// >= n * 8 + 4
printf("In f1(): sz(lfarr)=%u\n", sizeof(lfarr)); // sizeof(short *) == 4 || 8
}
int main(int ac, char **av) {
short lfarr[77];
static long long ll[] = {1, 2, 3};
if (ac != 2) {
fprintf(stderr, "Usage: %s num\n", av[0]);
exit(1);
}
f1(atoi(av[1]), lfarr);
printf("sz(farr)=%u\n", sizeof(farr)); // 23 * sizeof(float) == 92
printf("sz(lfarr)=%u\n", sizeof(lfarr)); // 77 * sizeof(short) == 154
printf("sz(char [20]))=%u\n", sizeof(char [20])); // 20 * sizeof(char) == 20
printf("sz(long)=%u\n", sizeof(long)); // sizeof(long) == 8
printf("sz(la)=%u\n", sizeof(la)); // 80 * sizeof(long) == 640
printf("sz(long long)=%u\n", sizeof(long long)); // sizeof(long long) == 8
printf("sz(ll)=%u\n", sizeof(ll)); // 3 * sizeof(long long) == 24
// printf("sz(exarr)=%u\n", sizeof(exarr)); // unknown
printf("sz(exarr_def)=%u\n", sizeof(exarr_def)); // 4 * sizeof(double) == 32
}
виноват, в предыдущем посте, конечно gcc, а не gss а include подключают stdio.h и stdlib.h. Кстати - как избежать здесь интерпретации спец. HTML символов, неужели писать \< \>
Ну нет, не только в контексте формального параметра функции. Например, можно еще так:
int a[10];
int *a2 = a;
Или вообще так:
int a[10];
a[0] = 1;
printf("%d\n", *a); // выдаст 1
Даже больше тебе скажу:
int a[10];
printf("%p %p\n", a, a + 1); // высрет 2 числа с 4 байтами разницы
Однако:
int a[10];
printf("%p %p\n", a, &a + 1); // высрет 2 числа с 40 байтами разницы
При decay-инге массив не "трактуется как указатель" - это фактически implicit cast в указатель на 0-й элемент.
То, что ты описал, это просто разные способы этот массив создать. Суть того, что я сказал, от этого не меняется - где бы ты массив не задавал, на каждый чих в его направлении, за исключением sizeof и & (вроде только их, если мне память не изменяет, а в доки/стандарт лезть лень), массив будет схлопываться в указатель на свой 0-й элемент.
И знаю я, что такое VLA-шники! И при чем тут вообще вопрос о том, когда считается этот самый sizeof? Да даже при вызове на VLA-шник он стопудов на адекватных компиляторах не считается-пересчитывается во время исполнения, а просто подгружает уже посчитанное для инициализации массива значение длины! И это не имеет ровно никакого значения в данном контексте...
int a[10];
int *a2 = a;
Или вообще так:
int a[10];
a[0] = 1;
printf("%d\n", *a); // выдаст 1
Даже больше тебе скажу:
int a[10];
printf("%p %p\n", a, a + 1); // высрет 2 числа с 4 байтами разницы
Однако:
int a[10];
printf("%p %p\n", a, &a + 1); // высрет 2 числа с 40 байтами разницы
При decay-инге массив не "трактуется как указатель" - это фактически implicit cast в указатель на 0-й элемент.
То, что ты описал, это просто разные способы этот массив создать. Суть того, что я сказал, от этого не меняется - где бы ты массив не задавал, на каждый чих в его направлении, за исключением sizeof и & (вроде только их, если мне память не изменяет, а в доки/стандарт лезть лень), массив будет схлопываться в указатель на свой 0-й элемент.
И знаю я, что такое VLA-шники! И при чем тут вообще вопрос о том, когда считается этот самый sizeof? Да даже при вызове на VLA-шник он стопудов на адекватных компиляторах не считается-пересчитывается во время исполнения, а просто подгружает уже посчитанное для инициализации массива значение длины! И это не имеет ровно никакого значения в данном контексте...
Давай различать указатель-тип и указатель-переменную, и, чтобы не запутаться,
называть тип "ссылка на ..." вместо "указатель на ...".
int a[10];
int *a2 = a;
void func(int *arg_p, int arg_a[10]) {
int *la;
la = a;
la = a2;
la = arg_p;
la = arg_a;
}
Здесь все переменные имеют тип "ссылка на int", то бишь 'int *'.
А вот результат трансляции в ассемблерный код:
5:ptr.c **** int *la;
6:ptr.c **** la = a;
27 .loc 1 6 0
28 000c 48C745F8 movq $a, -8(%rbp)
28 00000000
7:ptr.c **** la = a2;
29 .loc 1 7 0
30 0014 488B0500 movq a2(%rip), %rax
30 000000
31 001b 488945F8 movq %rax, -8(%rbp)
8:ptr.c **** la = arg_p;
32 .loc 1 8 0
33 001f 488B45E8 movq -24(%rbp), %rax
34 0023 488945F8 movq %rax, -8(%rbp)
9:ptr.c **** la = arg_a;
35 .loc 1 9 0
36 0027 488B45E0 movq -32(%rbp), %rax
37 002b 488945F8 movq %rax, -8(%rbp)
Отчетливо видно, что присвоение переменой 'la' имени внешнего массива 'a' отличается
от присвоения внешнего указателя 'a2' - в первом случае это непосредственный операнд
'$a' - именно адрес первого элемента массива a, во втором это содержимое
32-разрядного (или 64-разрядного) слова - указателя, размещенного по адресу '$a2',
т.е. в первом случае происходит одно разыменование, во втором - два.
Так же отчетливо видно, что присвоения 'la' указателя 'arg_p' и "массива" 'arg_a' ничем
не отличаеются - во обоих случаях происходит двойное разыменование. Кажется, Ритчи
напрасно допустил это послабление в языке, ведь ясно же было сказано
изначально, что массивы в C не передаются by value - чтобы не провоцировать
на написание неэффективных программ, но все же - (вот оно - послабление)
формальный параметр можно описать как массив - для удобства, а размерность
можно и не указывать - она все равно будет проигнорирована, ведь реально это указатель.
Кому-то это реально заплело мозги, я встречал программистов, которые на 5-ом году
активного использования C линковали 2 объектника, в исходниках одного
из которых писали 'int a[10]',
а в исходниках другого 'extern int *a', и потом жаловались на 'Memory fault' или
'Segmentation violation' - мол, в компиляторе ошибка.
Так вот, еще раз: никто ничего не "схлопывает",
имя массива в любом контексте имеет тип "ссылка на" свой
элемент, но приведение массива к указателю как к объекту данных (не к типу,
а к объекту данных на уровне объектного кода!) происходит только в одном контексте -
когда формальный параметр функции описан как массив, а все потому, что фактический
параметр - это реально засунутый в стек в точке вызова 32-битный (или 64-битный)
указатель, с которым в объектном коде функции надо и обращаться как с указателем - т.е.
двойным разыменованием. Именно поэтому sizeof от
массива-формального параметра всегда будет возвращать sizeof указателя (т.е. 4 или 8
в зав-сти от арх-ры), тогда как sizeof от любого другого массива будет возвращать
именно размер массива или error в случае incomplete type.
Что касается VLA, то просто откомпилируй и выполни тот код, там длина 'n' массива
'double d[n]' задается аргументом командной строки, какое там может быть
"уже посчитанное для инициализации массива значение длины" ? Там sizeof реально
вычисляется на этапе выполнения, и при запусках с разным значением аргумента
выводятся разные значения sizeof(s), и размер фрейма стека, выделяемого
активации функции f1, вычисляется непосредственно уже в объектном коде самой функции.
называть тип "ссылка на ..." вместо "указатель на ...".
int a[10];
int *a2 = a;
void func(int *arg_p, int arg_a[10]) {
int *la;
la = a;
la = a2;
la = arg_p;
la = arg_a;
}
Здесь все переменные имеют тип "ссылка на int", то бишь 'int *'.
А вот результат трансляции в ассемблерный код:
5:ptr.c **** int *la;
6:ptr.c **** la = a;
27 .loc 1 6 0
28 000c 48C745F8 movq $a, -8(%rbp)
28 00000000
7:ptr.c **** la = a2;
29 .loc 1 7 0
30 0014 488B0500 movq a2(%rip), %rax
30 000000
31 001b 488945F8 movq %rax, -8(%rbp)
8:ptr.c **** la = arg_p;
32 .loc 1 8 0
33 001f 488B45E8 movq -24(%rbp), %rax
34 0023 488945F8 movq %rax, -8(%rbp)
9:ptr.c **** la = arg_a;
35 .loc 1 9 0
36 0027 488B45E0 movq -32(%rbp), %rax
37 002b 488945F8 movq %rax, -8(%rbp)
Отчетливо видно, что присвоение переменой 'la' имени внешнего массива 'a' отличается
от присвоения внешнего указателя 'a2' - в первом случае это непосредственный операнд
'$a' - именно адрес первого элемента массива a, во втором это содержимое
32-разрядного (или 64-разрядного) слова - указателя, размещенного по адресу '$a2',
т.е. в первом случае происходит одно разыменование, во втором - два.
Так же отчетливо видно, что присвоения 'la' указателя 'arg_p' и "массива" 'arg_a' ничем
не отличаеются - во обоих случаях происходит двойное разыменование. Кажется, Ритчи
напрасно допустил это послабление в языке, ведь ясно же было сказано
изначально, что массивы в C не передаются by value - чтобы не провоцировать
на написание неэффективных программ, но все же - (вот оно - послабление)
формальный параметр можно описать как массив - для удобства, а размерность
можно и не указывать - она все равно будет проигнорирована, ведь реально это указатель.
Кому-то это реально заплело мозги, я встречал программистов, которые на 5-ом году
активного использования C линковали 2 объектника, в исходниках одного
из которых писали 'int a[10]',
а в исходниках другого 'extern int *a', и потом жаловались на 'Memory fault' или
'Segmentation violation' - мол, в компиляторе ошибка.
Так вот, еще раз: никто ничего не "схлопывает",
имя массива в любом контексте имеет тип "ссылка на" свой
элемент, но приведение массива к указателю как к объекту данных (не к типу,
а к объекту данных на уровне объектного кода!) происходит только в одном контексте -
когда формальный параметр функции описан как массив, а все потому, что фактический
параметр - это реально засунутый в стек в точке вызова 32-битный (или 64-битный)
указатель, с которым в объектном коде функции надо и обращаться как с указателем - т.е.
двойным разыменованием. Именно поэтому sizeof от
массива-формального параметра всегда будет возвращать sizeof указателя (т.е. 4 или 8
в зав-сти от арх-ры), тогда как sizeof от любого другого массива будет возвращать
именно размер массива или error в случае incomplete type.
Что касается VLA, то просто откомпилируй и выполни тот код, там длина 'n' массива
'double d[n]' задается аргументом командной строки, какое там может быть
"уже посчитанное для инициализации массива значение длины" ? Там sizeof реально
вычисляется на этапе выполнения, и при запусках с разным значением аргумента
выводятся разные значения sizeof(s), и размер фрейма стека, выделяемого
активации функции f1, вычисляется непосредственно уже в объектном коде самой функции.
Перечитал, что написал, и понял, что опять немного погорячиллся ("имя массива в любом контексте имеет тип "ссылка на" свой элемент"): в контексте операнда sizeof и унарной '&' имя массива действительно сохраняет свой изначально декларированный тип 'type [n]' - иначе все остальное про sizeof теряет смысл.
DlinaMassiva()
Рискну побыть занудой, но .length (и схожие конструкции), вероятнее всего, не функция, а поле (переменная внутри объекта) массива, содержащее в себе длину массива. Так проще, когда длина массива задаётся разово, при его создании, и не может быть изменена в дальнейшем.
в JS это геттер, вычисляемое значение, в примере ниже длина массива будет вычисляться n+1 раз, что очень неэффекивно на больших массивах:
for (let i=0; i<arr.length; i++) { ... }
for (let i=0; i<arr.length; i++) { ... }
В общем ничего там не считается. И это не совсем getter. Это скорее поле, которое автоматически выставляется после каждой операции над массивом. А по факту просто муть в спецификации. Не совсем стандартный JS-объект со своими заморочками. Разница конечно может быть и больше 2%, но обуславливается она здесь тем, что взять поле из объекта дольше, чем воспользоваться значением из регистра. Т.е. arr.length по-любому медленнее просто n.
миллисекунда к миллисекунде, а при многомиллионных тиражах такого кода сотни тонн лишнего угля придётся сжечь для процессоров
Речь не о миллисекундах. Речь об асимптотике. Она тут O(1). В этом суть.
А это в каком языке такая чудная функция ${#}
возможно, это, но на 100% не уверен:
How do I find out bash shell array length?
${#ArrayName[@]}
How do I find out bash shell array length?
${#ArrayName[@]}
Похоже, намёк на Perl, но там не совсем так. Определить длину массива @array в Perl можно либо оценив массив в скалярном контексте оператором scalar(@array), либо получив индекс последнего элемента массива выражением $#array и прибавив 1 (так как нумерация с нуля).
А возможность изменять ключ массива не предусмотрен, или пропуска значения??? ( кмх PHP кхм )
В Perl жесткое разделение между массивами и хэшами. В PHP это смешанный тип, поэтому так можно. А еще меня в перле дико вымораживают указатели, первое время скриптил только в обнимку с Data::Dumper. Хотя в целом от перла очень положительные эмоции по итогу.
Для конкретно *массивов* - нет, было в качестве экспериментальной фичи, но в итоге выпилили. А хеши можешь индексировать любыми ключами.
только не бейте!
.Количество()
.Количество()
Ловите 1С-ника!
You do it wrong
Пока 1С-ник >= 0
Цикл
Прописать(Пиздюли[1С-ник]);
КонецЦикла;
Пока 1С-ник >= 0
Цикл
Прописать(Пиздюли[1С-ник]);
КонецЦикла;
1СПрограммист
count (и производные) - имеет сложность О(n) (то есть нужно тупо посчитать каждый элемент)
size (и производные) - имеет сложность O(1), то есть размер уже известен, его просто нужно вернуть
length (и производные) - очень непонятная херня, в разных языках веде себя и как count, и как size
size (и производные) - имеет сложность O(1), то есть размер уже известен, его просто нужно вернуть
length (и производные) - очень непонятная херня, в разных языках веде себя и как count, и как size
Уже чуть улучшили метод выбора!
Чтобы написать коммент, необходимо залогиниться