老生常谈的问题:指针数组和数组指针。这是一篇需要不断补充的博文,知道多少先写多少吧
int *p[];
int (*p)[];
对于第一个,p先和[]结合,故p被声明为一个数组,而这个数组的每个元素的类型为int*型;
下一个p先和*结合,所以p是一个指针,其指向的是一个int型的一维数组(一直认为C里面数组的声明方式没有JAVA里面直观,C里声明一个int型的数组a为int a[],Java里则更明显 int[] a)
同理 对于一个函数
int *p();
int (*p)();
前者定义了一个函数,其返回值为一个int类型的指针;
后者则是定义了一直指针,它指向的是一个具有int类型返回值的函数。
--------------------------------------------------------------------------------------------------------------------------------------------------------
以下内容总结自《C与指针》
数组 int b[5];
b[4]的类型是整型,但是数组名b的类型是 指针常量(所谓指针常量,就是该指针是个常量,所存储的内容(地址)不能修改,即不能修改该指针所指向的地址),它的值是数组第一个元素的地址(若要对某个固定地址(如100)进行赋值,就需要先将该地址强制转换为指针常量 *(int *)100 = 5)其具体类型取决于数组类型,若是整型数组,则b就是 “指向int的指针常量”。
在两种情况下,数组名不能用指针常量来表示:
1、 作为sizeof的操作数
2、 作为&的操作数。此时返回的是指向数组的指针,而不是指向数组第一个元素的指针的指针。
声明一个数组时,编译器会根据声明所规定的个数为数组分配内存空间,然后再创建数组名,它的值是一个常量,指向这段空间的起始位置。
声明一个指针时,编译器只会为指针本身保存内存空间。
另int a[5]={...}; a++,++a均会报错,a是常量,不能被修改。
数组的初始化:
对于静态数组,初始化只进行一次,且才程序开始执行之间就完成了。这个工作是由链接器完成的,它用包含可执行程序的文件中的合适的值对数组进行初始化,若未指明,初始化为0
对于auto数组,每次执行进入相应的程序块时,变量所占据的内存空间可能并不相同,所以编译器无法为其预先分配内存地址,每次都会为其初始化,这应该很浪费时间。
char[] p = "hello world"; //只是为了简化'h','e'...初始化数组;其并非表示字符串常量
char *p = "hello world"; //字符串常量,p被初始化为“helloworld”的地址
对于数组和指针的声明,只有作为函数的参数时才能等同。且作为函数的参数时,总是转换为指针的,所以指明数组的第一维的长度也是无用的。
如:fun(char[] string )和fun(char *string)两者相同。传递过来的只是一个指针。
多维数组
C中多维数组在内存中的存储顺序为:按其最右边(先是最后一维,然后倒数第二维。。。最后才是第一维)下标的变化存储。
指向数组的指针
int matrix[5][10]; (matrix是一个指向数组的指针)
故int (*p)[10] = matrix才是正确的 此时若p+i;实际运算过程中是 p+i*10
若声明过程中未写明第二维的长度 即int(*p)(),此时对p进行加减,会将第二维视为空指针,会执行 p+i*0。
多维数组作为函数的参数进行传递时,跟一维数组一样,可以声明为函数或者数组。但是值得注意的是,声明过程中必须指明除了第一维的其他所有维的长度,这样编译器才能判断出具体下标的存储位置(第一维长度不用指明,就像一维数组不需指明其长度一样)。
int a[2][3];
a,a+2一样,均为指向数组的指针,对其进行整数的加减运算,都是乘以相应数组长度进行加减的。
而a[0],a[2]则均为指向整型的指针,对其进行加减运算,是乘以sizeof(int)进行运算的。
sizeof(a) 结果为24 数组名
sizeof(a+2) 结果为4
sizeof(a[0]) 结果为12 a[2]指向整型的指针,其相当于一个一维数组名,下同
sizeof(a[2]) 结果为12