基于AI的C语言程序设计(微课版)课件 第10章 指针_第1页
基于AI的C语言程序设计(微课版)课件 第10章 指针_第2页
基于AI的C语言程序设计(微课版)课件 第10章 指针_第3页
基于AI的C语言程序设计(微课版)课件 第10章 指针_第4页
基于AI的C语言程序设计(微课版)课件 第10章 指针_第5页
已阅读5页,还剩47页未读 继续免费阅读

下载本文档

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

文档简介

第10章

指针C语言的内存导航仪主

:蒋亚平目录CONTENTS01指针的概念02指针变量03通过指针引用数组04字符串指针变量05指向指针的指针06指向函数的指针05指针综合编程案例06本章小结问题导入普通传参普通传参是把变量的“值副本”传入函数,函数修改的只是副本,不会影响原始变量指针传参指针传参传递的是变量的内存地址,函数能顺着地址直接操作原始变量的存储空间。那么,为何地址传递能突破“副本限制”?这两种传参方式的本质差异又该如何理解?01指针的概念指针的概念从门牌号到地址:指针生活化映射内存与指针的类比指针生活化映射将计算机内存比作宿舍楼,每个内存单元就像一个宿舍,拥有唯一的门牌号即地址。指针则相当于记录这些门牌号的纸条,通过它我们可以快速找到对应的内存单元。这种类比帮助初学者理解指针的基本概念,即指针是内存地址的代表。变量与指针的关系当定义一个变量a并赋值为10时,编译器会为其分配一个内存地址,例如1000。此时,指针p可以保存这个地址1000,通过指针p我们就能访问变量a的值。这种关系类似于通过门牌号找到对应的宿舍,从而获取或修改其中的内容。直接访问与间接访问直接访问变量就像亲自拿着钥匙打开宿舍门,而间接访问则先通过指针找到地址,再进行操作。例如,使用变量名a直接访问其值,或者通过指针p间接访问a的值。这两种访问方式在C语言中都很常见,理解它们的区别对于掌握指针至关重要。指针就是地址,地址指向内存单元从门牌号到地址:指针生活化映射内存用户数据区直接访问和间接访问的过程02指针变量指针变量指针变量定义与运算符指针变量的声明在C语言中,指针变量的声明形式为:取地址与解引用运算符取地址运算符'&':用于获取变量的内存地址。解引用运算符'*':用于通过指针访问其指向的内存单元中的数据。指针变量的声明必须明确其指向的数据类型,以便正确地进行内存操作。类型名*指针变量名示例:声明一个指向整型数据的指针变量p。inta=10;int*p;p=&a;//把变量a的地址赋值给指针变量p*表示这是一个指针示例:通过指针变量p来访问变量a的值。printf("%d",*p);//输出结果为10,与printf("%d",a);效果相同指针变量还可以在定义时进行初始化。int*p=&a;例如'&a'得到变量a的地址。例如'*p'访问指针p所指向的变量。指针变量定义与运算符给指针变量赋值p=&a;//将变量a的地址赋给指针变量p通过指针访问其指向的变量printf("%d",*p);//输出指针p所指向变量的值(即a的值)*p=1;//将1赋值给指针p当前指向的变量,若p指向a,相当于a=1;引用指针变量的值printf("%p",p);//输出指针p的地址值(即指针p存储的内存地址)使用指针变量的三种操作

指针变量定义与运算符示例:交换指针变量。运行结果:#include<stdio.h>intmain(){intx,y,*p1,*p2,*p;printf("Pleaseentertwointegers:");scanf("%d,%d",&x,&y);p1=&x;p2=&y;//交换指针变量p1和p2p=p1;p1=p2;p2=p;printf("x=%d,y=%d\n",x,y);printf("*p1=%d,*p2=%d",*p1,*p2);return0;}交换指针变量

地址传参示例:传参示例。运行结果:#include<stdio.h>voidswap(intparam1,intparam2){ inttemp; temp=param1; param1=param2; param2=temp;}intmain(){ intx=5,y=10; swap(x,y); printf("交换后:x=%d,y=%d\n",x,y);return0;}传参和函数内参数交换的过程交换副本

地址传参示例:使用指针作为函数参数来交换两个整数的值。运行结果:#include<stdio.h>//交换函数,使用指针类型参数voidswap(int*p1,int*p2){inttemp=*p1;//临时存储p1指向的值*p1=*p2;//将p2指向的值赋给p1*p2=temp;//将临时存储的p1的值赋给p2}intmain(){intx=5,y=10;printf("交换前:x=%d,y=%d\n",x,y);//调用swap函数交换x和y的值swap(&x,&y);printf("交换后:x=%d,y=%d\n",x,y);return0;}指针作为函数参数函数的参数为指针变量函数的参数不仅可以是整型、浮点型等基本数据类型,还可以是指针类型。指针作为函数参数的作用:将一个变量的地址传递到函数中。交换原件03通过指针引用数组通过指针引用数组一维数组:指针自增替代下标01数组名与指针的关系02指针的自增操作03指针遍历数组在C语言中,数组名本质上是数组首元素的地址。例如,对于数组arr,arr本身就是一个指针,指向数组的第一个元素。这种关系使得我们可以使用指针来遍历数组,而不需要使用下标。指针的自增操作会根据其指向的数据类型自动调整步长。例如,对于int类型的指针p,执行p++后,p会指向下一个int类型的元素。这种自增特性使得指针遍历数组变得非常高效。通过指针p遍历数组arr时,可以使用*(p+i)访问数组的第i个元素,也可以通过p++逐个访问数组元素。这种方式不仅简洁,而且避免了下标计算,提高了代码的可读性和运行效率。

一维数组:指针自增替代下标示例:定义一个指针变量指向数组的首地址。intarr[10]={2,4,6,8,10,12,14,16,18,20};//p指向数组arr的首地址,即arr[0]的地址,等价于p=&arr[0]int*p=arr;指针变量指向数组元素访问数组元素有两种方式

下标方式:arr[i]或p[i];指针方式

*(p+i)——p是首地址,p+i就是第i个元素的地址,解引用后就是元素值。

一维数组:指针自增替代下标示例:通过指针访问数组中的元素并输出。运行结果:#include<stdio.h>intmain(){//定义一个包含5个整数的数组intarr[5]={10,20,30,40,50};//定义一个指针,指向数组的起始位置int*ptr=arr;//使用指针遍历并输出数组元素for(inti=0;i<5;i++){printf("元素%d:%d\n",i,*(ptr+i));//*(ptr+i)即指针访问数组元素}return0;}可以通过下面代码循环输入5个元素:for(inti=0;i<5;i++){ scanf("%d",&arr[i]);}也可以通过下面代码实现循环输入:int*p;for(p=arr;p<(arr+5);p++) scanf("%d",p);将指针p向后移动一个int类型的数据单元二维数组:行指针步长解析整型二维数组arr[3][5]:intarr[3][5]={{0,1,2,3,4},{5,6,7,8,9},{10,11,12,13,14}};一个包含三行五列的二维数组二维数组各元素的首地址及对应的值二维数组视为多个一维数组:arr被拆解为三个一维数组,即arr[0]、arr[1]和arr[2]每个一维数组中包含五个元素二维数组拆解为一维数组二组数组指针变量

二维数组:行指针步长解析示例:二维数组指针变量的使用。运行结果

#include<stdio.h>intmain(){//定义一个3x3的整型二维数组intarr[3][5]={{0,1,2,3,4},{5,6,7,8,9},{10,11,12,13,14}};//定义一个指针变量,指向二维数组的第一个元素int(*ptr)[5]=arr;//使用指针变量访问二维数组的元素printf("Usingpointertoaccesselements:\n");//遍历二维数组并打印元素for(inti=0;i<3;i++){for(intj=0;j<5;j++){//通过指针访问二维数组的元素printf("%-3d",*(ptr[i]+j));//也可以写作ptr[i][j]}printf("\n");}return0;}04字符串指针变量字符串指针变量字符指针与字符数组的内存边界字符指针与字符数组的区别(1)内存存储方式的区别字符串指针:字符串指针指向的是字符串常量,通常存储在只读数据段。字符数组:字符数组存储的字符串是可修改的。(2)语法不同char*ps="China";可以写成下面形式:char*ps;ps="China";而对数组方式:charstr[]={"China"};不能写成下面形式:charstr[10];str={"China"};指针方式:×字符指针与字符数组的内存边界字符指针与字符数组的区别(3)可变性差异字符数组:你可以修改字符数组中的每个字符。字符串指针:字符串指针指向的字符串常量是不可修改的。charstr[]="Hello";str[0]='h';//修改字符数组中的字符printf("%s\n",str);//输出"hello"";char*str="Hello";str[0]='h';//编译时会警告,运行时会导致错误(4)内存管理字符数组:字符数组的大小是在编译时确定的,因此需要提前知道所需的空间大小。字符串指针:字符串指针可以通过动态内存分配来管理内存大小。(5)使用场景的区别字符数组:适用于知道字符串长度的情况,或者字符串不需要修改的情况(强调长度不变)。字符串指针:适用于需要动态分配字符串的情况,尤其在函数中返回字符串或使用库函数时。

字符串示例:字符串常量。#include<stdio.h>intmain(){ charstr[]="HelloWorld!"; printf("%s\n",str); return0;}字符串的表示形式

字符串示例:字符数组。charstr[]="HelloWorld!";自动在数组的末尾添加了一个'\0'字符示例:字符指针。char*str="Hello,World!";str指向字符串"Hello,World!"的第一个字符'H'命令行参数:argv指针数组拆解main函数的参数main函数可以接受两个参数:argc和argv。argv数组的结构argv数组的第一个元素argv[0]通常指向程序的文件名,其余元素指向用户输入的参数。通过遍历argv数组,程序可以逐个处理这些参数,实现灵活的命令行交互。intmain(intargc,char*argv[])命令行参数的数量指向字符串的指针数组命令:C:\>MainArgsCC++Pythonargv数组argv[1]argv[2]argv[3]

命令行参数:argv指针数组拆解示例:main函数的参数。运行结果:#include<stdio.h>intmain(intargc,char*argv[]){ while(argc-->1){ printf("%s\n",*++argv); }}后置自减判断表达式本质:先判断,后自减(argc-->1等价于两步操作,顺序不可颠倒)第一步:判断argc>1是否成立(用argc当前的原值做判断);第二步:无论判断结果如何,argc的值都减1(后置自减--的特性:先使用变量原值,再修改变量)。05指向指针的指针指向指针的指针二级指针:指向钥匙的钥匙二级指针的定义二级指针是指向指针的指针,它存储的是指针变量的地址。例如,'int**pp;'定义了一个二级指针pp,它可以用来存储一级指针p的地址。这种多级指针结构在某些复杂的数据结构中非常有用。二级指针的应用通过二级指针,我们可以在函数中修改指针变量本身的值。例如,在动态内存分配中,二级指针可以用来接收分配的内存地址,从而实现灵活的内存管理。

二级指针:指向钥匙的钥匙示例运行结果inti=1;int*p=&i;int**pp=&p;指向i的指针变量指向p的指针变量第一把钥匙第二把钥匙房间

二级指针:指向钥匙的钥匙示例:指向指针的指针。运行结果:#include<stdio.h>intmain(){//步骤一:邮件内容intemailContent=100; //步骤二:邮箱(指针,指向邮件内容)int*mailbox=&emailContent; //步骤三:邮箱的指针(指向邮箱的指针,二级指针)int**pointerToMailbox=&mailbox;//打印邮件内容printf("邮件内容(通过一级指针访问):%d\n",*mailbox);printf("邮件内容(通过二级指针访问):%d\n",**pointerToMailbox);return0;}06指向函数的指针指向函数的指针

函数指针:把工厂门牌存进变量工厂(函数)门牌号码纸条(函数指针)门牌号码第一步第二步定义指向函数的指针格式:返回值类型(*指针变量名)(参数类型列表);int(*pf)(int,int);intadd(intx,inty)pf=add;(*pf)(3,5)或pf(3,5)等价于add(3,5),结果都是8函数的地址赋值给pf示例:

指向函数的指针函数指针的概念函数指针是指向函数的指针,它存储的是函数的入口地址。通过函数指针,我们可以在运行时动态地调用不同的函数,实现灵活的程序控制。函数指针的声明与使用声明函数指针时,需要指定函数的返回类型、参数类型等信息。例如,'int(*pf)(int,int);'定义了一个指向返回int类型、接收两个int参数的函数的指针。通过函数指针,我们可以像调用普通函数一样调用它所指向的函数。函数指针的应用场景函数指针在实现回调函数、策略模式等设计模式时非常有用。例如,通过函数指针数组,我们可以根据用户的选择动态调用不同的运算函数,实现一个灵活的计算器程序。指向函数的指针函数函数入口地址功能add0x00401000实现两个整数相加pf0x00401000指向

add函数的指针变量,存储add函数的入口地址​

指向函数的指针示例:实现三个整数由大到小排序(直接调用函数)voidsort_desc(int*a,int*b,int*c){//使用条件判断实现由大到小排序if(*a<*b){inttemp=*a;*a=*b;*b=temp;}if(*a<*c){inttemp=*a;*a=*c;*c=temp;}if(*b<*c){inttemp=*b;*b=*c;*c=temp;}}运行结果

指向函数的指针voidsort_desc_pointer(int*a,int*b,int*c){//使用条件判断实现由大到小排序if(*a<*b){inttemp=*a;*a=*b;*b=temp;}if(*a<*c){inttemp=*a;*a=*c;*c=temp;}if(*b<*c){inttemp=*b;*b=*c;*c=temp;}}intmain(){inta,b,c;int*ptr_a=&a,*ptr_b=&b,*ptr_c=&c;//输入三个整数printf("请输入三个整数:");scanf("%d%d%d",&a,&b,&c);//第一种方式:直接调用排序函数sort_desc(ptr_a,ptr_b,ptr_c);printf("排序后的结果(直接调用函数):%d%d%d\n",a,b,c);//重新输入三个整数进行排序printf("重新输入三个整数:");scanf("%d%d%d",&a,&b,&c);//第二种方式:使用指向函数的指针实现排序void(*sort_ptr)(int*,int*,int*)=sort_desc_pointer;sort_ptr(ptr_a,ptr_b,ptr_c);//使用函数指针调用排序函数printf("排序后的结果(函数指针调用):%d%d%d\n",a,b,c);return0;}示例:实现三个整数由大到小排序(通过指向函数的指针)。07指针综合编程案例

指针综合编程案例案例一:使用指针访问和修改变量。运行结果:#include<stdio.h>intmain(){intnum=10;int*p=#//指针p指向numprintf("变量num的初始值:%d\n",num);printf("通过指针访问num的值:%d\n",*p);printf("变量num的地址:%p\n",&num);printf("指针p存储的地址:%p\n",p);//通过指针修改num的值*p=20;printf("通过指针修改后,num的值:%d\n",num);return0;}

指针综合编程案例案例二:使用指针遍历一维数组。运行结果#include<stdio.h>intmain(){intarr[]={1,2,3,4,5};intlen=sizeof(arr)/sizeof(arr[0]);//计算数组长度int*p=arr;//指针p指向数组首元素(等价于&arr[0])intsum=0;printf("数组元素:");for(inti=0;i<len;i++){printf("%d",*(p+i));//通过指针偏移访问元素,等价于p[i]sum+=*(p+i);}printf("\n数组元素的和:%d\n",sum);//另一种遍历方式:指针自增printf("用指针自增遍历:");p=arr;//重置指针到首元素while(p<arr+len){printf("%d",*p);p++;//指针移动到下一个元素}printf("\n");return0;}

指针综合编程案例案例三:字符串指针的应用——字符串复制与比较。#include<stdio.h>//字符串复制:将src复制到dest(假设dest足够大)voidstrCopy(char*dest,constchar*src){while(*src!='\0'){*dest=*src;//复制当前字符dest++;//移动目标指针src++;//移动源指针}*dest='\0';//复制结束标志}//字符串比较:相等返回0,s1>s2返回1,s1<s2返回-1intstrCompare(constchar*s1,constchar*s2){while(*s1!='\0'&&*s2!='\0'){if(*s1>*s2)return1;if(*s1<*s2)return-1;s1++;//移动指针继续比较s2++;}//处理长度不同的情况if(*s1=='\0'&&*s2=='\0')return0;return(*s1!='\0')?1:-1;}intmain(){charstr1[]="hello";charstr2[20];char*str3="hello";char*str4="world";//复制字符串strCopy(str2,str1);printf("复制后str2:%s\n",str2);//比较字符串

//相等printf("str1与str3比较:%d\n",strCompare(str1,str3));//str1<str4printf("str1与str4比较:%d\n",strCompare(str1,str4));return0;}运行结果

指针综合编程案例案例四:指向指针的指针(二级指针)处理字符串数组。#include<stdio.h>#include<string.h>intmain(){//字符串数组:每个元素是char*类型char*strArr[]={"apple","banana","cherry","date","elderberry"};intlen=sizeof(strArr)/sizeof(strArr[0]);//数组长度char**p=strArr;//二级指针p指向字符串数组首元素intmaxLen=0;char*longestStr;printf("字符串数组元素:\n");

for(inti=0;i<len;i++){printf("%s\n",*(p+i));//二级指针访问第i个字符串//统计最长字符串intcurrentLen=strlen(*(p+i));if(currentLen>maxLen){maxLen=currentLen;longestStr=*(p+i);}}printf("最长字符串是:%s,长度:%d\n",longestStr,maxLen);return0;}运行结果:

指针综合编程案例案例五:指针作为函数参数实现数组排序。#include<stdio.h>//冒泡排序:通过指针操作数组voidbubbleSort(int*arr,intlen){for(inti=0;i<len-1;i++){for(intj=0;j<len-1-i;j++){//通过指针访问相邻元素并交换if(*(arr+j)>*(arr+j+1)){inttemp=*(arr+j);*(arr+j)=*(arr+j+1);*(arr+j+1)=temp;}}}}intmain(){intarr[]={5,2,8,1,9,3};intlen=sizeof(arr)/sizeof(arr[0]);int*p=arr;printf("排序前数组:");for(inti=0;i<len;i++){printf("%d",*(p+i));

温馨提示

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

评论

0/150

提交评论