目录
地址
地址:内存区的每一个字节的编号
例:int a =3;
变量地址:分配给变量内存单元的起始地址
系统对变量的访问方式
(1)直接访问:按变量的地址(变量名)存取变量;
例:
scanf("%d",&a);
k=i+j;
(2)间接访问:通过另一变量访问该变量的值
指针
指针:内存单元的地址 |
变量的指针:变量的地址,指示该变量对应的位置 |
指针变量:一个地址变量,存放的是另一个变量的地址 |
指针变量
1.定义方式
类型标识符 * 指针变量名;
如: int *p1;
char * p2;
指针变量三要素:类型、值、名字
注:
类型:一定要与所指变量类型一致;
* :说明符,说明该变量为指针变量;
指针变量名:要符合标识符命名规则
2. 指针变量的应用
(1)指针变量的赋值
例:
int i=10,*p,*q;
p=&i;
q=p;
将一个变量地址赋给另一个指针变量
指针变量=&变量名;
用已经赋值的同类型的指针变量赋值
指针变量可以有空值
p=NULL;(NULL要大写,代表指针变量不指向任一单元,指针变量为空)
NULL值为0,在头文件studio.h中有以下定义 #define NULL 0;
注:
在程序中使用变量之前,一定要给指针赋予确定的地址值,否则容易导致错误
(2)指针变量的引用
直接引用指针变量名
int i,j,*p; //定义了整型变量i,j以及整型指针变量p,
p&i; //i的地址赋值给了p,即p指向了i
scanf("%d%d",p,&j); //scanf函数在输入地址列表中用p代表i的地址,即直接引用指针变量名
通过指针变量来引用所指向变量
格式为: *p指针变量名,代表该指针变量所指向变量的值
注意:这种引用方式要求指针变量必须有值
例: printf("%d%d" ,*p,i);
printf函数中输出列表中*p代表的就是i变量
即输出的是i的值
指针的移动
指针是地址量,加上一个或减去一个整数n,表示指针变量指向当前位置的前方或后方第n个数据的位置
两个相同类型的指针变量相减所得的差指两者相隔的数据单元数
指针变量的运算
两个相同类型的指针变量之间可以进行各种关系运算,其结果表示他们所指向地址的位置之间的关系
例:
int *p,*q;
p<q表示p指向的位置在q的前面
p=q表示指向同一位置
例:直接访问和间接访问
main()
{
int a,b,*p1,*p2; //定义整型变量ab,及整型指针变量p1,p2
p1=&a;p2=&b; //p1指向a,p2指向b
scanf("%d%d",&a,p); //通过指针函数输入,地址列表中为&a和p2.分别采用了直接访问和间接访问的方法,其中p2存放的是b的地址。当输入3和5时,3直接存入a变量的存储单元,为直接存储方式。而5先找到p2里面存放的b的地址,然后存入b变量的存储单元,为间接访问方式
printf("%d,%d\n",a,b); //输出a,b的值,为直接访问。
printf("%d,%d\n",*p1,*p2);
//接着又输出*p1和*p2,指针运算符代表指向可以用指针变量所指向的变量代替,也就是a,b.因此输出值仍然是3,5;这属于间接访问
例:对两个整数按由大到小的顺序输出
main()
{
int *p1,*p2,*p,a,b;
a=5;b=9;
p1=&a;
p2=&b;
if(a<b){
p=p1;p1=p2;p2=p;
printf("a=%d,b=%d\n",a,b);
printf("max=%d,min=%d\n",*p1,*p2);
}
}
代码分析:
本例中,先定义整型指针变量p1,p2,p及整型变量ab ,并给a,b赋初值
然后p1指向a,p2指向b
实验要求按由大到小的顺序输出,即a小于b时,进行交换,这里5<9,所以交换
注意此处交换的是p1和p2的值,也就是两个指针变量的值
指针变量里面存的是ab的地址,交换以后,p1存放b的地址,p2存放a的地址(p1指向了b,p2指向了a),然后输出ab的值,ab的值并没有方式变化,仍然是5和9
因此按照输出函数的格式,输出a=5,b=9,接着又输出*p1,*p2,指针运算符代表指向可以用指针变量所指向的变量代替,然后输出max=9,min=5,程序结束
注:这里a和b并没有交换,而p1和p2的值改变,也就是交换了p1和p2的指向
main()
{
int *p1,*p2,p, a=5;b=9;
p1=&a;
p2=&b;
if(a<b){
p=*p1;*p1=*p2;*p2=p;
}
printf("a=%d,b=%d\n",a,b);
printf("max=%d,min=%d\n",*p1,*p2);
}
这个和上面的程序非常类似 ,这里p不是指针变量,是一个整型变量
交换语句为 p=*p1;*p1=*p2;*p2=p; ,也就是*p1和*p2进行交换,二者为间接访问,因此可以用他们指向变量来代替,也就是ab来代替。因此该语句交换的是ab的值,交换后,a=9,b=5
所以第一个输出语句输出的是a=9,b=5
第二个输出语句,输出*p1和*p2,p1和p2仍然指向ab,因此按照输出函数的格式,输出max=9,min=5
交换指针指向和交换指针所指向变量是值的区别:
|
例:
int i=30,*p,**q;//定义了整型变量i并初始化为30,指针变量p以及二级指针q,注意p存放整型变量的地址,而q则只能存放整型变量指针的地址。
p=&i;让p指向i
q=&p;p的地址放入q中,即q指向p
printf("%d,%d,%d",i,*p,**q);输出时,i为30,*p可以用p所指向的变量i代替,值为30
而**q,表示*q代表p,*再与p结合,仍然代表的是i,值也为30
指针与函数
1.指针变量作为函数参数
(1)指针类型做函数参数的作用的将一个地址值传送到函数中,函数对指针所指单元的操作,即对主调函数的变量进行操作
(2)实参必须是基类型相同的地址值或是已指向某个存储单元的指针变量
例:交换两数程序
#include<stdio.h>
int main()
{ int a=3,b=5,*p1,*p2;
void swap(int *pa,int *pb);
p1=&a;p2=&b;
if(a<b)swap(p1,p2);//swap(&a,&b)和swap(p1,p2)效果一样
printf("\n%d,%d\n",a,b);
}
void swap(int *pa,int *pb){
int p;
p=*pa,*pa=*pb;*pb=p;
}
实验分析:
在程序中先定义了a=3,b=5以及指针变量p1,p2
并且让p1指向a,p2指向b,
a<b则调用swap函数,并把p1,p2分别赋值给pa,pb。此时pa,pb也分别执行a,b,调用函数时给形参pa,pb和局部变量p分配存储空间,然后p作为中间变量,交换*pa,*pb的值。因为此时pa和pb分别指向了ab,因此交换的其实是实参ab的值,交换后a=5;b=3.调用结束,swap函数中的形参pa、pb及局部变量p内存单元释放,返回到主调函数,输出ab的值5,3
示意图:
如果把swap函数更改一下,p变为指针变量,交换语句变为pa和pb的交换。此时交换的是pa,pb的指向,也就是pa指向了b,而pb指向了a,执行完swap函数后,函数中的形参及局部变量释放。ab中的值仍为3和5,因此输出3,5。所以交换指针指向,不能实现两数交换
例:传值与传值程序示例
#include<stdio.h>
int f(int y,int*x)
{
y=y+*x;
*x=*x+y;
}
main()
{
int x=2,y=4;
f(y,&x);
printf("%d%d\n",x,y);
}
程序分析:
先给实参xy分配存储单元并赋初始值2和4.当调用语句给f函数的形参分配存储单元,并把实参y的值4传递给形参y,实参x的地址传递给形参指针变量x,也就是形参x指向实参x。然后执行f函数中的y=y+*x;形参y的值为4.形参x指向实参x,因此*x即为实参x的值2,执行后y的值为6。接着执行*x=*x+y;同理2+6=8赋值给形参x所指向的实参x,即实参x的值为8。f函数结束,释放形参变量存储空间,输出实参xy的值为8和4,程序结束
本例中y的传递方式为传值,采用传值的方式。相当于复制了一份数据给形参,因此形参的变化不会影响实参。
x的传递方式为传址,采用传地址的方式。函数对指针所指单元的操作,即对主调函数的变量进行操作
运行结果如下:
2.指针函数
指针函数:返回值是指针类型的函数
一般定义形式:
类型名 * 函数名(参数列表)
{......}
例如:int *a (int x,int y)
{......}
说明:
a:函数名,调用它后能够得到一个指向整型数据的指针(地址)
x,y:函数a的形参
*:表示此函数是指针类型函数(函数值是指针)
例:返回两个整数中最大数的地址
#include<stdio.h>
int *fun(int x,int y)//指针函数fun
{
if(x>=y)
return &x;//return后返回较大数的地址,与函数类型对应
return &y;
}
//int *fun(int *x,int *y)形参也可以为指针的形式 ,此时调用函数为p=fun(&a,&b);
//{
// if(*x>=*y)
// return x;
// return y;
//}
int main()
{
int a,b,*p;
scanf("%d,%d",&a,&b);
p=fun(a,b);//调用函数后返回值赋值给指针变量p
printf("%d",*p); //最后已*p的形式输出最大值
}
运行结果如下:
3.指向函数的指针
一个函数在编译时被分配给一个入口地址。在C语言中,函数名代表该函数的入口地址,因此可以定义一种指向函数的指针来存放这种地址。这种指针就称为指向函数的指针
定义方式:
类型 (*指针变量名)();
指向函数指针的使用:
(1)将函数入口地址(函数名)赋给指向函数的指针变量
(2)将指针变量(连同圆括号)代替函数名使用