1、需要传入较大的数据时用作参数
2、传入数组后对数组做操作
3、函数返回值不只一个结果
4、需要用函数来修改不止一个变量
5、动态申请内存
…
取地址运算符&:
scanf("%d",&i) ; 里的&
&的作用是获得变量的地址,它的操作数必须是变量
#include
int main()
{
int i=0;
printf("%p",&i);//以十六进制形式输出变量i的地址
return 0;
}
如果操作数不是变量,例如:a+b、a++、++a之类的就会报错
相邻变量的地址:
例如
#include
int main()
{
int i=0;
int j;
printf("%p\n",&i);//以十六进制形式输出变量i的地址
printf("%p",&j);
return 0;
}
我们可以看到地址一个是尾数1C一个是18,在十六进制中8和C相差4,我们知道int类型占4个字节,这代表在内存里,这两个变量是相邻的。再进一步观察,我们可以看到先定义的 i 是
1C,后定义的 j 是18,说明在内存里 i 在更高的地方而 j 在较低的地方。这是因为 i 和 j 都是本地变量,他们分配在内存的堆栈中,在堆栈中分配内存是置顶向下分配的。(后续会学到)
数组的地址:
#include
int main()
{
int a[10];//定义一个数组
printf("%p\n",&a);
printf("%p\n",a);
printf("%p\n",&a[0]);//取数组 a 第0个元素的地址
printf("%p\n",&a[1]);//取数组 b 第1个元素的地址
return 0;
}
从输出结果可以看到,前三个地址是一样的,这就说明了直接写取数组名的地址时,默认取的是数组第一个元素的地址,而且可以不用加 & 符号(下文会提及数组与指针的关联)。如若取数组里面某个元素的地址则只需要在 [ ] 中写明取第几号元素即可。据观察可知数组里相邻元素的地址也是相邻的。
间接运算符 * :
指针就是保存地址的变量
#include
int main()
{
int i=1000;
int*p = &i;//定义指针类型的变量 p 用来存放变量 i 的地址
printf("%d",*p);//*可以理解为取值,*p也就是取指针型变量p所指向的变量地址的值
return 0;
}
注意:int*p,q 这样定义的话表示定义一个指针型变量 p 和一个整型变量 q
作为参数的指针:
#include
void f(int *p);//定义一个以指针为参数的函数 f
int main()
{
int i=1000;
printf("i =%p\n",&i);//打印 i 的地址
f(&i);//调用函数 f
return 0;
}
void f(int*p)
{
printf("p =%p\n",p);//打印 p 的地址
}
敲黑板划重点
我们知道,对函数里的变量进行操作是不会改变主函数中这个变量的值的,但是用指针却可以做到。
#include
void f(int *p);//定义一个以指针为参数的函数 f
int main()
{
int i=1000;
printf("i =%p\n",&i);//打印 i 的地址
printf("i=%d\n",i);
f(&i);//调用函数 f
printf("i=%d",i);
return 0;
}
void f(int*p)
{
printf("p =%p\n",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<len;i++)
{
if(*min>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]
例如:
#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\n",min,max);
int *p=&min;//定义一个指针变量p让它指向变量min的地址
printf("*p=%d\n",*p);//打印指针p所指向的变量min地址存放的值
printf("p[0]=%d\n",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<len;i++)
{
if(*min>a[i])
{
*min=a[i];
}
if(a[i]>*max)
{
*max=a[i];
}
}
}
我们并没有定义数组,它是我们虚构出来的,但是却能编译运行,这说明其实我们把min当作是一个int类型的数组,指针p指向了这个数组。(这一块听得不是太懂…)
今天就先到这了,下回继续。