数组首地址a,&a,&a[0]
注:a,&a,&a[0]的含义虽然不同,但是他们三个的值是相等的!
以int a[3]为例说明:
1. a作为右值时,代表数组首元素的首地址,而非数组地址。 也就是a[0]的地址。int i = (a+1),这里a是右值,所以代表首元素的首地址,a+1代表下一个元素的首地址,即&a[1]。
2. a是整个数组的名字。所以sizeof(a)的值为sizeof(int) * 3 = 40,代表整个数组的大小。
3. &a即为取a的首地址,也即整个数组的首地址。所以sizeof(&a) = 4。 int p = (int)(&a+1)中的&a+1代表下一个数组的首地址,显然是越界的。
4. &a[0]代表首元素的首地址。 所以sizeof(&a[0]) = 4。
5. &a[3],很显然数组越界了,但它的sizeof是多少呢? 也是4,因为关键字sizeof求值是在编译的时候,虽然并不存在a[3]这个元素,但是这里并没有真正访问a[3],而是根据数组元素类型来确定其值的。所以sizeof(a[3])不会出错。
6. a[-1]代表什么意思?首先要明白下标的形式被编译器解析成指针的形式,即a[1]被解析成(a+1)。那么,a[-1]被解析成*(a-1)。
关于数组首元素的首地址和数组的首地址的区别:其实,数组首元素的首地址和数组首地址的值是相同的,即&a[0]和a(以及&a)是相等的,但是而这含义不一样。首元素的首地址加1后,是第二个元素的首地址(之所以一直说首地址,是因为有的类型存储时会占多个地址),但数组的首地址加1后是“下一个数组的地址”,这里的下一个数组只是为了说明加1时加了整个数组的大小,而不是一个元素的大小。
有一点比较容易混淆:a虽然代表整个数组,但(a+1)却代表下一个元素的首地址,即和(&a[0]+1)一样,下一个数组的形式为:(&a+1)。 下面以一个程序来说明:
#include
int main()
{
int a[3]= {1, 2,3};
printf("%ld/n",sizeof(long unsigned int));
printf("*(a+1)=%d/n",*(a+1));
printf("sizeof(a)=%ld/n",sizeof(a));
printf("sizeof(&a[3])=%ld/n",sizeof(&a[3]));
printf("a[-1]=%d/t*(a-1)=%d/n",a[-1],*(a-1));
printf("a=%p/t&a=%p/t&a[0]=%p/n",a,&a,&a[0]);
printf("a=%p/t(a+1)=%p/t(&a+1)=%p/n",a,(a+1),(&a+1));
return 0;
}
输出结果:
8
*(a+1)=2
sizeof(a)=12
sizeof(&a[3])=8
a[-1]=0 *(a-1)=0
a=0x7fffcb4cb980 &a=0x7fffcb4cb980 &a[0]=0x7fffcb4cb980
a=0x7fffcb4cb980 (a+1)=0x7fffcb4cb984 (&a+1)=0x7fffcb4cb98c
说明(下面的行数只计算main函数内有代码的行):
1. 程序第1行定义了一个具有3个元素的整型数组。
2. 第2行打印了long型的大小。因为我是64bit的,所以一个long是8byte。
3. 第3行打印了*(a+1)的值,结果和a[1]的值相等。说明a虽然代表整个数组,但作为右值时,的确代表首元素的首地址。
4. 第4行输出值为12,是整个数组的大小。
5. 第5行打印了一个出界元素的大小,没有报错,验证了上面第5条。
6. 第6行打印了a[-1]和*(a-1),输出值相等。验证了上面第6条。
7. 第7行打印了a和&a[0],值相等。说明数组的首地址和首元素的首地址是相等的。
8. 第8行打印了a,(a+1),(&a+1),由结果就可以看出首元素的首地址加1是加了一个数组元素的大小,而数组首地址加1是加了一个数组的大小。
数组首地址a,&a,&a[0]
注:a,&a,&a[0]的含义虽然不同,但是他们三个的值是相等的!
以int a[3]为例说明:
1. a作为右值时,代表数组首元素的首地址,而非数组地址。 也就是a[0]的地址。int i = (a+1),这里a是右值,所以代表首元素的首地址,a+1代表下一个元素的首地址,即&a[1]。
2. a是整个数组的名字。所以sizeof(a)的值为sizeof(int) * 3 = 40,代表整个数组的大小。
3. &a即为取a的首地址,也即整个数组的首地址。所以sizeof(&a) = 4。 int p = (int)(&a+1)中的&a+1代表下一个数组的首地址,显然是越界的。
4. &a[0]代表首元素的首地址。 所以sizeof(&a[0]) = 4。
5. &a[3],很显然数组越界了,但它的sizeof是多少呢? 也是4,因为关键字sizeof求值是在编译的时候,虽然并不存在a[3]这个元素,但是这里并没有真正访问a[3],而是根据数组元素类型来确定其值的。所以sizeof(a[3])不会出错。
6. a[-1]代表什么意思?首先要明白下标的形式被编译器解析成指针的形式,即a[1]被解析成(a+1)。那么,a[-1]被解析成*(a-1)。
关于数组首元素的首地址和数组的首地址的区别:其实,数组首元素的首地址和数组首地址的值是相同的,即&a[0]和a(以及&a)是相等的,但是而这含义不一样。首元素的首地址加1后,是第二个元素的首地址(之所以一直说首地址,是因为有的类型存储时会占多个地址),但数组的首地址加1后是“下一个数组的地址”,这里的下一个数组只是为了说明加1时加了整个数组的大小,而不是一个元素的大小。
有一点比较容易混淆:a虽然代表整个数组,但(a+1)却代表下一个元素的首地址,即和(&a[0]+1)一样,下一个数组的形式为:(&a+1)。 下面以一个程序来说明:
#include
int main()
{
int a[3]= {1, 2,3};
printf("%ld/n",sizeof(long unsigned int));
printf("*(a+1)=%d/n",*(a+1));
printf("sizeof(a)=%ld/n",sizeof(a));
printf("sizeof(&a[3])=%ld/n",sizeof(&a[3]));
printf("a[-1]=%d/t*(a-1)=%d/n",a[-1],*(a-1));
printf("a=%p/t&a=%p/t&a[0]=%p/n",a,&a,&a[0]);
printf("a=%p/t(a+1)=%p/t(&a+1)=%p/n",a,(a+1),(&a+1));
return 0;
}
输出结果:
8
*(a+1)=2
sizeof(a)=12
sizeof(&a[3])=8
a[-1]=0 *(a-1)=0
a=0x7fffcb4cb980 &a=0x7fffcb4cb980 &a[0]=0x7fffcb4cb980
a=0x7fffcb4cb980 (a+1)=0x7fffcb4cb984 (&a+1)=0x7fffcb4cb98c
说明(下面的行数只计算main函数内有代码的行):
1. 程序第1行定义了一个具有3个元素的整型数组。
2. 第2行打印了long型的大小。因为我是64bit的,所以一个long是8byte。
3. 第3行打印了*(a+1)的值,结果和a[1]的值相等。说明a虽然代表整个数组,但作为右值时,的确代表首元素的首地址。
4. 第4行输出值为12,是整个数组的大小。
5. 第5行打印了一个出界元素的大小,没有报错,验证了上面第5条。
6. 第6行打印了a[-1]和*(a-1),输出值相等。验证了上面第6条。
7. 第7行打印了a和&a[0],值相等。说明数组的首地址和首元素的首地址是相等的。
8. 第8行打印了a,(a+1),(&a+1),由结果就可以看出首元素的首地址加1是加了一个数组元素的大小,而数组首地址加1是加了一个数组的大小。
举报