指针的传递
指针即地址,来看一个例子,此时在子函数中不能修改main函数中变量的值:
#include <stdio.h> //通过打断点调试,查看i和j对应的地址,以及两者值的变化 void change(int j){ j=6; } int main() { //开始执行时系统为main函数开辟函数栈空间 int i=10;//此处main函数的栈空间为i分配4字节大小的空间 printf("before change i=%d\n",i);//可打断点,观察&i,&j //C语言的函数调用均为值传递,即将i的值赋值给j //调用change函数时,系统会为其分配函数栈空间,并为形参i分配4字节大小的空间 change(i); //&i和&j不一样,change修改的是j的值,i的值不变 //函数执行完毕,其栈空间就会释放,j不再存在 printf("after change i=%d\n",i); return 0; }
初始时
进入change函数
离开change函数
于是打印结果是
那么,如何在子函数中修改main函数中变量的值呢?将程序作部分修改后,再来看:
void change(int* j){ *j=6;//间接访问得到变量i }
change(&i);//传递变量i的地址
结果是
这是因为修改后 j=&i,虽然还是值传递,但此时j是指针变量,内部存储的是i的地址,*j间接访问到了与i相同的区域,并改变i值。通过调试,我们仍可以看到&j与&i不相等。
指针的偏移
前面讲指针即地址,除了指针的传递,还可以对指针进行加减,称为指针的偏移。
#include <stdio.h> #define N 5 int main() { int a[N]={1,2,3,4,5}; int *p; int i; p=a;//数组名中存储着数组的起始地址,类型为整型指针,与上面一致 for(i=0;i<N;i++){//正序输出 //指针变量加1后,偏移的长度是其基类型的长度,即sizeof(int) printf("%3d",*(p+i));//*(p+1)就是a[1] } printf("\n\n"); p=&a[4];//让p指向最后一个元素 for(i=0;i<N;i++){//逆序输出 printf("%3d",*(p-i)); } printf("\n"); return 0; }
结果为
指针与一维数组
上面我们提到,数组名中存储着数组的起始地址。所以一维数组在函数调用进行传递时,它的长度子函数无法知道。通过下面的例子再次练习指针的传递与偏移:
#include <stdio.h> void change(char *d){ //定义的指针变量要和数组数据的类型一致 *d='H';//通过取值操作,将'h'改为'H',称为指针法 d[1]='E';//通过取下标的方式获取数组元素并修改,称为下标法 *(d+2)='L'; } int main() { char c[10]="hello"; change(c);//数组名作为实参传递给子函数时,是弱化为指针的 puts(c); return 0; }
结果为