第十四讲 程序控制论.docx
- 文档编号:13191990
- 上传时间:2023-06-11
- 格式:DOCX
- 页数:19
- 大小:22.73KB
第十四讲 程序控制论.docx
《第十四讲 程序控制论.docx》由会员分享,可在线阅读,更多相关《第十四讲 程序控制论.docx(19页珍藏版)》请在冰点文库上搜索。
第十四讲程序控制论
第十四讲第九章 指针
内容:
§10.1 地址和指针的概念
§10.2 变量的指针
§10.3 数组的指针:
一维数组的指针
指针是C语言的一个重要的概念,也是C语言的一个重要特色,当然也是C语言学习的一
个难点。
正确而灵活地使用指针,可以有效地表示复杂的数据结构、能动态分配内存、方
便地使用字符串、有效而方便地使用数组、调用函数时能得到多于1个的函数值、能直接
处理内存地址。
由于C语言的指针的这些功能,使得指针成为了C语言的精华.但是,由于指
针的概信念比较复杂,使用也比较灵活,在学习时也要求大家多思考,多比较,多上机。
§10.1指针的概念
一、数据在内存中的存储
如果在程序中定义了一个变量,在编译时就给这个变量分配内存单元,系统根据变量
的类型,分配一定长度的空间.在程序运行时,变量和该变量的存储单元之间存在着唯一
的对应关系。
二、几个概念
1.地址:
内存区中每一个存储单元的编号叫作地址。
在程序运行时,变量和存储单元的地址之间存在着唯一的对应关系(地址相当于旅馆的房间号)。
2.内容:
内存单元中存放的数据叫作内存单元的内容(内容相当于房间的旅客)。
3.指针变量:
在C语言中,有一类特别的变量,这些变量中存放的数据是另外一个变量的地址,这类变量叫作指针变量。
4.指针:
变量或存储单元的地址叫作指针。
5.指向:
所谓指向就是通过地址建立起来的一种联系。
在C语言中,一旦指针变量被赋值,我们可以说这个指针变量指向某个存储单元。
三、对变量的访问方式
1.直接访问方式:
用户对变量名或变量的地址进行访问,系统根据变量名与内存中存储单元的对应关系对变量名所指定的存储单元进行访问。
2.间接访问方式:
用户对指针变量进行访问,通过指针变量的值指向被访问的内存单元,从而实现对变量的存取,即按指针指向存取变量。
例如,定义一个整型变量i,系统就会为i分配一个2字节的存储单元,该单元的编号假定为2000,我们可以为变量i赋一个整数3。
这样我们就可以这样说,变量i的地址为2000,变量i的内容为3。
接着,我们再定义一个指向整型数据的指针变量pi,将整型变量i的地址赋给pi,我们就可以说指针变量pi指向变量i,或者说,pi的内容是i的地址即2000。
§10.2变量的指针和指向变量的指针变量
一、两种新的运算符号
1.取地址运算符号
(1)运算符号:
&(单目,前置)
(2)运算功能:
取变量的地址,变量的地址可以通过&运算符号来得到。
(3)使用方法:
&变量名
(4)结合性:
自右向左
(5)优先等级:
与"-(负号运算符)"、"++"、"--"具有相同的优先等级,高于加、减、乘、除,低于括号运算符。
2.指针运算符(间接运算符)
(1)运算符号:
*(单目,前置)
(2)运算功能:
取地址中的值,或者说给出存储于所指地址中的值。
(3)使用方法:
*指针变量名
(4)结合性:
自右向左
(5)优先等级:
高于加、减、乘、除运算,低于括号运算符,与负号运算符和自加自减运算符的优先等级相同。
二、变量的指针
变量的指针是指变量存储单元的地址。
三、指针变量的定义
1.格式:
类型标识符*标识符
2.说明:
(1)"*"号表示被定义的变量为指针变量;
(2)标识符即为被定义的指针变量名;
(3)类型标识符表示被定义的指针变量只能指向相应类型的其它变量。
四、指针变量的引用
1.对指针变量的赋值:
指针变量名=&变量名;
2.给指针变量所指向的存储单元中赋值:
*指针变量名=变量名;
3.将指针变量所指向的变量中的内容赋给其它变量:
变量名=*指针变量名;
例1(教材P204例10.1)指针变量的引用。
main()
{inta,b;
int*pointer_1,pointer_2;/*注意pointer_1和pointer_2中的"_"是下划线而不是减号*/
a=100;b=10;
pointer_1=&a;/*变量a的地址赋给指针变量pointer_1*/
pointer_2=&b;/*变量b的地址赋给指针变量pointer_2*/
printf("%d,%d\n",a,b);/*输出变量a和b的地址*/
printf("%d,%d\n",*pointer_1,*pointer_2);/*输出*pointer_1和*pointer_2即变量a,b的值*/
}
程序运行结果为:
100,10
100,10
例2指针变量的引用的另一个例子。
main()
{inti,j,k;
int*pi,pj;
pi=&i;/*将i的地址赋给指针变量pi*/
pj=*j;/*将j的地址赋给指针变量pj*/
*pi=1;/*对pi所指向的存储单元访问,即对i的地址进行间接访问,*pi与i等价*/
*pj=10;/*对pj所指向的存储单元访问,即对j的地址进行间接访问,*pj与j等价*/
k=*pi+*pj;
printf("i=%d,j=%d,k=%d\n",i,j,k);/*输入整型变量i,j,k的值*/
printf("pi=%o,pj=%o\n",pi,pj);/*以八进制格式输出pi和pj值,即i和j的地址*/
}
程序运行结果为:
i=1,j=10,k=11
pi=177726,pj=177730;
从程序的运行结果可以看出:
pi(即&i)和pj(即&j)的值相差2,因为整型变量在内存
中被分配2个字节的存储单元,故两个变量的地址值也相差2,并注意到输出这两个地址时
使用的是%o(即八进制无符号数)格式,故分别为177726和177730.
例3(教材P206例10.2)输入a和b两个整数,按先大后小的顺序输出a和b。
main()
{int*p1,*p2,*p,a,b;/*注意这种定义方法中p1,p2,p为指针变量,a和b为整型变量*/
scanf("%d,%d",&a,&b);
p1=&a;
p2=&b;
if(a
{p=p1;p1=p2;p2=p;}/*两个指针变量交换,交换以后,p1指向存放大数的单元,p2指向存放小数的单元*/
printf("a=%d,b=%d\n",a,b);
printf("max=%d,min=%d\n",*p1,*p2);
}
程序运行时,从键盘上输入:
5,9
结果如下:
a=5,b=9
max=9,min=5
五、指针变量作为函数的参数
在C语言中,可以用指针变量作为函数的参数,此时形参和实参都应当为指针类型数据。
使用指针变量作参数,在函数执行过程中能够使指针变量所指向的变量值发生变化,从而在函数调用结束后这些变化后的值得以保存,并在主调函数中使用它们。
例4(教材P207例10.3)对输入的两个数按大小顺序输出用指针类型的数据作函数的参数。
swap(p1,p2)/*函数中p1和p2并未交换,但p1和p2所指向的变量单元进行了交换*/
int*p1,*p2;/*形参为两个指针变量,其值分别为实参pa(即&a)和pb(即&b)的值*/
{intp;/*定义中间变量p进行交换使用*/
p=*p1;/*将形参p1所指向的存储单元(main函数中的变量a)中的数据放入中间单元p中*/
*p1=*p2;/*将p2所指向的存储单元(main函数中的变量b)中的数放入p1所指向的存储单元中*/
*p2=p;/*将中间变量p中的数据放入p2所指向的存储单元中*/
}
main()
{int*pa,*pb;
inta=1,b=2;
printf("a=%d,b=%d\n",a,b);/*输出交换前的数据*/
pa=&a;
pb=&b;
swap(pa,pb);/*指针变量pa和pb作为实参,即变量a和b的地址*/
printf("a=%d,b=%d\n",a,b);/*输出交换后的数据*/
}
程序运行结果如下:
a=1,b=2
a=2,b=1
例5(教材P210例10.4)输入三个数,按大小顺序输出.
swap(pt1,pt2)/*函数swap的功能是使两个指针变量所指向的单元的值进行交换*/
int*pt1,*pt2;/*两个形参均为基类型为整型的指针变量*/
{intp;
p=*pt1;
*pt1=*pt2;
*pt2=p;/*由于地址作参数,实际上进行的是main函数中两个变量中的数值的交换*/
}
exchange(q1,q2,q3)/*函数exchange的功能是对三个指针变量所指向的单元的数值排序*/
int*q1,*q2,*q3;
{if(*q1<*q2)swap(q1,q2);/*执行后q1所指向的单元(即a)中存放的是a,b中的较大者*/
if(*q1<*q3)swap(q1,q3);/*执行后q1所指向的单元(即a)中存放的是a,b,c中的最大者*/
if(*q2<*q3)swap(q2,q3);/*执行后q2所指向的单元(即b)中存放的是b,c中的较大者*/
}
main()
{inta,b,c,*p1,*p2,*p3;
scanf("%d,%d,%d",&a,&b,&c);
p1=&a;p2=&b;p3=&c;
exchange(p1,p2,p3);
printf("%d,%d,%d\n",a,b,c);
}
六、对指针变量的一些补充说明
1.指针变量的定义和引用中都使用了*,但二者含义不同.在定义时*的含义是所定义的变量为指针变量而不是其它类型的变量;在引用指针变量时的*是间接访问运算符。
2."&*变量名"和"*&变量名"二者的意义不同,根据这二个运算符号的右结合性,"&*变量名"与"&(*变量名)"等价,而"*&变量名"与"*(&变量名)"等价.前者的变量类型必须为指针类型,后者的类型可以任意;前者表示取指针变量名所向的变量单元的地址,后者表示指向变量名的地址所确定变量单元即变量自身,也就是说,"*&变量名"与"变量名"是等价的。
3.指针变量的值可以使用printf()函数输出,如例1。
请看如下的程序:
main()
{int*p1,*p2;inta=1,b=2;
floatf=2;longl=1000;
doubled=1000,*pd;
float*pf;long*pl;
p1=&a;p2=&b;
pf=&f;pl=&l;
pd=&d;
printf("\n整型变量a,b的地址%o%o\n",p1,p2);
printf("单精度型变量f的址%o\n",pf);
printf("长整型变量l的地址%o\n",pl);
printf("双精度型变量d的地址%o\n",pd);
printf("指针变量pd的地址%o\n",&pd);
}
运行结果如下:
整型变量a,b的地址177702177704
单精度型变量f的址177706
长整型变量的l地址177712
双精度型变量d的地址177716
指针变量pd的地址17726
可以看出,整型变量在内存中占2个字节,单精度型变量在内存中占4个字节,长整型变量在内存中占4个字节,双精度型变量在内存中占8个字节。
§10.3数组的指针和指向数组的指针变量
一、几个基本概念
1.数组的指针:
数组中有许多元素,而数组的指针只有一个,因而数组的指针无法指向各个元素。
在C语言中,数组的指针是指数组的首地址,用数组名表示。
2.数组元素的指针:
数组元素的指针是指数组元素的地址。
3.变址运算符(下标运算符)
(1)运算符号:
[]
(2)运算功能:
使指针变量或数组名所表示的地址移动若干个相对移动量(每个相对移动量所表示的内存单元的大小视数据类型而定),然后取出相应变量的值。
(3)使用方法:
指针变量[下标]
数组名[下标]
(4)结合性:
自左向右
(5)优先等级:
最高,与括号相同
例如:
有一维整型数组a,a[3]表示从数组a的首地址开始,移动3个相对移动量,每个相对移动量为一个数组元素所占的存储单元的字节数.对于整型数组a,每个相对移动量为2字节,即向下移动6个字节,然后对这个地址进行间接访问,即与*(a+3)等价。
二、指向一维数组的指针变量
1.一维数组及其元素的地址
如果有一维数组a,则:
a首地址:
a
a的第i个元素的地址:
a+i&a[i]
a的第i个元素的值:
*(a+i)a[i]
2.指向一维数组的指针变量
定义:
类型说明符*标识符;
赋值:
指针变量名=数组名
指向一维数组的指针变量的运算:
p+i表示移动i个相对移动量,一个移动量是一个数组元素所占的存储单元的字节数.如:
一个指向整型数组的指针变量的一个相对移动量为2个字节,一个指向字符型数组的指针变量的一个相对移动量为1个字节。
如果有一个一维数组a,指针变量p,将a的首地址赋给p,则有:
a的首地址:
p&p[0]
a的第i个元素的地址:
p+i&p[i]
a的第i个元素的值:
*(p+i)p[i]
3.有关一维数组及其指针变量在使用时的注意事项
(1)指针变量可以实现使本身的值改变,即可以使用p++,a++.p++与p+1等价,但是指针变量的加减运算是使其值增加若干个相对移动量。
(2)注意下面几种运算:
*p++与*(p++)等价(*与++同优先等级,右结合性)
*(p++)与*(++p)不等价(前者指向当前,后者指向下一个)
(*p)++与*(p++)不等价(前者表示变量值加1,后者表示移动一个变量单元)
(3)数组名本身表示数组的首地址,是常量而不是变量,故只能进行加减运算,但不能进行自加自减运算。
例1(教材P212例10.5)输出一维数组的全部数组元素(指针指向数组的首元素)。
程序如下:
main()
{inta[10],i,*p;
p=a;
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
for(i=0;i<10;i++)
printf("%d",a[i]);/*此句中的a[i]还可以改成:
*(a+i)、*(p+i)、p[i]*/
}
例2 一维数组的指针和一维数组元素的指针(指针指向数组中的任意元素)。
main()
{inta[10]={1,2,3};
int*pa,*p;
pa=a;/*数组a的首地址赋给指针变量pa,则pa与a等价,pa指向一维数组a*/
p=&a[2];/*数组元素a[2]的地址赋给指针变量p,则&a[2]与p等价,p指向a[2]*/
printf("a[1]=%d\n",*(pa+1));/**(pa+1)、*(a+1)、a[1]三者等价*/
printf("a[2]=%d\n",*p);/**p、*(&a[2])、a[2]三者等价*/
printf("a[3]=%d\n",*(pa+3));/**(pa+3)、*(a+3)、a[3]三者等价*/
}
程序运行结果为:
a[1]=2
a[2]=3
a[3]=0
例3一维数组的指针和指向一维数组的指针变量 。
main()
{inta[]={1,2,3,4,5},*p;
p=a;/*将数组a的首地址赋给指针变量p*/
printf("%d%d%d%d\n",*a,*p,a[0],p[0]);
printf("%d%d%d%d\n",*(a+4),*(p+4),a[4],p[4]);
printf("%8x%8x%8x%8x\n",a,p,&a[0],&p[0]);/*输出地址的值最好用无符号格*/
printf("%8x%8x%8x%8x\n",a+2,p+2,&a[2],&p[2]);/*式输出,即用%u、%x、%o格式*/
}
想一想,上面程序的输出结果中,哪些输出值是相同的?
哪些输出值是不同的?
哪些输出值之间的相对关系可以确定?
下面是有关一维数组指针与一维数组元素及其地址之间的一些对应关系:
如果a是一维数组,p是指针变量,将a的首地址赋给p,则有:
a的首地址:
a
a的第i个元素地址:
a+i p+i &a[i] &p[i]
a的第i个元素的值:
*(a+i)*(p+i)a[i] p[i]
a的第0个元素的值:
*a *p a[0] p[0]
如果p是指向一维数组中的某个元素,则上述等价关系不一定成立,这时:
p+i表示自p当前所指向的数组元素向下移动i个相对移动量所对应的数组元素的地址。
*(p+i)表示自p当前所指向的数组元素向下移动i个相对移动量所对应的数组元素的值。
例4指针变量指向数组任意元素的情况。
main()
{inta[]={1,2,3,4,5},*p;
p=&a[1];/*将数组a中的一个元素的地址赋给指针变量p*/
printf("%d%d%d%d\n",*a,*p,a[0],p[0]);
printf("%d%d%d%d\n",*(a+4),*(p+4),a[4],p[4]);
printf("%8x%8x%8x%8x\n",a,p,&a[0],&p[0]);
printf("%8x%8x%8x%8x\n",a+2,p+2,&a[2],&p[2]);
}
分析一下,该程序运行的结果与例2相比,有什么不同?
为什么会有这些不同?
从上面两个例子可以看出,数组名a永远表示数组的首地址,a+i表示第i个元素的地址;而指针变量p所表示的各种含义则与p所赋的初值有关,即看p当前指向数组中的哪个元素,p+i表示自该元素向下i个元素的地址。
4.一维数组名作函数参数
(1)形参和实参都是数组名
例5(教材P217例10.7)将一个数组中的n个数按相反顺序存放,形参和实参均为一维数组。
voidinv(x,n)/*形参为一维数组,需在形参说明中加以说明*/
intx[],n;
{intt,i,j,m=(n-1)/2;
for(i=0;i<=m;i++)/*交换的次数最多为数据个数n的一半,i的终值不能为n*/
{j=n-i-1;/*j的值随i的值增大而减小*/
t=x[i];x[i]=x[j];x[j]=t;}
return;
}
main()
{staticinti,a[10]={3,7,9,11,0,6,7,5,4,2};
printf("Theoriginalarray:
\n");/*为输出原始数组进行提示*/
for(i=0;i<10;i++)/*输出原始数组*/
printf("%d,",a[i]);
printf("\n");
inv(a,10);/*调用函数inv进行逆序存放,实参为一组数组*/
printf("Thearrayhasbeeninverted:
\n");/*为输出逆序后的数组进行提示*/
for(i=0;i<10;i++)/*输出逆序后的数组*/
printf("%d,",a[i]);
printf("\n");
}
程序运行结果如下:
Theoriginalarray:
3,7,9,11,0,6,7,5,4,2,
Thearrayhasbeeninverted:
2,4,5,7,6,0,11,9,7,3,
(2)形参为指针变量,实参为数组名:
在调用函数时,将实参的首地址传给形参。
请看如下的程序:
例6(教材P219例10.8)将一个一维数组中的最大元素和最小元素找出来intmax,min;/*定义一个全局变量,在整个程序中均可使用*/
voidmax_min_value(array,n)/*在函数中形参为指针变量*/
int*array,n;/*调用时实参的值(即数组number的首地址传给形参array*/
{int*p,*array_end;
array_end=array+n;/*数组中最后一个元素后面的存储单元的地址赋给array_end*/
max=min=*array;/*认为首元素既是最大值,又是最小值*/
for(p=array+1;p {if(*p>max)max=*p; elseif(*p return; } main() {inti,number[10]; printf("enter10datas\n"); for(i=0;i<10;i++)/*输入原始数据*/ scanf("%d",&number[i]); printf("The10datasare: \n"); for(i=0;i<10;i++)/*输出原始数据*/ printf("%d",number[i]); printf("\n"); max_min_value(number,10);/*在调用函数时,以数组名为实参*/ printf("max=%d,min=%d\n",max,min);/*输出最大、最小值,注意到这两个变量均为全局变量*/ } 程序运行时,先输出: enter10datas 然后从键盘上输入 12345678910 结果如下: The10datasare: 12345678910 max=10,min=1 (3)形参为数组名,实参为指针变量: 在主调函数中将数组的首地址传给指针变量,在调用函数时将指针变量传给形参。 例7 将一个一维数组的中的数据按相反顺序存放,形参为数组名,实参为指针变量。 voidinv(x,n) intx[],n;/*形参为一维数组,调用时实参的值(即数组number的首地址)传给形参*/ {int*p,t,*i,*j,m=(n-1)/2; i=x;/*指针变量i中存放数组首地址*/ j=x+n-1;/*指针变量j中存放数组中最后一个元素的地址*/
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第十四讲 程序控制论 第十四 程序 控制论