《c语言程序设计》课件-第7章 指针_第1页
《c语言程序设计》课件-第7章 指针_第2页
《c语言程序设计》课件-第7章 指针_第3页
《c语言程序设计》课件-第7章 指针_第4页
《c语言程序设计》课件-第7章 指针_第5页
已阅读5页,还剩71页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第7章指针C语言程序设计内容提要指针的概念难点:理解指针数据类型用指针做函数参数,向函数传递变量值、数组元素和字符串动态内存分配函数及其应用一维、二维动态数组的实现Skill用指针做函数参数编程为什么引入指针的概念铁杆C/C++程序员最挚爱的武器:指针C/C++的高效、高能主要来自于指针很多不可能的任务由指针完成大多数语言都有无数的“不可能”而C语言是“一切皆有可能”——李宁“ImpossibleisNothing”——adidas为什么引入指针的概念指针为函数提供修改变量值的手段

为C的动态内存分配系统提供支持

为动态数据结构(如链表、队列、二叉树等)提供支持

改善某些子程序的执行效率

变量(Variables)与变量的地址(Address)变量的地址变量名内存:计算机内的存储部件所有指令和数据都保存在内存里速度快,可随机访问,但掉电即失编译或函数调用时为变量分配内存单元inta=0;0x0037b0000000ContentsContentsContentsContentsContentsContentsContents变量的值a某存储区域变量是对程序中数据存储空间的抽象

变量(Variables)与变量的地址(Address)变量的地址内存中的每个字节都有唯一的一个编号(地址)地址是一个无符号整数,其字长一般与主机相同地址按字节编号,按类型分配空间inta=0;0x0037b0000000ContentsContentsContentsContentsContentsContentsContentsa某存储区域0x0037b0010x0037b0020x0037b003&atheAddressOperator

变量(Variables)与变量的地址(Address)如何读写内存中的数据?inta=0;0x0037b0000000ContentsContentsContentsContentsContentsContentsContentsa某存储区域0x0037b0010x0037b0020x0037b003只要指明要访问的变量的内存单元地址就可以立即访问到变量所在的存储单元&ascanf("%d",&a);

变量(Variables)与变量的地址(Address)如何读写内存中的数据?inta=0;0x0037b0000000ContentsContentsContentsContentsContentsContentsContentsa某存储区域0x0037b0010x0037b0020x0037b003直接访问:按变量地址存取变量值&ascanf("%d",&a);

变量(Variables)与变量的地址(Address)如何读写内存中的数据?inta=0;0x0037b0000000ContentsContentsContentsContentsContentsContents0x0037b000a某存储区域0x0037b0010x0037b0020x0037b003间接访问:通过存放变量地址的变量去访问变量&a指针(Pointer)的概念什么类型的变量可以存放变量的地址?指针类型——存放地址型数据的特殊数据类型指针变量——专门用于存放地址型数据的变量变量的指针←→变量的地址

指针变量

指向

变量变量的地址(指针)变量值变量地址存入指针变量指针的定义如何定义指针变量?inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...整型变量10指针变量0x0037b000指针的定义指针变量指向的数据类型称为基类型inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...整型变量10指针变量0x0037b000用指针变量要指向的数据类型作为指针变量的基类型int

*pa;pa错误的指针定义如何在一个数据类型声明两个指针?用法

int*p1,*p2;错误的声明int*p1,p2;指针的赋值inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...整型变量10指针变量0x0037b000仅仅是定义了可以指向int型数据的指针变量,但并未指向a使其指向a需对指针变量初始化int

*pa;pa=&a;int

*pa=&a;pa指针的赋值inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...整型变量10指针变量0x0037b000int

*pa;pa=&a;int

*pa=&a;paPointershavenames,typesandvalues指针的赋值inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...整型变量10指针变量0x0037b000int

*pa;pa=&a;int

*pa=&a;只能指向同一基类型的变量,否则将引起warningfloat

a;int*pa=&a;warningC4133:'=':incompatibletypes-from'float*'to'int*'painti,*p;p=&i;

int*p;float*q;p=q;inti;float*p;p=&i;int*p;p=100;判断对错指针变量只存放地址!一个指针变量不能指向与其类型不同的变量!我是对的,你猜对了吗?应在类型相同的指针变量之间赋值inti=24;i是int变量&i是int指针,指向变量i但你不能对它赋值指针操作符和地址操作符&i24i地址操作符int*p;p=&i;p是int指针

*p是指针p所指向的存储单元的内容象普通变量i一样使用*p,*取指针p指向内存的内容指针操作符和地址操作符p24*p指针操作符指针操作符和地址操作符inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...200x0037b000int

*pa=&a;

*(&a)/*该表达式引用的是变量a的内容*/

&(*pa)

/*该表达式的值代表的是变量a的地址*/pa指针的使用inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...整型变量10指针变量0x0037b000int

*pa;pa=&a;int

*pa=&a;*pa=20;20间接访问(寻址)pa指针的使用inta=10;0x0037b000a0x0037b0040x0037b0080x0037b00B&a…...…...整型变量20指针变量0x0037b000int

*pa;pa=&a;int

*pa=&a;*pa=20;如果指针指向一个非你控制的内存空间并对该空间进行访问,将可能造成危险Neveruseuninitializedpointers.painti;

scanf("%d",i);

/*这样会如何?*/charc;

scanf("%d",&c);

/*这样呢?*/i的值被当作地址。如i==100,那么输入的整数就会从地址100开始写入内存输入以int的二进制形式写到c所在的内存空间。c所占内存不足以放下一个int,其后的空间也被覆盖指针的使用inti;int*iPtr=&i;intj=3;int*jPtr=&j;思考:*jPtr=*iPtr;

i=4;*jPtr=i;iPtr=j;iPtr?ijPtr3jpointermanipulation——算术运算

short*p,a[10];p=a;p++;p值增加多少?pp+1a[0]pointermanipulation——算术运算

short*p,a[10];p=a;p++;p值增加多少?如果short改成long,p值增加多少呢?指针的加减运算是以其基类型的字节长度为单位的pp+1a[0]pointermanipulation——算术运算指针运算不能乱算指针和整数的加减运算同类型指针之间的减法运算其它运算,比如乘法、除法、浮点运算、指针之间的加法等,并无意义,所以也不支持PointersandErrors对指针指向的存储单元执行++操作,请使用

(*p)++而不是

*p++

*p*p=*p+1;*pp=p+1;pointermanipulation——关系运算指向同一种数据类型的两个指针才能进行关系运算值为1或0p>qp<qp==q不能与非指针类型变量进行比较pointermanipulation——赋值运算指针在使用前一定要赋值确定指针指向哪里为指针变量赋的值必须是一个地址main(){

int*p; scanf("%d",p);…}main(){

inta,*p=&a;scanf("%d",p);…}TC下不报错VC下报错PointersandFunctions—指针与函数简单变量做函数参数——CallbyValue(传值)不能改变实参的值形参(parameter)←

实参变量(variable)指针做函数参数——CallbyReference(传地址)

为了改变实参的值请使用:指针形参(Pointerparameter)←&(variable)a&apointerparameteraxparameterargumentvoidSwap(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;}/*callbyreference:inta=15,b=8;swap(&a,&b);*/PassbyReferenceDeclaretheparameter

xandyasapointerInthebodyoftheprocedure,ifdereferencex,use*xInthecallifargument

a

isavariable,use&a两数互换例7.1~7.2voidSwap(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;}/*callbyreference:inta=15,b=8;int*pa=&a,*pb=&b;swap(pa,pb);*/PassbyReferenceInthecallifargument

paisapointer,usepa

without

&Declaretheparameter

xandyasapointerInthebodyoftheprocedure,ifdereferencex,use*x两数互换例7.1~7.2voidSwap(int*x,int*y){inttemp;temp=*x;*x=*y;*y=temp;}main(){inta,b;a=5;b=9;Swap(&a,&b);printf("a=%d,b=%d",a,b);}

voidSwap(intx,inty){inttemp;temp=x;x=y;y=temp;}main(){inta,b;a=5;b=9;Swap(a,b);printf("a=%d,b=%d",a,b);}程序1程序2例7.1~7.2:编写函数实现两数的互换主调函数被调函数实参形参结果有何不同?NotWork!Why?Tracetheexecution主调函数被调函数main(){

inta,b;a=5;b=9;Swap(a,b);printf("a=%d,b=%d",a,b);}voidSwap(intx,inty){

inttemp;temp=x;x=y;y=temp;}55ab实参形参99xyab程序1xy55temp9x

和y是内部变量单向值传递主调函数被调函数main(){

inta,b;a=5;b=9;Swap(&a,&b);printf("a=%d,b=%d",a,b);}voidSwap(int*x,int*y){

inttemp;temp=*x;*x=*y;*y=temp;}&a&a实参形参&b&bxyab程序2xy5temp5ab995*x*y交换的是x

和y指向的单元内容voidSwap(int*x,int*y){

inttemp;temp=*x;*x=*y;*y=temp;}指针pTemp未初始化指针pTemp指向哪里未知对未知单元写操作是危险的voidSwap(int*x,int*y){

int

*pTemp;

*pTemp=*x;*x=*y;*y=*pTemp;}voidSwap(int*x,int*y){

inttemp;temp=*x;*x=*y;*y=temp;}非危险操作但是交换的是地址值不是指针指向单元的内容voidSwap(int*x,int*y){

int

*pTemp;

pTemp=x;x=y;y=pTemp;}指针变量与其它类型变量的对比共性在内存中占据一定大小的存储单元先定义,后使用特殊性

它的内容只能是地址,而不能是数据必须初始化后才能使用,否则指向不确定的存储单元只能指向同一基类型的变量可参与的运算:加、减整数,自增、自减、关系、赋值使用原则明确指针指向了哪里明确指针指向单元的内容是什么字符数组与字符指针C语言并没有为字符串提供任何专门的表示法,完全使用字符数组和字符指针来处理字符串就是一串以用''引起来的字符HelloChina\0字符数组就是每个元素都是字符型的数组字符指针就是指向字符类型数据的指针"HelloChina"pStr数组最后一个元素必须是'\0'才表示字符串字符数组与字符指针定义和初始化方法不同

char*pStr="HelloChina";HelloChina\0"HelloChina"pStrcharstr[12]={"HelloChina"};

char*pStr;pStr="HelloChina";strpStr=&str[0];字符数组与字符指针定义和初始化方法不同

str="HelloChina";HelloChina\0"HelloChina"pStrcharstr[12]={"HelloChina"};

char*pStr;pStr="HelloChina";strWhy?数组名str是地址常量

字符指针pStr是变量

例7.5:字符串拷贝——用字符数组编程voidMyStrcpy(chardstStr[],charsrcStr[]){

inti=0;

while(srcStr[i]!='\0') { dstStr[i]=srcStr[i]; i++; } dstStr[i]='\0';}HelloChina\0

srcStr[i]dstStr[i]Hi=0ei=1li=2li=3oi=4i=5Ci=6hi=7ii=8ni=9ai=10\0srcStr[i]=='\0voidMyStrcpy(char*dstStr,char*srcStr){

while(*srcStr!='\0') { *dstStr=*srcStr; srcStr++; dstStr++; } *dstStr='\0';}例7.5:字符串拷贝——用字符指针编程HelloChina\0

*srcStr*dstStrHelloChina\0*srcStr=='\0srcStr++srcStrdstStr++dstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrsrcStrdstStrvoidMyStrcpy(char*dstStr,constchar*srcStr){

while(*srcStr!='\0') { *dstStr=*srcStr; srcStr++; dstStr++; } *dstStr='\0';}例7.5:字符串拷贝——用字符指针编程HelloChina\0

*srcStr*dstStrHellsrcStrdstStrChina\0o当只允许访问指针指向的地址中的内容时,把函数的指针形参定义为const,试图修改内容时编译器会报错ProtectingParameterValuesA

const

qualifierqualifypointers

使用const修饰指针变量

constint*p;

pointertoaconstantintegerp是一个指针变量,可以指向一个整型常量thevalueofpmaychange,butthevalueof*pcannot执行*p=10这样的赋值操作,VC下编译会提示如下错误信息:errorC2166:l-valuespecifiesconstobjectint*constp;

constantpointertointegerp是一个常量指针,可以指向一个整数thevalueof*p

canchange,butthevalueofpcannot例7.6:计算实际字符个数unsignedintMyStrlen(charstr[]){

inti;

unsignedintlen=0;

for(i=0;str[i]!='\0';i++) { len++; }

return(len);}unsignedintMyStrlen(constchar*pStr){

unsignedintlen=0;

for(;*pStr!='\0';pStr++) { len++; }

return(len);}方法2:用字符指针实现方法1:用字符数组实现指针与数组inta[4]={1,2,3,4};0x0037b000a[0]0x0037b0040x0037b0080x0037b00Ba….…...1int

*pa=a;paint

*pa=&a[0];234a[1]a[2]a[3]数组名是一个常量指针不能修改该指针的指向指针可当数组名使用指针与数组inta[4]={1,2,3,4};0x0037b000a[0]0x0037b0040x0037b0080x0037b00Ba….…...1int

*pa=a;paint

*pa=&a[0];234a[1]a[2]a[3]数组元素的等价引用形式a[i]*(a+i)pa[i]*(pa+i)a+1*(a+1)pa[0]*(pa+2)pa+2*pa指针与数组inta[4]={1,2,3,4};0x0037b000a[0]0x0037b0040x0037b0080x0037b00Ba….…...1p234a[1]a[2]a[3]for(i=0;i<4;i++)scanf("%d",&a[i]);

for(i=0;i<4;i++)printf("%d",a[i]);for(p=a;p<(a+4);p++)scanf("%d",p);

for(p=a;p<(a+4);p++)printf("%d",*p);*p*pa+4例7.7:插入排序算法的关键是:找到待插入的位置依次移动插入位置及其后的所有元素腾出这一位置放入待插入的元素a[0]a[1]a[2]a[3]a[4]a[5]待插入元素x=41

3

57

9

5

7

9

4插入元素x=4例7.7:插入排序a[0]a[1]a[2]a[3]a[4]a[5]待插入元素x=41

3

57

9

for(i=0;(i<n)&&(x>a[i]);i++) { }/*找到待插入的位置*/

找到了待插入的位置例7.7:插入排序

pos=i;

for(i=n-1;i>=pos;i--) { a[i+1]=a[i];/*向后移动*/ } a[pos]=x;/*插入元素x到位置pos*/a[0]a[1]a[2]a[3]a[4]a[5]1

3

57

9

5

7

9

4插入元素x=4待插入元素x=4例7.7:插入排序voidInseart(inta[],intn,intx){

inti,pos;

for(i=0;(i<n)&&(x>a[i]);i++) { }/*找到待插入的位置*/ pos=i;

for(i=n-1;i>=pos;i--) { a[i+1]=a[i];/*向后移动*/ } a[pos]=x;/*插入元素x到位置pos*/}例7.3:在一个班级中找出最高分及其学号voidFindMax(intscore[],longnum[],intn,intpMaxScore,longpMaxNum){

inti; pMaxScore=score[0]; pMaxNum=num[0];

for(i=1;i<n;i++) {

if(score[i]>pMaxScore) { pMaxScore=score[i]; pMaxNum=num[i]; } }}能返回这两个值吗?例7.3:在一个班级中找出最高分及其学号voidFindMax(intscore[],longnum[],intn,int

*pMaxScore,long

*pMaxNum){

inti;

*pMaxScore=score[0];

*pMaxNum=num[0];

for(i=1;i<n;i++) {

if(score[i]>*pMaxScore) {

*pMaxScore=score[i];

*pMaxNum=num[i]; } }}指针参数指定了存放这两个值的地址指针和数组做函数参数通过指针或数组参数,使调用者获得修改后的数据通过一个参数把大量的数据送到函数内如果只向内传送数据,就把参数定义为const,防止意外修改数据,也让函数的功能更明确voidPrintArray(const

int*p,intn)

{

......

}voidPrintArray(const

inta[],intn)

{

......

}指针、数组以及其它的类型混合基本数据类型int、long、char、short、float、double……数组是一种数据类型是从其它类型派生的类型每个元素都有一个类型指针是一种数据类型是从其它类型派生的类型XX类型的指针任何类型都可以做指针或者数组的基类型指针数组用指针作数组的基类型——?指针数组元素均为指针类型数据的数组定义形式为:

数据类型*数组名[数组长度];例如

char*ptr[5];

ptr[5]*char例7.10main(){

inti;

char

str[][10]={"Pascal","Basic","Fortran","Java","VisualC"};

for(i=0;i<5;i++){printf("%s\n",str[i]);

}}strstr[0]Pascalstr[1]str[2]str[3]BasicFortranJava二维数组字符串VisualCstr[4]例7.10main(){

inti;

char

*ptr[]={"Pascal","Basic","Fortran","Java","VisualC"};

for(i=0;i<5;i++){printf("%s\n",ptr[i]);

}}ptr[0]Pascalptr[1]ptr[2]ptr[3]BasicFortranJavaptr指针数组字符串ptrVisualCptr[4]例7.10:字符串按字典顺序排序—二维数组编程char

str[N][10]={"Pascal","Basic","Fortran","Java","VisualC"};for(i=0;i<N-1;i++) {

for(j=i+1;j<N;j++) {

if(strcmp(str[j],str[i])<0) {

strcpy(temp,str[i]); strcpy(str[i],str[j]); strcpy(str[j],temp); } }}strstrstrstrstrstrstrstrstrstr例7.10:字符串按字典顺序排序—指针数组编程char

*ptr[N]={"Pascal","Basic","Fortran","Java","VisualC"};for(i=0;i<N-1;i++){

for(j=i+1;j<N;j++){

if(strcmp(ptr[j],ptr[i])<0){

temp=ptr[i]; ptr[i]=ptr[j]; ptr[j]=temp;} }}指针数组ptr字符串排序前Pascal\0Basic\0Fortran\0Java\0VisualC\0ptr[0]ptr[1]ptr[2]ptr[3]ptr[4]指针数组ptr字符串排序后Pascal\0Basic\0Fortran\0Java\0VisualC\0ptr[0]ptr[1]ptr[2]ptr[3]ptr[4]返回指针值的函数

数据类型*函数名(参数表){……}编一个函数连接两个字符串,然后返回连接后字符串的首地址返回指针值的函数char*MyStrcat(char*dstStr,char*srcStr){ char*pStr=dstStr;

while(*dstStr!='\0') { dstStr++; }

for(;*srcStr!='\0';dstStr++,srcStr++) { *dstStr=*srcStr; } *dstStr='\0'; returnpStr;}返回指针值的函数#include<stdio.h>#defineARR_SIZE80char*MyStrcat(char*dstStr,char*srcStr);main(){ charfirst[ARR_SIZE]="Hello"; charsecond[ARR_SIZE]="world"; char*result=NULL;

result=MyStrcat(first,second); printf("\nTheresultis:%s\n",result);}这个字符数组应该保证足够大动态分配内存Twoprimarymethodsofallocati

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论