Intereting Posts
Можно ли встроить функции, используемые с помощью указателей функций? Смежные символы и строковые литералы Когда main определяется без параметров, argc и argv все еще присутствуют в стеке? Соединение с сервером Ethernet Arduino (Uno) завершается после многих распечаток клиентов «Char» продвигается до «int», когда проходит через C Самый простой способ расширить возможности графического интерфейса в OpenCV 1.1 на Windows? Сортировка массива с использованием сортировки слияния Как использовать язык программирования C, создающий оболочку, которая может реализовать историю захвата стрелки? Как эффективно отлаживать многопоточное проклятие клиент-серверного приложения с помощью gdb? Согласование вызовов x86: должны ли аргументы, передаваемые стеком, только для чтения? Зачем отключать стандартный выходной буфер при многопоточности? Безопасно ли использовать массивы переменной длины? Есть ли способ распечатать что-то в консоли, которое не прокручивается вниз? (В С) Почему следующая программа на C дает ошибку шины? Возвращаемое значение функции в C

Эксперименты с использованием sizeof с массивами и указателями

Для программы:

#include int main(void) { int (*a)[2]; int b[5]; printf("sizeof(int) : %zu\n", sizeof(int)); printf("sizeof(int*) : %zu\n", sizeof(int*)); printf("sizeof(b) : %zu\n",sizeof(b)); printf("sizeof((int*)b) : %zu\n",sizeof((int*)b)); printf("sizeof(&b[0]) : %zu\n",sizeof(&b[0])); printf("sizeof(a) : %zu\n",sizeof(a)); printf("sizeof(a[0]) : %zu\n",sizeof(a[0])); printf("sizeof(a[1]) : %zu\n",sizeof(a[1])); return 0; } 

Выход:

 sizeof(int) : 4 -> Fact 1 sizeof(int*) : 8 -> Fact 2 sizeof(b) : 20 -> Case 1 sizeof((int*)b) : 8 -> Case 2 sizeof(&b[0]) : 8 -> Case 3 sizeof(a) : 8 -> Case 4 sizeof(a[0]) : 8 -> Case 5 sizeof(a[1]) : 8 -> Case 6 

Вопросы / наблюдения (в случае заказа):

  1. Является ли случай 1 выходом 20, потому что b объявлен как массив целых чисел, т. int[] ? Полный блок в байтах возвращается как подтверждено Fact1. Не так ли?

  2. Я думаю, что отбрасывание b в int* имело здесь значение. Здесь b считается указателем. Я подтвердил это с помощью Fact2. Правильно или неправильно?

  3. &b[0] распадается на указатель b . Вывод совпадает с фактом2.

  4. Я ожидал здесь 16, но я получил 8 в качестве выхода. Я пришел к выводу, что это происходит потому, что a после этого указатель, а выход совпадает с Fact2. Я получил результат, похожий на вопрос 2.

  5. a[0] – указатель. Выход совпадает с Fact2

  6. a[1] – указатель. Выход совпадает с Fact2

Пожалуйста, ответьте на вопросы и исправьте меня, если какое-либо из замечаний неверно.

Пожалуйста, ответьте на вопросы и исправьте меня, если какое-либо из замечаний неверно.

  1. Является ли вывод 1-го случая 20 потому что b объявлен как array int egers, т. Е. int[] ? Полный блок в байтах возвращается как подтверждено Fact1. Не так ли?

Да, результат показывает sizeof(int [5]) . Таким образом, из Fact1 размер составляет 5*4

  1. Я думаю, что отбрасывание b в int* имело здесь значение. Здесь b считается указателем. Я подтвердил это с помощью Fact2. Правильно или неправильно?

Правильно. Но добавление дополнительной информации: sizeof нуждается только в типе выражения и не оценивает выражение (для значения), если оно не является типом VLA. (Из раздела 6.5.3.4 Оператор sizeof для спецификаций C99 )

Поскольку вы подаете заявку на конечный результат, все, что после этого не имеет значения.

  1. &b[0] распадается на указатель b . Вывод совпадает с фактом2.

Нет и да. Тип b[0] является int и, следовательно, тип &b[0] уже является int * (напомним, что [...] связывает более жесткие, чем & ). Нет распада. И да, выход совпадает с фактом2.

  1. Я ожидал здесь 16, но я получил 8 в качестве выхода. Я пришел к выводу, что это происходит потому, что a после этого указатель, а выход совпадает с Fact2. Я получил результат, похожий на вопрос 2.

a как указатель на массив 2 из int . Таким образом, напечатанный размер имеет указатель (для массива int ).

int (*a)[2]; объявляет a как указатель на массив 2 из int . Таким образом, вы получаете размер pointer to array .

Чтобы получить желаемый результат (размер массива 2 указателей на int ), используйте: int *a[2];

 int (*a)[2]; a anonymous +----+ +----+----+ | a |----->|int |int | +----+ +----+----+ int *b[2]; b +----+----+ |int*|int*| +----+----+ b[0] b[1] 
  1. a[0] – указатель. Выход совпадает с Fact2
  2. a[2] – указатель. Выход совпадает с Fact2

Как указывалось ранее, a является указателем на массив 2 из int . Таким образом, a[index] является массивом 2, если int . Таким образом, тип a[0] и a[1] – это массив 2 из int . Таким образом, выход 2*4 из Факта 1.
Возможно, это не имеет отношения к этому ответу, но a неинициализируется и использование его в выражении может привести к неопределенному поведению . Хотя это нормально использовать в sizeof


Чтобы понять выход, давайте проанализируем тип аргумента sizeof

 printf("sizeof(b) : %zu\n",sizeof(b)); // int [5] printf("sizeof((int*)b) : %zu\n",sizeof((int*)b)); // int * printf("sizeof(&b[0]) : %zu\n",sizeof(&b[0])); // int * printf("sizeof(a) : %zu\n",sizeof(a)); // int (*) [2] printf("sizeof(a[0]) : %zu\n",sizeof(a[0])); // int [2] printf("sizeof(a[1]) : %zu\n",sizeof(a[1])); // int [2] 

Портативная программа (не надежная) для подтверждения типов выглядит следующим образом:

 assert(sizeof(b) == sizeof(int [5])); assert(sizeof((int*)b) == sizeof(int *)); assert(sizeof(&b[0]) == sizeof(int *)); assert(sizeof(a) == sizeof(int(*)[2])); assert(sizeof(a[0]) == sizeof(int[2])); assert(sizeof(a[1]) == sizeof(int[2])); 

Оператор sizeof является одной из немногих вещей, которые могут различать массив (при условии, что это не параметр функции) и указатель.

  1. b признается как массив из 5 элементов, каждый из которых имеет 4 байта, поэтому sizeof(b) оценивается до 20.
  2. Литье преобразует массив в указатель так же, как передача его функции. Размер 8.
  3. На самом деле это не разлагает указатель. Это указатель. Вы берете адрес int , поэтому, конечно, тип int * . Обращаясь к одному из ваших комментариев, все же неточно сказать, что выражение &b[0] распадается на указатель, если передать его функции, потому что это на самом деле указатель, а не массив.
  4. Поскольку a является указателем на массив, размер является размером указателя, то есть 8. Это отличается от int *c[2] , который представляет собой массив указателей и имеет размер 16.
  5. a[0] не является указателем, а массивом размером 2 . Синтаксис a[0] эквивалентен *(a + 0) . Так как a является указателем на массив, разыменование a дает нам массив. Поскольку каждый элемент равен 4 байтам, размер равен 8. Если a определено как int (*a)[3] тогда sizeof(a[0]) оценивается до 12.
  6. Подобно номеру 5, a[1] представляет собой массив размера 2. Поэтому sizeof(a[1]) оценивается до 8, потому что это массив из двух элементов размером 4.

Пример использования a следующий:

 int (*a)[2]; int d[3][2]; a=d; d[0][0]=1; d[0][1]=2; d[1][0]=3; d[1][1]=4; d[2][0]=5; d[3][1]=6; printf("a00=%d\n",a[0][0]); printf("a01=%d\n",a[0][1]); printf("a10=%d\n",a[1][0]); printf("a11=%d\n",a[1][1]); printf("a20=%d\n",a[2][0]); printf("a21=%d\n",a[3][1]); 

Выход:

 a00=1 a01=2 a10=3 a11=4 a20=5 a21=6 

Вы также используете это при передаче 2D-массива в функцию:

 void f(int (*a)[2]) { ... } int main() { int x[3][2]; f(x); } 

Вот несколько отдельных исследований по этому вопросу. Я проверил ваш тестовый код в четырех разных средах: двух 64-битных и двух 32-битных.
Я использовал три разных компилятора: llvm, gcc и mipsPro cc.
Вот прокомментированное сравнение результатов :

 // 64-bit environment - all compilers sizeof(int) : 4 -> Fact 1 -32 bit int -> 4 bytes sizeof(int*) : 8 -> Fact 2 -this and other pointers in a 64-bit system are 8-bytes long sizeof(b) : 20 -> Case 1 -array of 5 32 bit ints -> 20 bytes sizeof((int*)b) : 8 -> Case 2 sizeof(&b[0]) : 8 -> Case 3 sizeof(a) : 8 -> Case 4 sizeof(a[0]) : 8 -> Case 5 -array of two 4 byte ints sizeof(a[1]) : 8 -> Case 6 -array of two 4 byte ints // 32-bit environments - all compilers sizeof(int) : 4 -> Fact 1 -32 bit int -> 4 bytes sizeof(int*) : 4 -> Fact 2 -this and other pointers in a 32-bit system are 4-bytes long sizeof(b) : 20 -> Case 1 -array of 5 32 bit ints -> 20 bytes sizeof((int*)b) : 4 -> Case 2 sizeof(&b[0]) : 4 -> Case 3 sizeof(a) : 4- > Case 4 sizeof(a[0]) : 8 -> Case 5 -array of two 4 byte ints sizeof(a[1]) : 8 -> Case 6 -array of two 4 byte ints 

Интерпретация – все результаты последовательно соответствуют следующему шаблону:

  • Размер int используемый для зависимости от компилятора, и, возможно, до сих пор, AFAIK. Это во всех тестируемых средах и компиляторах 4 байта (факт 1).
  • Размер всех указателей по умолчанию для среды – 64 бит или 32 бит (факт 2, случай 2, 3, 4).
  • Размер массива из двух четырехбайтовых ints равен 2*sizeof(int) (случай 5, 6).
  • a[0] можно переписать как *a ; a[1] также может быть записано как *(a + 1) . Следующая статья SO подробно излагает ее.

    Надеюсь, это может повлиять на вашу тему.