1、需要传入较大的数据时用作参数
2、传入数组后对数组做操作
3、函数返回值不只一个结果
4、需要用函数来修改不止一个变量
5、动态申请内存
…
取地址运算符&:
scanf("%d",&i) ; 里的&
&的作用是获得变量的地址,它的操作数必须是变量
#includeint main() { int i=0; printf("%p",&i);//以十六进制形式输出变量i的地址 return 0; }
如果操作数不是变量,例如:a+b、a++、++a之类的就会报错
相邻变量的地址:
例如
#includeint main() { int i=0; int j; printf("%pn",&i);//以十六进制形式输出变量i的地址 printf("%p",&j); return 0; }
我们可以看到地址一个是尾数1C一个是18,在十六进制中8和C相差4,我们知道int类型占4个字节,这代表在内存里,这两个变量是相邻的。再进一步观察,我们可以看到先定义的 i 是
1C,后定义的 j 是18,说明在内存里 i 在更高的地方而 j 在较低的地方。这是因为 i 和 j 都是本地变量,他们分配在内存的堆栈中,在堆栈中分配内存是置顶向下分配的。(后续会学到)
数组的地址:
#includeint main() { int a[10];//定义一个数组 printf("%pn",&a); printf("%pn",a); printf("%pn",&a[0]);//取数组 a 第0个元素的地址 printf("%pn",&a[1]);//取数组 b 第1个元素的地址 return 0; }
从输出结果可以看到,前三个地址是一样的,这就说明了直接写取数组名的地址时,默认取的是数组第一个元素的地址,而且可以不用加 & 符号(下文会提及数组与指针的关联)。如若取数组里面某个元素的地址则只需要在 [ ] 中写明取第几号元素即可。据观察可知数组里相邻元素的地址也是相邻的。
间接运算符 * :
指针就是保存地址的变量
#includeint main() { int i=1000; int*p = &i;//定义指针类型的变量 p 用来存放变量 i 的地址 printf("%d",*p);//*可以理解为取值,*p也就是取指针型变量p所指向的变量地址的值 return 0; }
注意:int*p,q 这样定义的话表示定义一个指针型变量 p 和一个整型变量 q
作为参数的指针:
#includevoid f(int *p);//定义一个以指针为参数的函数 f int main() { int i=1000; printf("i =%pn",&i);//打印 i 的地址 f(&i);//调用函数 f return 0; } void f(int*p) { printf("p =%pn",p);//打印 p 的地址 }
敲黑板划重点
我们知道,对函数里的变量进行操作是不会改变主函数中这个变量的值的,但是用指针却可以做到。
#includevoid f(int *p);//定义一个以指针为参数的函数 f int main() { int i=1000; printf("i =%pn",&i);//打印 i 的地址 printf("i=%dn",i); f(&i);//调用函数 f printf("i=%d",i); return 0; } void f(int*p) { printf("p =%pn",p);//打印 p 的地址 *p=233; }
还是上一次的代码,这一次在函数中我们把*p赋值为233,然后神奇的事情发生了:
i 的值由原来的1000变成了233。原因是使用指针我们从根本上(内存中)改变了变量的值。
实战一下:刚开始学C语言的时候做过的交换两个变量的题
#include指针应用场景:函数返回多个值void f(int *pa,int *pb);//定义一个以指针为参数的函数 f int main() { int a=1000; int b=233; f(&a,&b); printf("a=%d b=%d",a,b); return 0; } void f(int *pa,int *pb) { int tmp=0; tmp=*pa; *pa=*pb; *pb=tmp; }
因为函数的返回值只有一个,用指针的话可以带回多个值
例如:找出数组中最大以及最小的数
#include指针常见错误void minmax(int a[],int len,int *min,int *max);//定义一个以指针为参数的函数 f int main() { int min; int max; int a[10]={1,2,3,4,5,66,78,90,19,28}; minmax(a,sizeof(a)/sizeof(a[0]),&min,&max); printf("min=%d max=%d",min,max); return 0; } void minmax(int a[],int len,int *min,int *max) { *min=*max=a[0]; for(int i=1;i a[i]) { *min=a[i]; } if(a[i]>*max) { *max=a[i]; } } }
定义了指针变量,还没有指向任何变量,就开始使用指针。
必须先要让指针指向某个变量的地址才能用*p对变量的值进行操作。
函数参数表中的数组其实是指针!!!
在参数表中 *ar 等价于ar[ ]
数组变量是特殊的指针
数组变量本身表达地址,所以
int a[10]; int *p=a; //无需用&取地址(虽然用了也不会报错)
但是数组的单元表达是变量,需要用&取地址
例如要取数组a中的3个元素的地址就必须要写成&a[3];
[ ]运算符可以对数组做,也可以对指针做
p[0]==a[0]
例如:
#includevoid minmax(int a[],int len,int *min,int *max);//定义一个以指针为参数的函数 f int main() { int min; int max; int a[10]={1,2,3,4,5,66,78,90,19,28}; minmax(a,sizeof(a)/sizeof(a[0]),&min,&max); printf("min=%d max=%dn",min,max); int *p=&min;//定义一个指针变量p让它指向变量min的地址 printf("*p=%dn",*p);//打印指针p所指向的变量min地址存放的值 printf("p[0]=%dn",p[0]);//打印数组p[0]的值 return 0; } void minmax(int a[],int len,int *min,int *max) { *min=*max=a[0]; for(int i=1;i a[i]) { *min=a[i]; } if(a[i]>*max) { *max=a[i]; } } }
我们并没有定义数组,它是我们虚构出来的,但是却能编译运行,这说明其实我们把min当作是一个int类型的数组,指针p指向了这个数组。(这一块听得不是太懂…)
今天就先到这了,下回继续。



