声明一个数组时,编译器将根据声明所指定的元素数量为数组保留内存空间,然后再创建数组名,它的值时一个常量,指向这段空间的起始位置。数组名是符号地址常量
( 一个常量指针,这个值不能被改变 ) ,在编译时求值并存在编译器的符号表里面,其值就是个内存地址;所以可以认为程序没有给他分配空间,数组名只是代表了那个数组空间;与指针不一样,指针指向一块空间,同时指针本身也存储在某个空间;可以认为数组名存在在符号表里,符号表是编译器用的,我们管不到;p_arr和&p_arr值是一样的,本来对常量取地址是非法的,但是标准组织没有定对数组名取地址是非法还是合法,所以因编译器而异.
引用chinaunix上一个叫dump_crash会员的发言:
C专家编程里解释的很好:经典的错误:在一个文件定义了数组,却在另外一个文件声明其为指针。代码如下:/*File name: main.c*/extern int* array; /*声明指针*/int main(void){ array[0]=1; /*用指针访问数据*/ return 0;} /*File name: def.c*/int array[5]={0}; /*定义的却是数组*/ 1。编译器对数组名和指针变量的处理方式编译器在编译时会产生一个符号表,记录了符号名和它的地址。对于指针变量,这显然很好理解。而数组名就不那么明显了,它仅仅是一个符号而已,何来地址?编译器是这样处理的,它记录了array[0]的地址;这和我们通常的理解也是一样的。2。带下标形式的数组和指针寻址方式(1)数组情形char a[9]="abcdefgh";...c=a[i];在编译期,会在符号表中创建这样一条记录:name:a address:9980要获取a[i]的值分两个步骤:step 1:取得i的值并和9980相加step 2:在内存地址(9980+i)处取其内容 (2)指针情形char* p="abcdefgh";...c=p[i];在编译期,会在符号表中创建这样一条记录:name:p address:4624要获取p[i]的值分三个步骤:step 1:在内存地址4624处取其内容,比如说“5081”step 2:取得i的值并和5081相加step 3:在内存地址(5081+i)取其内容 现在有了这些知识,前面出现的错误就很好解决了。在def.c中定义array是一个int型数组,在符号表中就会有把array和array[0]的地址关联起来。而在main.c中却把把array看作是一个int型指针,于是乎按照上面介绍的指针寻址方式,把符号表中array的地址(即&array[0])中的内容当作指针来寻址,这显然是不对的。
上面程序运行的后果是core dumped,但是这种情况和下面的还不一样:
}
输出结果
在这个例子中,注意这里面虽然print的参数arr被声明为一个貌似指针一样的东西int arr[]
但是这个东西其实和你在栈上声明的int arr[5]已经有了本质的区别,区别在哪呢?请看:
- 在栈上声明 int arr[] 是办不到的,因为编译器不能在编译的时候确定这个array的空间大小,也不能分配空间
- 在栈上声明 int arr[5]的时候,arr本身是不占用任何空间的,他的大小是数组元素的大小总和。这个符号本身并不占任何空间,这个是和指针的本质区别
- 在print函数参数中声明的int arr[]已经丧失了上面说它在的栈上本质特点,他在本质上已经变成了一个指针,你可以用sizeof看到他在64位机器上占用的空间是8个字节。而且,这次它是占用空间的有地址的,这个可以从输出的结果上看出来。
所以,当main中调用print(a)的时候,把a的值传给了arr,这个时候编译器使用指针的方式来寻址是没有问题的,因为arr其实就是一个指针,他已经不再是一个数组名称!
以上讨论了,像int arr[]的这种声明
- 不能在栈上出现
- 在函数的参数列表里面声明的时候,作用等同于指针
- 最后说一下这个东西在struct/class这样的东西里面声明
比如有这样一个声明:
先说结论:这种情况下,arr还是一个array,所以他不占用任何空间,他的存在就像是一个隐形的指针。因为他的存在不占用空间,然而你却可以像使用指针一样来使用他,你可以写obj.arr[0]=3(前提是你给obj分配了足够的空间),但是你却不能写obj.arr=&temp_integer,因为arr是一个arrar名称,是一个常量,不能被赋值。
但是,这就有了一个很尴尬的局面:
你似乎不能操作这个arr里面的内容,因为不论是在构造函数还是使用他的代码中,你都不能写arr=(int*)malloc(sizeof(int));
这个时候别急,你可以给test的对象分配更大的空间,比如:
test * obj = (test *) malloc(sizeof(test)+4)0;
这里后面+40的空间就可以被arr来使用,想要对它操作的话既可以把的值传给一个真正的指针来操作,也可以直接使用arr。
你可能会说,这种属于奇巧淫技,没处用,可惜你错了,redis中就是这么用的,
不信请看: