为什么不能运行?
//文件1
int mango[100];
//文件2
extern int *mango;
//开始使用指针访问文件1中的数组
上面的例子是类型不匹配错误,无法正常运行,错误和下面的例子相似
//文件1
int mango;
//文件2
extern float *mango;
声明和定义的区别
- 定义有且只有1个,但它可以有多个extern声明
- 定义是特殊的声明,它分配了内存空间,用于创建新的对象,声明则用于指代其他地方定义的对象
- 注意多维数组声明的时候,要给出除最左边一维之外的其他维的长度
可修改的左值
- 出现在赋值号左边的称为左值,右边的称为右值
- 左值代表的是地址,右值代表的是地址的内容
- 左值编译时可知,右值运行时才知道,编译器为每个变量分配一个地址,这个地址编译时可知,而且该变量在运行时一直保存于这个地址。相反,右值运行时才知道,如果需要用到右值,编译器就发出指令从指定的地址读取变量值放入寄存器
- 左值一般都是可修改的,那么为什么会有不可修改的左值,数组名就是不可修改的左值,可以简单理解为数组名的左值永远都只能是首地址
数组的访问
指针的访问
开篇的错误解释
对于extern int * mango; 当用mango[2]来访问的时候,首先,会按照图B所示对指针解引用,然后按照图A对下标进行偏移并直接访问,更为正式的说法:
1、取得mango的地址,提取存储于此处的指针;
2、把下标所表示的偏移量与指针的值相加,产生一个地址;
3、访问上面的地址,得到int
- 因此,既然mango声明为指针,那么不管在定义的时候是数组还是指针,都会按照上述步骤进行指针的下标操作,但是只有定义也为指针的时候,才能得到正确的值。
- 解决的办法很简单,让外部声明和定义互相匹配即可
指针与数组的其他区别
指针 | 数组 |
---|---|
保存数据的地址 | 保存数据 |
间接访问数据,首先取得指针的内容,把它作为地址,然后从这个地址提取数据。如果有一个下标[i],就把指针的内容加上i的偏移作为地址,从中提取数据 | 直接访问数据,a[i],只是简单的访问a+i的地址取得数据 |
通常用于动态数据结构 | 通常用于存储数目固定且数据类型相同的元素 |
相关的函数malloc/free | 隐式分配和删除 |
通常指向匿名数据 | 自身即为数据名 |
关于常量字符串
char* p = "abcdef";
int *pn = 2;//ERROR
char a[] = "abcdef"
数组和指针都可以在定义中使用常量字符串初始化,机制却不一样。定义指针时,编译器只是给指针本身分配空间,除非在定义的时候赋值一个常量字符串进行初始化。只有常量字符串才可以如此,浮点数之类绝对不行。
ANSI C规定,初始化指针时的常量字符串为只读,如果试图通过指针改变字符串的值,会出现未定义的行为。
与指针相反,由常量字符串初始化的数组是可以修改的。
Reference
C专家编程