Учитывая `int num [7]`, как `num`,` & num [0] `,` & num` отличаются?

Я прочитал в книге C, что для массива num[7] термин num эквивалентен &num[0]. Эта концепция работала отлично для меня, но когда я написал эту программу, показанную ниже, я снова запутался.

#include<stdio.h>
#include<conio.h>
int main()
{
    int num[]={21,22,23,24,25,26,27};
    int *x,*y,*z;
    x=&num;
    y=num;
    z=&num[0];
    printf("%d   %d   %d\n",sizeof(x),sizeof(y),sizeof(z));
    printf("%d  %d  %d\n",sizeof(&num),sizeof(num),sizeof(&num[0]));
    printf("%d   %d   %d",*(&num),*(num),*(&num[0]));
    getch();
    return 0;  
}

:

      4    4    4
      4    28   4
      2293536   21   21

Если num идентично &num[0], то почему существует разница в их размере? И что это за третий тип термина &num? Я знаю, что он показывает стоимость мусора, но имеет ли смысл этот термин? z=&num[0] Я уже понимаю. Компилятор показывает предупреждение для назначения x=&num, но для y=num; у компилятора нет никаких проблем. Если num имеет размер 28, то почему он получил привязку к целочисленному указателю y без typecast?

Затем я попытался на 2-й массив таким образом:

#include<stdio.h>
#include<conio.h>
int main ()
{
    int s[4][2]={{1234,56},{1235,57},{1236,58},{1237,59}};
    int i
    printf ("\n%d %d %d %d %d",sizeof(s[i]),sizeof(&s[i]),sizeof(s),
        sizeof(s[0][0]),sizeof(&s));
    getch();
    return 0;
}

Теперь выход

8  4  32  4   4

Здесь sizeof(s[i]) есть 8. потому что s[i] является одномерным массивом, и он имеет два элемента, так что это нормально. Но я не знаю, что означают термины &s[i] и &s. И я снова могу видеть, что s не идентичен s[0][0]. Я использовал версию Dev С++ 4.9.9.2 для запуска всех программ. Я хочу быть понятным в этих трех типах терминов.

Ответ 1

Ничего себе, много вопросов за один раз: P

Сначала я попытаюсь объяснить вам этот вывод:

  4    4    4
  4    28   4
  2293536   21   21

sizeof() является унарным оператором в c. Он заменяется целым числом, когда код компилируется, а не во время выполнения. Поэтому компилятор грамотно изменяет ваши printfs на:

 printf("%d   %d   %d\n", 4, 4, 4);
 printf("%d  %d  %d\n", 4, 28, 4);
 printf("%d   %d   %d",*(&num),*(num),*(&num[0]));

На ранней стадии компиляции.

Компилятор достаточно доволен, чтобы дать вам размер всего массива при написании sizeof(num). То, как sizeof определено для работы с массивами. Все остальные элементы дают вам размер (int *), кроме sizeof (& num), который дает вам размер (int **) (int ** имеет тот же размер, что и int *).

  • & num - расположение памяти указателя на ваш массив
  • num, и num [0], является ячейкой памяти первого int в вашем массиве

За второй вопрос:

printf("\n%d %d %d %d %d",sizeof(s[i]),sizeof(&s[i]),sizeof(s),sizeof(s[0][0]),sizeof(&s));

 

sizeof(s[i]) - size of an array (int[2]) == 8
sizeof(&s[i]) - size of a pointer to an int array sizeof(int **) == 4
sizeof(s) - size of a 2D array containing 8 ints == sizeof(int[8]) == 32
sizeof(s[0][0]) - size of an int === 4
sizeof(&s) - size of a pointer to an array == 4

Ответ 2

Хорошие вопросы здесь. Надеюсь, мы все можем объяснить вам эти проблемы.

Учитывая

int num[]={21,22,23,24,25,26,27};

Тогда

  • num имеет тип int[], потому что это объявленный массив целых чисел, чья память распределена на месте. Обратите внимание, что он не имеет типа int*, который бы имел место, если вы его malloced.
  • sizeof(num) равно 28, потому что num - это массив из 7 int, который на вашем компьютере имеет размер 4 байта. Значение было бы 56, если ints составляло 8 байтов или 14, если у них было 2 байта, но наиболее распространено 4 байта на целое число.
  • &num[0] - это указатель типа int*, значением которого является адрес первого элемента num.
  • Размеры x и друзей 4, потому что они объявлены как указатели, которые на вашем компьютере под вашим компилятором C указатели выделяются в 4 байта.

Следует иметь в виду, что когда массив используется в определенных контекстах, например, передается как параметр, он преобразуется в int*. Вот почему вы можете сказать *num и получить 21. Трюк, но как это. Вот почему обычно можно обменивать num и &num[0], но вы действительно должны учитывать это различие, потому что, как вы заметили, значения sizeof отличались.

Преобразование - это то, почему y = num имеет смысл. y имеет тип int*, а в C вы получаете автоматическое преобразование из int[] TO int*. Вы не можете сделать x = &num, потому что тип &num является "указателем на массив int". Вы не можете назначить это int* (указатель на int).

В случае

int s [4] [2] = {{1234,56}, {1235,57}, {1236,58}, {1237,59}};

Мы имеем тип s как int[][], тип &s как pointer to int[][] и тип &s[i] как указатель на int[] (потому что s[i] - массив int). Из-за того, как C позволяет назначать/передавать массивы указателям, вы можете играть в те же игры, что и в первом примере.

Вы заметите, что s, &s[0] и &s[0][0] все указывают на одинаковые места памяти, но, как вы заметили, значения sizeof будут разными.

Ответ 3

Ваши противоречия действительны. Это не случай, когда num эквивалентен &num[0]. Это просто ложно. Массивы представляют собой отдельный тип указателей, а num относится к объекту с типом int[7], а не int*. Вот почему размер отличается, например, потому что один является непрерывным набором из семи целых чисел.

Обратите внимание, что если необходимо, num может быть преобразовано в int* со значением &num[0]. Конечно, преобразование - это не то же самое, что эквивалентность. Вы найдете эту путаницу между массивами и указателями, которые странно видны, потому что люди повторяют ложность, что массивы являются указателями. Это не так.

Ответ 4

Теперь мой вопрос: если num идентичен & num [0], то почему существует разница там размер?

num - массив. sizeof имеет иногда удивительное поведение для массивов, которое заключается в том, что он сообщает вам размер хранилища всего массива, если вы передаете ему фактический массив, но он сообщает только размер указателя на элемент в массиве, если вы пройдете это адрес такого элемента. Это может привести к путанице, поскольку имя массива ухудшается до указателя на вызовы функций.

Итак, ответ заключается в том, что num не идентичен &num[0] - последний является адресом первого элемента num, при этом вся информация об общем размере массива удаляется. Эти две вещи взаимозаменяемы во многих контекстах, таких как вызов фактических функций, но не при вызове sizeof (который не является функцией, а специальным ключевым словом, обработанным компилятором).