指针数组和数组指针
分清楚这二者的区别只需要关注其后两个字:
指针数组本质为数组,数组中存储着指针
数组指针本质为指针,该指针指向一个数组
然后我们还需要明确一下优先级的顺序:() > [] > *
int *p1[5];
//根据优先级,先看[],由此看出p1为一个长度为5的数组
//再结合*,该数组元素为指针类型,因此为指针数组
int (*p2)[5];
//根据优先级,先看(),由此看出p2为一个指针,该指针指向一个长度为5的数组
//因此为数组指针
数组指针例子:
int a[5]={1,2,3,4,5};
//定义一个一维数组
int (*P)[5]
//定义一个数组指针,步长为5
p=&a;
//将数组a的首地址赋值给p
printf("%p\n",a); //输出数组a的地址
printf("%p\n",p); //p存储a的地址,输出数组a的地址
printf("%p\n",*p); //输出数组a的地址
printf("%p\n",p[0]); //输出数组首元素的地址
printf("%d\n",**p); //可以理解为*(*p),输出a[1]的值
printf("%d\n",*p[0]);//根据优先级,先看p[0]为首元素地址,*解引用后输出a[1]的值
int b[3][4];
//定义一个二维数组
int(*p1)[4];
//定义一个数组指针,指向含四个元素的一位数组
p1=b;
//将该二维数组首地址赋值给p1,p1=b与p1=&b[0]等价
p1++;
//此语句执行后p1指向从b[0][]变为b[1][]
由上述可知,数组指针也称指向一维数组的指针,所以数组指针也称行指针
指针数组例子:
int a = 1;
int b = 2;
int *p[2];
p[0] = &a;
p[1] = &b;
printf("%p\n", p[0]); //a的地址
printf("%p\n", &a); //a的地址
printf("%p\n", p[1]); //b的地址
printf("%p\n", &b); //b的地址
printf("%d\n", *p[0]); //p[0]表示a的地址,则*p[0]表示a的值
printf("%d\n", *p[1]); //p[1]表示b的地址,则*p[1]表示b的值
//将二维数组赋给指针数组
int *p1[3]; //一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2],所以要分别赋值
int c[3][4];
for (int i = 0; i<3; i++)
p1[i] = c[i];
一点小补充
int arr[5]={1,2,3,4,5};
int (*p1)[5]=&arr; //正确
int (*p2)[5]=arr; //错误
事实上arr和&arr的值相同,都是表示数组的地址,那为何在编译时会报错呢?
原因在于在C语言中赋值符号"="的两边数据类型要相同,若不同则需要显式或隐式类型转换
在上述代码中,p1和p2都是数组指针,指向整个数组,&arr表示整个数组的地址,由此正确, 但arr表示的是数组首元素的地址(指向单个元素的指针),虽然值相同,但类型不同,由此会提示错误信息
指针函数和函数指针
与上述概念类似,要分清这二者的区别同样只需要关注其后面两个字:
指针函数本质为一个函数,其返回值类型为指针类型
int *func();
//指针函数,返回值类型为int *型
void *func1();
//void *表示可以返回任意类型的指针,但接收void *函数返回值时需要强转
//但不建议这么使用,因为强转有风险
函数指针本质为一个指针,其指向一个函数的地址,通俗点说就是一个指向函数的指针
int (*func)();
//定义了一个函数指针
//函数指针需要将一个函数的地址赋值给它,一般来说有两种写法
func = Function;
func = &Function;
//&不是必须的,因为函数名就代表了它的地址
//调用函数指针的方法也有两种
x = (*func)();
x = func();
引用(C++)
需要注意的是,C语言中是没有引用的,引用相当于为对象取了另外一个名字
int val=100;
int &reval=val; //reval指向val,是val的另外一个名字
int &reval2; //错误写法,引用必须被初始化
初始化变量时,初始值会被拷贝到新建的对象中,然而定义引用时,程序把引用和它的初始值绑定在一起,而不是拷贝给引用,一旦初始化完成,引用就会和初始值对象一直绑定,无法令引用重新绑定到另外一个对象
int &reval = 10; //错误,引用类型初始值必须是一个对象
double dval = 3.14;
int &reval = dval; //错误,此处的引用类型必须要int型对象
补充:引用即别名,只是为一个已经存在的对象所起的另外一个名字,引用本身不是一个对象,不能定义引用的引用,也不能定义指向引用的指针,但指针式对象,存在对指针的引用
int i=42;
int *p;
int *&r=p; //r时一个对指针p的引用
r=&i; //r引用了一个指针,因此给r赋值&i就是令p指向i
*r=0; //解引用r得到i,也就是p指向的对象,将i的值改为0
注:要理解r的类型,可以从右往左阅读r的定义,离变量名最近的符号对变量有最直接的影响,例如:&离r最近,由此r时一个引用,其余部分用以确定r引用的类型是什么,此例中* 说明r引用的是一个指针