




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
《C语言程序设计教程》
(第二版)Lizq98@李志球、刘昊编著1第7章
指针
本章要点:
◆
了解指针和指针变量的基本概念◆
掌握指针变量的定义和引用方法◆
掌握数组的指针和指向数组的指针变量◆
掌握函数的指针和指向函数的指针变量◆
掌握指针数组和指向指针的指针概念2第7章
指针目录
7.1指针的概念7.2指针变量7.3指针与数组7.4指针与函数7.5返回指针值的函数7.6指针数组和指向指针的指针
37.1指针的概念在计算机中,所有的数据都是存放在存储器中的。不同的数据类型所占用的内存单元数不等,为了正确地访问这些内存单元,必须为每个内存单元编号。根据一个内存单元的编号即可准确地找到该内存单元,内存单元的编号称为地址。说明一个变量后,编译器将划分出若干存储器单元来存储该变量。编译器将这个存储单元地址与变量名联系起来,程序引用这个变量名时,系统就访问相应的存储单元。1000100110021003100410051006100710081009
100value47.1指针的概念内存单元的编号或地址称为指针。C语言中允许用一个变量来存放指针,这种变量称为指针变量。因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。例如定义p_value用来存放value的地址,如上图所示。因为p_value包含变量value的地址,所以它指向value在存储器中的存储单元,也就是说,p_value是指向value的,一般把它称作value的一个指针,如下图所示。1000100110021003100410051006100710081009
1001002valuep_value57.2指针变量7.2.1指针变量的定义及赋值1.指针变量的定义
定义指针变量的格式类型说明符*变量名;其中,类型名说明指针变量所指向变量的类型;星号(*)说明所定义的变量是一个指针变量。指针变量可与非指针变量一起说明,例如:char*p_char;float*p_value,percent;注意:*p_char说明了p_char是一个指针变量,指针变量名为p_char,而不是*p_char。67.2指针变量7.2.1指针变量的定义及赋值2.指针变量的赋值
1)指针变量初始化2)用赋值语句给指针变量赋值指针变量的赋值只能赋予地址,而不能赋予任何其它数据,否则将引起错误。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。在定义指针变量同时,可以把另一变量的地址赋值给指针变量,即指针变量的初始化。例如:
inta;int*p=&a;inta,*p;p=&a;77.2指针变量7.2.1指针变量的定义及赋值3)说明:(1)上例赋值语句中右边的符号“&”为取地址运算符,当取地址运算符“&”放在一个变量名之前时,它返回该变量在内存中的首地址。(2)不允许把一个数赋予指针变量,故下面的赋值是错误的:
p_value=1002;应该使用取地址运算符“&”把一个地址赋给指针变量。如:
p_value=&value;2.指针变量的赋值
87.2指针变量7.2.1指针变量的定义及赋值3)说明:(3)使用未初始化的指针变量虽不会引起编译出错,但可能导致无法预料的后果。指针变量在保存一个变量的地址之前是不起作用的。(4)一个指针变量只能指向同一个类型的变量,必须在定义时规定指针变量所指向变量的类型。(5)指针变量只能存放地址,不能将一个整型量赋给一个指针变量。2.指针变量的赋值
97.2指针变量7.2.2指针变量的引用
1000100110021003100410051006100710081009
1001002valuep_value*p_value在说明并初始化指针变量之后,便可在程序中引用该指针变量了,指向运算符(*)也因此显示出它的重要性,将它放在指针变量名之前时,表示引用指针变量所指向的变量。如图7.2所示。图7.2指向运算符用于指针将指针变量p_value指向变量value,则可以用*p_value来引用变量value。即*p_value与value具有同样的意义,如果想打印value的值,可以写成:
printf("%d",value);或printf("%d",*p_value);107.2指针变量7.2.2指针变量的引用【例7.1】
指针基本使用方法。#include<stdio.h>main(){int
var=100;
int*ptr;
ptr=&var;/*直接和间接访问变量var*/
printf("\nDirect
access,var=%d",var);
printf("\nIndirect
access,var=%d",*ptr);/*用两种方法显示变量var的地址*/
printf("\n\nTheaddressofvar=%ld",(long)&var);
printf("\nTheaddressofvar=%ld",(long)ptr);}程序运行结果:Directaccess,var=100Indirectaccess,var=100Theaddressofvar=1569325022Theaddressofvar=1569325022117.2指针变量7.2.3指针变量作函数参数在第6章中,函数参数是普通变量,函数和被调用函数之间是以值传递的方式进行参数的信息传递的。引入指针概念后,可以用指针作为函数的参数,使在被调用函数种可以改变主调函数中变量的值。一般在主调函数中将变量的地址(指针)作为参数传递给函数,被调用函数执行时,按这个地址去存取变量参数的值。127.2指针变量7.2.3指针变量作函数参数【例7.2】
对输入的两个整数按大小顺序输出。swap(int*p1,int*p2){int
val;
val=*p1;*p1=*p2;*p2=val;}main(){int
a,b;
int*pointer1,*pointer2;
scanf("%d,%d",&a,&b);pointer1=&a;pointer2=&b;
if(a<b)swap(pointer1,pointer2);
printf("\n%d,%d\n",a,b);}程序运行结果为:3,7<CR>7,3137.3指针与数组
指针与数组之间存在特殊的关系。实际上,在使用数组下标时,就是在不明白指针情况下使用了指针。指针变量可以象指向简单变量一样指向数组和数组元素,即把数组元素的起始地址或某一元素的地址放到一个指针变量中。数组元素的指针指向该元素的地址,数组的指针则是指向数组首元素的地址,即数组的起始地址。147.3指针与数组
7.3.1指向数组元素的指针变量一个数组是由连续的一块内存单元组成的。数组名就是这块连续内存单元的首地址。数组的元素按顺序存储在存储器单元中,它的第一个元素位于第一位,其后的数组元素(下标大于0)存储在后续地址。每个数组元素按其类型不同占有几个连续的内存单元。指向数组的指针变量称为数组指针变量。可以定义一个指针变量,并初始化为指向数组。157.3指针与数组
7.3.1指向数组元素的指针变量例如,用array[]第一个元素的地址来初始化指针变量p_array:
intaray[100],*p_array;
p_array=array;则表达式*array是数组的第一个元素,*(array+1)是数组的第二个元素,依次类推。167.3指针与数组
7.3.1指向数组元素的指针变量【例7.4】
输入10个整数存放在数组中,利用指针变量访问此数组元素,求出其中的最大值。#include<stdio.h>main(){intx[10],*p,i,n,max,min;p=x;
printf("请输入10个整数:");
for(i=0;i<10;i++)
scanf("%d",p+i);max=*p;min=*p;177.3指针与数组
7.3.1指向数组元素的指针变量【例7.4】
输入10个整数存放在数组中,利用指针变量访问此数组元素,求出其中的最大值。for(i=1;i<10;i++){if(*(p+i)>max)max=*(p+i);if(*(p+i)<min)min=*(p+i);}
printf("\nmax=%d:min=%d\n",max,min);}程序运行结果:请输入10个整数:21457870468921556699<CR>max=99:min=21187.3指针与数组
7.3.2指针运算1.指针加减一个整数
指针运算一般是指针变量的增值和减值。当对指针变量进行增1或减1时,将使指针变量的值使它指向下一个或上一个数组元素,并按数据类型将保存在指针变量中的地址增值或减值。例如,ptr_to_int
是指向某int型数组第一个数组元素的指针变量,当执行ptr_to_int++后,则ptr_to_int的值按int型的大小增值(一般为2字节),从而使ptr_to_int指向下一个数组元素。如果ptr_to_float指向一个float型数组,则语句ptr_to_float++按float型的大小(一般为4字节)给ptr_to_float增值,使之指向下一个元素。注意,不能对数组名执行增值和减值运算。当用指针变量对数组元素操作时,编译器不跟踪数组的头和尾,如果不注意的话,可能会因指针变量增值或减值而指向数组之外的元素,一旦如此,可能会出现意想不到的结果,197.3指针与数组
7.3.2指针运算【例7.5】
利用指针运算与指针方法来存取数组元素。#include<stdio.h>#defineMAX10main(){int
i_array[MAX]={0,1,2,3,4,5,6,7,8,9,};
int*i_ptr,count;floatf_array[MAX]={0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9};float*f_ptr;
i_ptr=i_array;
f_ptr=f_array;for(count=0;count<MAX;count++)
printf("\n%d\t%f",*i_ptr++,*f_ptr++);}程序运行结果:00.00000010.10000020.20000030.30000040.40000050.50000060.60000070.70000080.80000090.900000207.3指针与数组
7.3.2指针运算2.两个指针相减
当两个指针变量指向同一数组的不同元素时,两指针变量相减所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。例如pf1和pf2是指向同一浮点数组的两个指针变量,设pf1的值为2010H,pf2的值为2000H,而浮点数组每个元素占4个字节,所以pf1-pf2的结果为(2000H-2010H)/4=4,表示pf1和pf2之间相差4个元素。两个指针变量不能进行加法运算。例如,pf1+pf2毫无实际意义。217.3指针与数组
7.3.2指针运算3.两个指针关系运算
指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的关系。例如:pf1==pf2表示pf1和pf2指向同一数组元素pf1>pf2表示pf1处于高地址位置pf1<pf2表示pf2处于低地址位置指针变量还可以与0比较。设p为指针变量,则p==0表明p是空指针,它不指向任何变量;p!=0表示p不是空指针。空指针是由对指针变量赋予0值而得到的。例如:#defineNULL0int*p=NULL;227.3指针与数组
7.3.3数组名作函数参数C语言中,函数的参数可以是数组,此时实参与形参都应是数组名,当数组作为函数参数时,传递的是数组的首地址,函数“知道”了数组的地址后就可以访问数组元素。【例7.6】
将数组传送到函数。main(){intarray[6],count;
int
largest(intx[],int);
for(count=0;count<6;count++){printf("输入一个整数:")
scanf("%d",&array[count]);}
printf("\n最大值=%d",larges(array,6));}237.3指针与数组
7.3.3数组名作函数参数【例7.6】
将数组传送到函数。int
largest(intx[],inty){int
count,biggest=-12000;
for(count=0;count<y;count++){if(x[count]>biggest)biggest=x[count];}returnbiggest;}程序运行结果:输入一个整数:1<CR>输入一个整数:2<CR>输入一个整数:3<CR>输入一个整数:10<CR>输入一个整数:5<CR>输入一个整数:6<CR>最大值=10247.3指针与数组
7.3.3数组名作函数参数数组名作函数参数注意事项:(1)当把一个简单变量传送到函数时,只是传送了一个复制的变量值,函数可以使用这个值,但不能改变这个原始变量。将一个数组传送到函数时,函数接受的并不是复制的数组的值而是数组的地址,函数处理实际的数组元素并能修改保存,而作为参数传递到函数中的数组地址不会被改变。(2)形参数组和实参数组的类型必须一致,否则将引起错误。(3)形参数组和实参数组的长度可以不相同,因为在调用时,只传送首地址而不检查形参数组的长度。(4)在函数形参表中,允许不给出形参数组的长度。257.3指针与数组
7.3.3数组名作函数参数【例7.7】用键盘输入若干个整数,在函数中用冒泡法实现数据的由小到大排序。#include<stdio.h>voidsort(int
arry[],intn);main(){intx[100],i,n;
printf("请输入数据:");
scanf("%d",&n);数组名作为函数参数时,只把数组的首地址传递给函数,并没有把数组中元素个数传递给函数,要处理不同大小的数组,一般将数组中元素个数也作为参数传送给函数。for(i=0;i<n;i++)
scanf("%d",&x[i]);
sort(x,n);
for(i=0;i<n;i++)
printf("%d\t",x[i]);}267.3指针与数组
7.3.3数组名作函数参数【例7.7】用键盘输入若干个整数,在函数中用冒泡法实现数据的由小到大排序。voidsort(int*arry,intn){int
i,j,t;
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++)if(*(arry+j+1)<*(arry+j)){t=*(arry+j];*(arry+j]=*(arry+j+1);*(arry+j+1)=t;}}277.4指针与函数1.指向函数的指针变量
指向函数的指针提供了调用函数的另一种方法。当程序运行时,每一个函数被装到某个地址开始的内存中,这个起始地址是函数的入口地址,称为函数的指针。可以把此地址赋值给一个指针变量,然后通过该指针变量调用此函数。它提供了一种灵活的调用函数的方法,能使程序在几个函数中“挑选”,并选择符合当前情况的一个。指向函数的指针一般说明格式如下:
type(*ptr_to_func)(parameter_list);其中,ptr_to_func为一个指向函数的指针变量,该函数返回值为type类型,parameter_list是函数传递的实参列表。287.4指针与函数2.用函数指针实现函数的调用
说明了一个指向函数的指针变量后,可以将该指针变量指向某个函数。【例7.8】
使用指向函数的指针调用函数。#include<stdio.h>voidmain(){floatsquare(float);float(*p)(float);p=square;
printf("%f%f",square(6.9),p(6.9));}floatsquare(floatx){returnx*x;}程序运行结果:47.61000147.610001297.4指针与函数2.用函数指针实现函数的调用
使用指向函数的指针变量应注意:(1)当说明指向函数的指针时不要忘记使用圆括号。(2)使用格式char(*func)();,说明一个指向不带参数且返回字符值的函数的指针。(3)指针使用前必须初始化。(4)不能使用与所需类型不同的返回值或实参的函数指针。307.4指针与函数2.用函数指针实现函数的调用
【例7.9】使用指向函数的指针调用不同的函数。#include<stdio.h>voidfunc1(int);voidone(void);voidtwo(void);voidother(void);voidmain(){inta;for(;;){puts(“输入1-10的数,0退出:");scanf("%d",&a);if(a==0)break;func1(a);}}317.4指针与函数2.用函数指针实现函数的调用
【例7.9】使用指向函数的指针调用不同的函数。voidfunc1(intx){void(*ptr)(void);if(x==1)
ptr=one;elseif(x==2)
ptr=two;else
ptr=other;
ptr();}程序运行结果:输入1-10的数,0退出:2<CR>你输入的是2.输入1-10的数,0退出:11<CR>你输入的是1,2以外的数.输入1-10的数,0退出:0<CR>voidone(void){puts(“你输入的是1.");}voidtwo(void){puts("你输入的是2.");}voidother(void){puts(“你输入的是1,2以外的数.");}327.4指针与函数2.用函数指针实现函数的调用
【例7.10】
改写例题7.9,用指向函数的指针作为参数传递给函数实现调用不同的函数。#include<stdio.h>voidfunc1(void(*p)(void));voidone(void);voidtwo(void);voidlther(void);voidmain(){void(*ptr)(void);
inta;for(;;){puts("\输入1-10的数,0退出:");
scanf("%d",&a);337.4指针与函数2.用函数指针实现函数的调用
【例7.10】
改写例题7.9,用指向函数的指针作为参数传递给函数实现调用不同的函数。voidfunc1(void(*p)(void)){(*p)()}voidone(void){puts("你输入的是1.");}voidtwo(void){puts("你输入的是2.");}voidother(void){puts("你输入的是1,2以外的数.");}if(a==0)break;elseif(a==1)ptr=one;elseif(a==2)
ptr=two;else
ptr=other;func1(ptr);}}347.5返回指针值的函数函数可以返回一个整数、字符或实数,也可以返回指针,即地址。返回指针的函数的定义格式为:例如:double*funcl(parameter_list);structaddress*func2(parameter_list);type*func(parameter_list);不能混淆返回指针的函数和指向函数的指针,例如:double(*func)();/*指向一个返回值为double型函数的指针*/double*func();/*返回一个指向double指针的函数*/说明了返回一个指向double类型指针的函数
说明了返回一个指向address结构类型指针的函数357.5返回指针值的函数【例7.11】
从函数返回指针与简单值。#include<stdio.h>intlarger1(intx,inty);int*larger2(int*x,int*y);voidmain(){inta,b,bigger1,*bigger2;
printf("Entertwointegervalues:");
scanf("%d%d",&a,&b);bigger1=larger1(a,b);
printf("\nThelargervalueis%d.",bigger1);bigger2=larger2(&a,&b);
printf("\nThelargervalueis%d.",*bigger2);}367.5返回指针值的函数【例7.11】
从函数返回指针与简单值。intlarger1(intx,inty){if(y>x)returny;elsereturnx;}int*larger2(int*x,int*y){if(*y>*x)returny;elsereturnx;}程序运行结果:Entertwointegervalues:1113333<CR>Thelargervalueis3333.Thelargervalueis3333.377.6指针数组和指向指针的指针
7.6.1指针数组数组的全部元素均为指针类型数据,称为指针数组。指针数组的定义格式为:例如:int*p[10];类型标识*数组名[数组长度说明];指针数组经常在字符串处理中使用。一个字符串是存储在内存中的字符序列,因此用指向第一个字符的指针(指向char类型的指针)指示串的开始,用一个空字符标记串的结束。通过说明和初始化指向char类型的指针数组,就可以访问并处理大量的使用指针数组的字符串了。例如:charmessage[]="Thisisthemessage.";或char*message="Thisisthemessage.";38程序运行结果:Fourscoreandsevenyearsagoourforefathers7.6指针数组和指向指针的指针
【例7.12】初始化并使用指向char类型的指针数组。#include<stdio.h>voidmain(){char*message[8]={"Four","score","and","seven","years","ago","our","forefathers"};
intcount;for(count=0;count<8;count++)
printf("%s",message[count]);}
397.6指针数组和指向指针的指针
【例7.12】初始化并使用指向char类型的指针数组。100015562012100015562012???????message[0]message[1]message[2]message[3]message[4]message[5]message[6]message[7]message[8]message[9]one\0two\0three\0
在此例中,message是一个指向串开始的指针。指针数组与字符串的关系如图9.6所示。注意,数组元素message[3]到message[9]没有初始化以指向图中任何对象。407.6指针数组和指向指针的指针
【例713】
给函数传递指针数组。#include<stdio.h>voidprint_strings(char*p[],intn);voidmain(){char*message[8]={"Four","score","and","seven","years","ago","our","forefathers"};print_strings(message,8);}voidprint_strings(char*p[],intn){intcount;
for(count=0;count<n;count++)
printf("%s",p[count]);}程序运行结果:Fourscoreandsevenyearsagoourforefathers本例说明一个指针数组,且数组名是指向它的第一个元素的指针,当数组传递给函数时,程序传递的是一个指向指针数组(第一个数组元素)的指针(数组名)。417.6指针数组和指向指针的指针
7.6.2指向指针的指针在C语言中,可以建立指向指针数据的指针,即具有一个指针地址值的变量。说明:定义指向指针的指针变量时需使用双重指向运算符**,当用指向指针的指针访问所指的变量时也使用这种运算符。例如:intx=12;/*x是一个整形变量*/int*ptr=&x;/*ptr是一个指向x的指针*/int**ptr_to_ptr=&ptr;/*ptr_to_ptr是一个指向int类型指针的指针*/427.6指针数组和指向指针的指针
7.6.3指针数组作main函数的形参main函数是可以带参数的。C语言规定main函数的参数只能有两个,习惯上这两个参数写为argc和argv,而且argc(第一个形参)必须是整型,argv(第二个形参)必须是指向字符串的指针数组。带形参的main函数的函数头应写为:main(argc,argv)int
argv;char*argv[];或写成
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- T/CGA 42-2023地下黄金矿山岩石力学数据采集技术规范
- T/CECS 10302-2023抗流挂聚氨酯防水涂料
- T/CECS 10295-2023建筑机器人地面清洁机器人
- T/CECS 10163-2021纤维增强聚氨酯复合材料杆塔
- T/CECS 10010-2019罐式全变频调速给水设备
- T/CCPITCSC 075-2021阳光采购通用要求
- T/CCMA 0113-2021高空作业车检查与维护规程
- T/CBMCA 016-2020室内无机建筑涂装材料应用技术规程
- T/CAR 13-2023一体式热源塔热泵机组
- T/CAPEB 00001.4-2022制药装备容器和管道第4部分:管件
- 地域文化(专)-终结性考试-国开(SC)-参考资料
- 《卵巢无性细胞瘤》课件
- 燃气锅炉房工程施工方案
- PRP注射治疗膝关节炎
- 第一次电力工程例会发言稿
- 上海市安装工程预算定额(2000)工程量计算规则
- 安徽省江南十校2023-2024学年高一下学期5月阶段联考化学试题2
- GB/T 7247.1-2024激光产品的安全第1部分:设备分类和要求
- 东方电影学习通超星期末考试答案章节答案2024年
- 唐宋名家诗词鉴赏学习通超星期末考试答案章节答案2024年
- (完整)注册安全工程师考试题库(含答案)
评论
0/150
提交评论