我在我的书(以及互联网上的许多来源)中读到了这一点:
数组变量指向到数组中的第一个元素。
如果是,则数组变量和第一个元素不同。正确?
这意味着通过以下代码,它将产生两种不同的结果:
int main(){
char msg[] = "stack over flow";
printf("the store string is store at :%p\n",&msg);
printf("First element: %p\n",&msg[0]);
}
但是我收到了两个案例的相同结果。所以,通过这个例子,我认为应该说:数组变量是第一个元素。 (因为它有相同的地址)
我不知道这是真还是错。请教我。
答案 0 :(得分:8)
数组变量表示数组占用的整个内存块,而不仅仅是数组的第一个元素。因此array
不与array[0]
相同(参见sizeof array / sizeof array[0]
)。但是数组的第一个元素与数组本身位于相同的内存地址。
说数组指向第一个元素也是不正确的,在大多数情况下,数组表达式衰变为指向其第一个元素的指针,但它们是不同的东西(例如,再次参见sizeof
)。 / p>
答案 1 :(得分:5)
他们指向相同的地址,即printf
会显示相同的值,但它们的类型不同。
&msg
的类型是char(*)[16]
,指向char &msg[0]
的类型是char *
,指向char的指针测试这个的一种便宜的方法是做一些指针算术。尝试打印&msg + 1
。
此C FAQ可能有用。
答案 2 :(得分:5)
数组变量 整个数组。它衰减成指向数组第一个元素的指针。
如果你看一下类型:
msg
的类型为char [16]
&msg
的类型为char (*)[16]
&msg[0]
的类型为char *
因此,在msg
可以衰减到数组的上下文中,例如作为参数传递时,其值将等于&msg[0]
。
让我画出这个:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
|s|t|a|c|k| |o|v|e|r| |f|l|o|w|\0|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--+
想象一下这个数组的起点,'s'
所在的地址是地址0x12345678
。
msg
本身,指的是整个16字节的内存。就像你说int a;
时一样,a
指的是4个字节的内存。msg[0]
是该16个字节的第一个字节。&msg
是数组开始的地址:0x12345678
&msg[0]
是数组的第一个元素的地址:0x12345678
这就是为什么&msg
和&msg[0]
的值相同,但它们的类型不同。
现在问题是,msg
本身并不是头等公民。例如,您无法分配数组。这就是为什么在大多数情况下,数组会衰减到它的指针。
如果你知道函数指针,这非常相似:
int array[10];
int function(int);
int *var = array
中,array
衰减到指针(&array
)void *var = function
中,function
衰减到指针(&function
)注意,在函数指针的情况下,我们喜欢保留类型,所以我们写:
int (*var)(int) = function;
同样,您可以使用数组:
int (*var)[10] = array;
答案 3 :(得分:2)
char myChar = 'A'
char msg[] = 'ABCDEFGH'
当您输入 myChar 时,您会获得价值。 但是使用 msg ,您将获得指向第一个字符的指针(对于必须使用msg [x]的值)
msg = &msg[0]
我认为这可以帮助你理解。
答案 4 :(得分:1)
这样看:
&msg = 0x0012
&msg[0] = 0x0012
&msg[1] = 0x0013
在这种情况下,&msg[1]
指向msg+1
。当您引用&msg
或&msg[0]
时,您指的是相同的内存地址,因为这是指针开始的位置。增加数组变量会使指针增加+1,因为char变量的大小只有1个字节。
如果你用一个整数做同样的技巧,你会将指针增加+4个字节,因为整数是4个字节。
答案 5 :(得分:1)
使用数组表达式时,编译器会将其转换为指向第一个元素的指针。这是由1999 C标准在6.3.2.1中指定的显式转换3.这对您来说很方便,因此您不必编写&array[0]
来获取指向第一个元素的指针。
转换发生在所有表达式中,除非数组表达式是sizeof
或一元&
的操作数,或者是用于初始化数组的字符串文字。
通过打印sizeof array
和sizeof array[0]
,您可以看到数组及其第一个元素不同。
答案 6 :(得分:1)
在大多数情况下,数组类型的表达式(“T
的N元素数组”)将被/转换为/“decay”替换为指针类型的表达式(“指向T
”的指针),表达式的值将是数组中第一个元素的地址。
所以,假设声明
int a[10];
表达式a
的类型是“int
”的10个元素数组,或int [10]
。但是,在大多数情况下,表达式的类型将转换为“指向int
”或int *
的指针,表达式的值将等同于&a[0]
。
此规则的例外情况是数组表达式是sizeof
或一元&
运算符的操作数,或者是用于初始化声明中另一个数组的字符串文字。
因此,根据我们上面的声明,以下所有内容都是正确的:
Expression Type Decays to Value ---------- ---- --------- ----- a int [10] int * address of the first element of a &a int (*)[10] n/a address of the array, which is the same as the address of the first element &a[0] int * n/a address of the first element of a *a int n/a value of a[0] sizeof a size_t n/a number of bytes in the array (10 * sizeof (int)) sizeof &a size_t n/a number of bytes in a pointer to an array of int sizeof *a size_t n/a number of bytes in an int sizeof &a[0] size_t n/a number of bytes in a pointer to int
请注意,表达式a
,&a
和&a[0]
都具有相同的值(a
的第一个元素的地址) ,但类型不同。类型很重要。假设如下:
int a[10];
int *p = a;
int (*pa)[10] = &a;
p
和pa
都指向a
的第一个元素,我们假设它位于地址0x8000
。执行行
p++;
pa++;
但是,p
指向下一个整数(0x8004
,假设为4字节int
s),而pa
指向next 10个元素的整数数组;也就是说,a
(0x8028
)的最后一个元素之后的第一个整数。