第四章 指针和数组
4.1指针
· 指针类型的大小一定是当前系统的位数,比如32位系统,sizeof就是4个字节。
· 指针里的内容一定是一个地址,即使存放其他数据,都会被当做地址处理。
· 指针一旦被定义,类型就确定了(强制转型除外),如int* p,在内存开辟了连续的四个字节的空间,这四个字节里存储的就是p指向的int型变量的四个字节的空间的地址。
· 在定义指针变量的时候,*的作用是表明这是一个指针型数据,之后*放在指针变量前的作用是作为一个钥匙,打开这个地址所存储的数据的值。
4.2 数组
· 数组是一个具有相同类型的变量的集合,定义一个数组时,编译器根据指定的元素个数和元素的类型分配确定大小的一块内存,数组名a一旦与这块内存匹配就不能改变。
· 数组名a不能作为左值,我们只能访问数组的某个元素而无法把数组当成一个总体进行访问,a作为右值,代表的意思和&a[0],代表的是数组首元素的首地址,而&a代表的是数组的首地址,两者的值相同,但是意义和用法不同。
指针和数组
· 数组和指针没有任何关系,是两个不同类型的变量,只不过数组和指针的使用方式在某些情况相似而已。
· 对于char* p=”abcdef”;
char a[]=”abcdef”;
都可以以指针的形式和以下标的形式访问,这两种方法对于两者没有区别
以指针的形式访问:*(p+i), *(a+i)
以下标的形式访问:a[i] p[i]
编译器总是把以下标的形式的操作解析为以指针的形式的操作
· &a和a的区别是:a等价于&a[0],a+1是指偏移一个元素的地址。&a+1是指偏移整个数组的地址,即指向下一个数组的首地址
· 指针通常用于动态数据结构,数组用于存储固定数目且数据类型相同的元素。
· 指针用于存储一系列的数据的时候,需要用malloc和free动态分配内存和释放,否则会导致内存泄露,数组则是隐式分配和删除
· 指针指向匿名数据(也可以指向具名数据),数组自身即为数组名,指针的访问是匿名访问,数组是具名+匿名访问
指针数组和数组指针
· 指针数组,存储指针的数组,int *p[10]; //[]的优先级高于”*”
· 数组指针,指向数组的指针,int (*p)[10]; //可以这样理解, int (*)[10] p;
· chara[3]={1,2,3}; char (*p)[3]=&a;//数组指针p指向数组a,&a代表的是数组a的地址,这里不应用a。这里对p3+1,得到的是&a的地址+3.
· int *p=”123456”; p+1加的是一组元素的地址,(int *)p+1加的是一个元素的地址,(int )p+1加的是1
多维数组与指针
· 二维数组虽然是二维的,但是内存的分布依然是线性的,即一行一行连续着
· 二级指针是指针的指针,保存的是一级指针的地址,一级指针指的是数据的地址
· 当指针不用的时候,或者初始化的时候,对其赋值NULL,指向0地址,当需要使用指针的时候,必须把一个地址保存到该指针。
数组参数和指针参数
· C语言中,当一位数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针,所以可以这样写:void func(char *p) / void func(char p[])。
· 函数本身是没有类型的,只有函数的返回值才有类型,返回值为任何类型,都不影响函数的执行。
· 不能把指针变量本身传递给一个函数,指针变量指向的对象是以实参传入的,指针变量本身是以形参的形式传入的,所以如果在函数内部分配内存或是改变指针对象,退出函数就没用了。解决的方法是用return或是二级指针,道理和一级指针在函数内部修改对象的值一样。
· 数组参数 等效的指针参数
数组的数组: char a[3][4], 数组的指针:char (*p)[10];
指针数组:char *a[5], 指针的指针:cahr **p;
函数指针
· 函数指针就是函数的指针,它是一个指针,指向一个函数
· 如char *(*fun)(char* p1,char* p2),返回值为char*的函数指针