Учитывая `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=#
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
(который не является функцией, а специальным ключевым словом, обработанным компилятором).