C语言程序设计基础(微课版) 课件汇 张宁 第7-12章 函数-文件_第1页
C语言程序设计基础(微课版) 课件汇 张宁 第7-12章 函数-文件_第2页
C语言程序设计基础(微课版) 课件汇 张宁 第7-12章 函数-文件_第3页
C语言程序设计基础(微课版) 课件汇 张宁 第7-12章 函数-文件_第4页
C语言程序设计基础(微课版) 课件汇 张宁 第7-12章 函数-文件_第5页
已阅读5页,还剩201页未读 继续免费阅读

下载本文档

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

文档简介

C语言程序设计

第7章函数main(){

准备东西;

打车(去公园);

玩;

点菜(鱼香肉丝);

吃;

}打车(去哪){

油门;

转弯;

刹车;}去公园玩的程序点菜(吃什么){

if(葱没了)打车(去买葱);

洗菜;

切菜;

炒;

return

做好的菜;}暂停暂停暂停函数的调用调用

main函数其他函数

调用

其他函数

其他函数调用

其他函数

main函数调用

主调函数

被调函数

C源程序由函数组成:一个main函数若干其他函数函数概述除main函数外,其他函数都不能独立执行;其他函数只有在被调用时才执行,不调用不执行;同一函数可被反复多次调用;调用返回:函数结束后,谁调用的,返回谁,不一定都返回main函数。函数概述(2)参数:

0~多个 有的函数有1~多个参数,有的函数没有参数返回值:0~1个 有的函数有1个返回值,有的函数没有返回值sin(30)0.5函数名参数返回值(实际应使用弧度)系统函数又称标准函数或库函数,如sqrt()、fabs()、rand()等;需要包含对应的头文件才能调用:#include<xxx>我们自己编写的函数,需要定义后才能调用;定义就是由我们自己把函数“这段话”在程序中写出来自定义函数函数分两种:函数的定义和调用函数的定义函数返回值类型

函数名(参数类型1

参数1,参数类型2

参数2,...){

语句;

语句;

语句;}intmax

(inta,intb){ if(a>b)

returna;

else

returnb;}voidPrintStar(){printf("*****\n");}intmax(inta,b){...}每个参数都必须有类型main(){...

intmax(inta,intb) { … } …}函数不能嵌套定义函数体()

必不可少参数无;不写返回值类型int表示无返回值时应写void函数定义头部:函数名前写void

的是无返回值的函数;函数名前写其他类型说明(如int、float、double、char等)或不写的是有返回值的函数。函数名(参数1,参数2,…);函数的调用调用,就是使用。要调用函数,直接喊名()对有参数的函数还要同时给出参数,即:函数名(实参1,实参2,…);形式参数(简称形参): 在函数定义头部中的参数,在函数未被调用时,此参数无具体值;实际参数(简称实参): 调用函数时给出的具体参数,是有具体值的。打车(去哪){

油门;

转弯;

刹车;}点菜(吃什么){ if(葱没了)… 洗菜;

…;}intmain(){ …;

打车(去公园);

点菜(鱼香肉丝);}实参实参形参形参形参必须是一个变量实参可以是一个表达式sin(30*3.14/180)

()万不可省!实参

main的空间函数调用的过程独立空间,激活形参。当做变量,单向值传。变量其间,同名不乱。函数结束,全部完蛋。#include<stdio.h>voidfun(intp){

intd=2; p=d++;printf("%d",p);}main(){

inta=1; fun(a); printf("%d\n",a);}a:1fun的空间形参p:1d:22322暂停21实参#include<stdio.h>voidswap(intx,inty){ inttemp; printf("swap中交换前:x=%d

y=%d",x,y); temp=x;x=y;y=temp; printf("swap中交换后:x=%d

y=%d",x,y);}main(){ inta=15,b=18; printf("main中调用swap前:a=%db=%d\n",a,b); swap(a,b); printf("main中调用swap后:a=%db=%d\n",a,b);}实参到形参的单向值传递main的空间a:15b:18swap的空间main中调用swap前:a=15b=18x:

y:

1518temp:?main中调用swap前:a=15b=18swap中交换前:x=15y=18151815main中调用swap前:a=15b=18swap中交换前:x=15y=18swap中交换后:x=18y=15main中调用swap前:a=15b=18swap中交换前:x=15y=18swap中交换后:x=18y=15main中调用swap后:a=15b=18实参形参单向传递12sin函数返回了算好的0.5给main函数。函数的返回值函数在执行之后,可以返回一个值给“调用它的函数”。return

表达式;这是通过return语句实现的:doublesin(求几的正弦){ ……; ……; ……; ……;

return0.5;}main(){ …… t=sin(30*3.14/180);}0.5main(){ …… printf("%f",sqrt(4));}2doublesqrt(求几的平方根){ ……; ……; ……; ……;

return2;}美食型点菜(吃什么){

if(葱没了)打车(去买葱);

洗菜;

切菜;

炒;

return

做好的菜;}main(){

点菜(鱼香肉丝);

吃;}sqrt函数返回了算好的2给main函数。“点菜”函数返回了做好的鱼香肉丝给main函数。return有两个作用①将表达式的值作为函数值返回给调用它的主调函数;

②执行return后,函数立即结束(本函数后面的语句也都不执行了),

返回到主调函数,继续运行主调函数中刚才调用函数语句的下一语句。return表达式;说的对!但return也有层次性,仅能返回调用它的函数——谁调用它返回谁,不能越级返回,不一定都返到main函数哦。return类似break,但比break强大!嵌套循环内的break只能跳出一层;而若return在嵌套循环内,有多少层都能跳出,因为整个函数都跳出啦!#include<stdio.h>intmax(inta,intb){

if(a>b)returna;

else

returnb;}voidPrintStar(){ printf("*****\n");}main(){ intx,y,z; PrintStar(); printf("输入2数:\n"); scanf("%d%d",&x,&y); z=max(x,y); printf("%d较大\n",z); PrintStar();}main的空间x:?y:?z:?PrintStar的空间*****

*****输入2数:_

*****输入2数:1020

max的空间a:10b:2010202020*****输入2数:102020较大

PrintStar的空间*****输入2数:102020较大*****临时空间可有多个return语句,但只能有一个被执行

#include<stdio.h>intmax(inta,intb){

if(a>b)returna;

else

returnb;}voidPrintStar(){ printf("*****\n");}main(){ intx,y,z; PrintStar(); printf("输入2数:\n"); scanf("%d%d",&x,&y); z=max(x,y); printf("%d较大\n",z); PrintStar();}printf才会输出到屏幕z=max(x,y);

函数返回值20,z被赋值20,但屏幕上不会有任何输出如执行:printf("%d",max(x,y));直接输出20

20

截然不同

函数的返回值

程序的输出结果

(屏幕输出结果)max2个数大数sqrt1个数平方根sin

弧度正弦值函数的作用:黑匣子罐头厂函数的调用函数有两种调用方式:①语句

②表达式中对无返回值的函数(void)只能用第①种方式调用;对有返回值的函数(非void或省略)

2种调用方式均可。intmax

(inta,intb){ if(a>b)

returna;

else

returnb;}voidPrintStar(){printf("*****\n");}此函数有返回值

此函数无返回值

z=max(5,3)*2;//z=10;b=sqrt(4)*2;//b=4;printf("%d",max(5,3));

//输出5z=PrintStar()*2;printf("%d",PrintStar());使用函数的好处

主函数

(main函数)

函数1

函数3

函数4函数2

命令命令命令命令协调相互调用程序功能被细分为若干函数,每个函数负责一个小功能。main()是“节目主持人”,负责调度、指挥各函数工作。return语句

有return语句无return语句有返回值的函数(名前非void)

返回表达式的值,函数结束

返回系统默认值,函数结束函数中语句执行结束后(执行到最后的}),返回系统默认值,函数结束无返回值的函数(名前有void)

函数结束(无返回值)函数中语句执行结束后(执行到最后的}),函数结束(无返回值)return表达式;return;return;return表达式;无论函数有/无返回值,均可有/无

return语句。return语句的两种用法:

return

表达式;

return; 无返回值的函数只能用后者的用法。

max

(inta,intb){

if(a>b) …PrintStar(){……voidint必须返回一个值永远无法返回值#include<stdio.h>voidfun(intp){

intd=0; d=d+p; printf("%d",p);}main(){

inta=1; fun(a); printf(%d\n",a);}无返回值的函数使用return语句

if(d>0)return;main的空间a:1fun的空间p:

1d:01此语句未执行1无返回值的函数使用return语句1#include<stdio.h>voidfun(intp){

intd=0; d=d+p; printf("%d",p);}main(){

inta=1; fun(a); printf(%d\n",a);}main的空间a:1fun的空间p:

1d:0111变量其间,同名不乱(1:函数内变量同名)1#include<stdio.h>voidfun(intp){

int

a=0;

a=a+p; printf("%d",p);}main(){

inta=1; fun(a); printf(%d\n",a);}

if(a>0)return;此语句未执行main的空间a:1fun的空间p:

1a:01变量其间,同名不乱(2:形参实参同名)1#include<stdio.h>voidfun(inta){

intd=0; d=d+a; printf("%d",a);}main(){

inta=1; fun(a); printf(%d\n",a);}

if(d>0)return;此语句未执行main的空间a:1fun的空间a:

1d:01形参也是变量也可与其他函数的变量同名函数的声明#include<stdio.h>voidfun(intp){

intd=0; d=d+p;

if(d>0)return; printf("%d",p);}main(){

inta=1; fun(a); printf("%d\n",a);}函数的声明#include<stdio.h>

main(){

inta=1; fun(a); printf("%d\n",a);}voidfun(intp){

intd=0; d=d+p;

if(d>0)return; printf("%d",p);}?fun

是什么?程序有错!fun是我定义的函数啊,为什么不往下看?这儿已经出错,出错了我就不往下看了!刚才的程序定义fun函数,了解!fun是你定义的函数,我认得,正确!顺序编译顺序编译笨死了!函数的声明(2)#include<stdio.h>main(){

inta=1; fun(a); printf("%d\n",a);}voidfun(intp){

intd=0; d=d+p;

if(d>0)return; printf("%d",p);}voidfun(int)喂!我有个函数fun,将下面定义,听到了吗?听到了!fun?刚才有人喊过,这是下面会定义的函数,不是错误。果然是在这里定义的嘛!程序没错,可以运行喽!p;顺序编译#include<stdio.h>main(){

inta=1; fun(a); printf("%d\n",a);}voidfun(intp){

intd=0; d=d+p;

if(d>0)return; printf("%d",p);}voidfun(int)函数的声明(2);函数的声明函数的声明是

函数定义头部+;声明被调函数,目的就是“告诉”计算机该函数的“样式”(也称函数的原型),使计算机今后可以识别该函数。可省略形参名,但只可省略形参名,其他均不可省!最后的;

不可省!(可以省略形参名,或随意另起名);pxam声明时的形参名既可省略,也可随意另起名函数声明的位置在函数外声明:使得位于声明位置之后的所有函数内都可以调用被声明的函数。在函数内声明:使得仅在本函数内可以调用被声明的函数;main(){

floatadd(floatx,floaty); …… add(1,2); //能调用add函数}intfun(){ …… add(3,4); //未声明add,不能调用add}floatadd(floatx,floaty){ ……}doublefun2(intm){

add(5,6); //在定义之后,也能调用}函数的声明调用调用调用能调用add函数的区域函数的定义

函数的递归讲故事...从前有座山,山里有座庙,庙里有个老和尚讲故事,故事是什么呢?“从前有座山,山里有座庙,庙里有个老和尚讲故事,故事是什么呢?”‘从前有座山,山里有座庙,庙里有个老和尚讲故事,故事是什么呢?’……函数的递归调用调用函数1

函数1调用函数1

函数2

函数1

调用函数直接或间接地自己调用自己,称为递归

intf(intx){ ……f(y);……}递归的分析方法与嵌套调用类似。尽管每次调用的都是自身(同一函数),但要把每次所调用的函数都看作是不同的函数,这些函数都具有相同的参数、返回值和语句。直接调用自己间接调用自己求阶乘n!=n*(n-1)*(n-2)*…*3*2*1(1!=1,0!=1)n!=n*(n-1)!

我要算4!赵钱孙李4!=4*3!钱,你去算3!,算好后告诉我哦!①要是有人问我1或0的阶乘,我就直接告诉他1。②要不我就再找个人,让他去算(n-1)的阶乘,我再乘n就行了,我才不一个个乘哩,嘿嘿。3!=3*2!孙,你去算2!,算好后告诉我哦!2!=2*1!李,你去算1!,算好后告诉我哦!1!就是1啊。12*1=223*2=6244*6=246int

ff(intn){ intf=0; if(n==0||n==1) f=1;

else returnf;}求阶乘的人(要算n的阶乘?){ if(问1或0的阶乘)

结果=1; else

{

再找个人求(n-1)的阶乘;

结果=n*他算的(n-1)的阶乘; } return

结果;}ffnn!的结果 f=n

*

;ff(n-1)int

ff(intn){ intf=0; if(n==0||n==1) f=1;

else returnf;} f=n

*

;ff(n-1)求阶乘

#include<stdio.h>intff(intn);main(){ intn;inty; scanf("%d",&n);y=ff(n); printf("%d!=%d",n,y);}main的空间ff的空间n:?_44n:4f:0intff(intn){

intf=0;

if(n==0||n==1) f=1;

else f=n*ff(n-1);

returnf;}ff的空间n:3f:0n-1ff的空间n-1n:2f:0ff的空间n-1n:1f:02262424intff(intn){

intf=0;

if(n==0||n==1) f=1;

else f=n*ff(n-1);

returnf;}intff(intn){

intf=0;

if(n==0||n==1) f=1;

else f=n*ff(n-1);

returnf;}44!=241递归程序,结构简练,可读性强。但执行时其时间和空间上的开销都比较大。为防止自调用无休止地进行,在函数内必须设置调用终止的条件,否则程序将无法终止,被称为死递归。1y:?24递归练习

#include<stdio.h>int

function(intx);intmain(){ printf("%d\n",function(7));

return0;}int

function(intx){

ints;

if(x==1||x==2)return2; s=x*function(x-2);

returns;}main的空间function的空间x:7s:?function的空间x:5s:?function的空间x:3s:?function的空间x:1s:?2s=x*function(x-2);s=x*function(x-2);663030210210210C语言程序设计

天津大学副教授张宁第8章指针生活中的编号地址和指针的基本概念●●●0124G-1地址——编号一个字节34G内存

4×1024×1024×1024个字节1000100110021003a2000200120022003binta=1;doubleb=8.2;a:1

b:

8.2

有了变量的地址,存取变量就可以通过两种方式:实际地址:2031132、3209356

(十六进制:0x001efe1c、0x0030f88c)1)通过变量名2)通过变量的地址数学系男生宿舍,也可以说是305宿舍。10002000变量a占据编号1000~1003的4个字节——变量a的地址为1000

变量b占据编号2000~2007的8个字节——变量b的地址为2000

8.220042005200620071地址和指针的基本概念1000,2000

1,8.2

变量的值(内容)变量的地址区别地址不变内容可变●●●0124G-1一个字节31000100110021003a2000200120022003b8.2200420052006200714G内存

4×1024×1024×1024个字节地址——编号a:1

b:

8.210002000有了变量的地址,存取变量就可以通过两种方式:1)通过变量名2)通过变量的地址inta=1;doubleb=8.2;数学系男生宿舍,也可以说是305宿舍。inta=1;doubleb=8.2;a:1

b:8.2

10002000保存指针变量特殊的专用变量int*p;p=&a;p:

[]

*是标志:定义的是指针变量, 不是普通变量;变量名叫p,不是叫*p。变量的类型是int*,不是int

指针变量一律占4字节

指针变量简称指针

1000

3000只能保存数据不能保存地址Hi,这是指针变量,存地址的!不是存数据的普通变量哦!只能保存地址不能保存数据●●●3000300130023003p[1000]4G-14G内存

4×1024×1024×1024个字节01231000100110021003a2000200120022003b8.220042005200620071定义指针变量2000200120022003b8.22004200520062007p=&a;double*q;inta=1;doubleb=8.2;int*p;a:1

b:

8.2

10002000p:

[]3000指针变量的基类型指针变量p指向了变量a

p是指向变量a的指针变量

p是指向变量a的指针

基类型基类型:指针变量所指向的变量的类型

p=&b;q:[]4000p不是int型而是int*型q=&a;q=&b;

2000

●●●4000400140024003q[2000]q不是double型,更不是int型而是double*型4G内存

4×1024×1024×1024个字节3000300130023003p[1000]2000200120022003b8.220042005200620074G-11000

p:

[]a:1

b:

8.2

100020003000q:[]4000

2000

指针变量基类型里的“大小王”基类型void*void*r;r:[]5000r是void*型r=&a;r=&b;

1000

[2000]

●●●void类型的指针变量4000400140024003q[2000]3000300130023003p[1000]2000200120022003b8.220042005200620075000500150025003r4G内存

4×1024×1024×1024个字节4G-1inta=1;doubleb=8.2;int*p;p=&b;double*q;q=&a;q=&b;p=&a;1000

[1000][2000]指针变量的赋值为指针变量赋值,有三种方法①赋值语句的方法p=&a;intb=2;int*q;p:[]int*p;inta=1;a:1

10002000指针变量被赋值前,其值为随机数——随机地址。若此时访问或修改它所指向的空间的内容,会造成意外后果,甚至导致系统崩溃!变量名叫p不是叫*p

1000

*p=&a;4000q:[]③允许指针变量之间赋值,但两个指针变量必须基类型相同q=p;int*r;r=q;double*s;s=p;b:

2

3000?

账户密码?Windows系统重要空间?其它程序变量?②定义指针变量时初始化(定义时赋初值)intb=2;int*q=&b;[1000]r:[?]5000[1000]s:[?]6000s占4字节

3000

指针变量的赋值(2)不允许把一个“数”当地址赋给指针变量

int*p; p=1000;p:[]2000a:1

1000特殊地,允许:

p=0;或p=NULL;指针变量值为0(地址值为0)时,表示什么也不指向——空指针01230

?地址为0开始的一段内存非常重要!p:[?]2000p:[0]2000指针变量未赋值:指向随机(不确定)指针变量值为0(确定):不指向任何内容v.s(必须用&

取变量的地址,如p=&a;)NULL(必须全部大写)是系统定义的宏#define

NULL0指针运算两兄弟——两个运算符(2)*

指针运算符(间接访问运算符)

——获取或改写以p为地址的内存的内容: *p*

不是获得或改写指针变量本身的值,而是获得或改写它所指向单元的值。&是运算符*是运算符(1)&

取地址运算符

——获取变量的地址

&变量名

&可用于普通变量,也可用于指针变量,后者取指针变量本身的地址。都不是变量名的一部分!我是*快递员从哪取货,或您要送哪?地址给我,马上办到!*

运算只能用于指针变量,不能用于普通变量(如*a错误)。int

*p;与定义指针变量时的*不同:*相同符号不同含义&

和*

互为逆运算:如果p=&a;p

&a*p

*&a

a&*p

p&*&*&*p

p*&*&*&*p

ainta=1,b=2;int*p=&a;*p=&a;*p=b;p=a;p=&b;*p=3;练习3000p:[1000]a:

11000b:

22000不是说*p=&a而是p=&a变量类型是int*

不是

int[2000]p指此处,此处只能存地址,不能存数据。故p=a;错误23double*px,*py=0,x=0,y;*px=0;px=0;y=py;px:[?]4000py:[0]5000x:

0.0

6000y:

?

7000[0]不是*py=0,还是py=0为p赋值,这里叫p不叫*p此处只能存数据,不能存地址未知空间被意外修改*p是指此处此处只能存数据,不能存地址故*p=&a;错误总结C语言中的*我是*快递员从哪取货,或您要送哪?地址给我,马上办到!①定义指针变量,*是一个标志,无运算的含义,如:

int

*p;②取地址指向的内容,或改写指向的内容,*是指针运算符,如*p③算术表达式中*是乘法运算符,如:a*b④指针变量做函数形参、函数返回值类型同①

,如:int*fun(int

*p,int

*q){…}有int等类型说明符*

后有一个地址量,*前无内容*

前后各有一个量Hi,这是指针变量,存地址的!不是存数据的普通变量哦!位于函数的形参表中;位于函数返回值类型后*相同符号不同含义总结C语言中的指针变量指针变量保存地址的专用变量。

定义时必须有*,如int*p;使用时有*、无*的情况均有*p

表示取地址指向的内容或改写内容

p

表示p中保存的地址本身

a:1

1000p:[1000]2000&p

表示变量p的地址有int等类型说明符即为定义

无int等类型说明符即为使用

程序例输入a和b两个整数,按先大后小的顺序输出a和b。#include<stdio.h>main(){

int*p1,*p2,*p,a,b; p1=&a;p2=&b; scanf("%d%d",&a,&b);

if(a<b) printf("\na=%d,b=%d\n", a,b); printf("max=%d,min=%d\n", *p1,*p2);}p1:[]3000p2:[]4000b:

2000a:

1000p:[

]5000_

2030

2030a=20,b=302030a=20,b=30max=30,min=20并未交换a、b本身,而是交换了指向,使p1指向较大数[2000]

1000

2000

20301000

[1000]

{p=p1;p1=p2;p2=p;}{p=p1;p1=p2;p2=p;}数组的指针指向一维数组元素的指针a:a[0]a[1]a[2]a[3]a[4]12345inta[5]={1,2,3,4,5};int*p;p=&a[1];p=&a[0];10001004100810121016p:[?]2000float*q;q=&a[1];[1004][1000]q:[?]3000q只能保存float型变量的地址,而a[1]为int型(设在VisualC++2010中)10001004100810121016指针变量的运算——加减整数a:a[0]a[1]a[2]a[3]a[4]12345p:[?]2000[1004][1000]p=p+1;

[1004]p+=2;

p--;

指向向前或向后移动n个单位(n个元素)p±n=p中的地址编号±(每元素字节数×n)指针变量加上或减去一个整数n:[1012][1008]+1下一站(该运算应只对指向数组的指针变量进行,否则毫无意义)京沪高铁(设在VisualC++2010中)inta[5]={1,2,3,4,5};int*p;p=&a[1];p=&a[0];指针变量的运算——加减整数(2)每个char型变量占1字节,对基类型为char的指针变量±n,恰好是地址±n

c:c[0]c[1]c[2]c[3]'a''b''c''d'charc[4]={'a','b','c','d'};char*p=&c[2];p:[1002]20001000100110021003[1003]++p;

p-=2;

[1001]void类型的指针不能做±n的运算(也不能做++、--的运算)指针变量的运算——指针变量相减两指针变量的加法、乘法、除法运算是没有意义的。例如,p1+p2、p1*p2、p1/p2均无意义。结果为两地址间相差的单位个数(元素个数),不一定是相差的字节数:

p1-p2=(p1中的地址编号-p2中的地址编号)/每元素字节数两指针变量相减:(该运算应只在指向同一数组的元素的两个指针变量之间进行)x:x[0]x[1]x[2]x[3]x[4]x[5]doublex[6];double*p1=&x[1],*p2=&x[5];printf("%d",p2-p1);p1:[1008]2000p2:[1040]30001000100810161024103241040=(1040-1008)/8京沪高铁相差4站指针变量的运算——关系运算p1==p2 表示p1和p2指向数组的同一元素;

p1>p2 表示p1所指元素位于p2所指元素之后;

p1<p2 表示p1所指元素位于p2所指元素之前。两指针变量之间可以进行大小的比较,即是比较两指针变量中所保存的地址编号的大小。两指针变量间的关系运算:(该运算一般只对指向同一数组的元素的两个指针变量进行,表示它们所指元素的先后位置)p==0或p==NULL

表示p是空指针,不指向任何位置;p!=0或p!=NULL表示p不是空指针。指针变量还可以与0比较:逆置数组元素逆置数组a中7个元素的值。数组a中7个元素的原始排列为1、2、3、4、5、6、7,逆置后使其排列为7、6、5、4、3、2、1。a:a[0]a[1]a[2]a[3]a[4]a[5]a[6]123456710001004100810121016(设在VisualC++2010中)10201024#include<stdio.h>#define

N7main(){ inta[N]={1,2,3,4,5,6,7},i,t;

int*p=&a[0],*q=&a[N-1];

while(p<q) { t=*p;*p=*q;*q=t; p++;q--; }

for(i=0;i<N;i++)//输出结果

printf("%d",a[i]); printf("\n");}p:[1000]2000q:[1024]300071p++;q--;[1004][1020]62[1008][1016]53[1012]7654321

数组元素的地址转换为元素下标a:a[0]a[1]a[2]a[3]a[4]12345inta[5]={1,2,3,4,5};int*p,*q;q=&a[0];//0号元素地址

p=&a[2];10001004100810121016p:[1008]2000q:[1000

]3000(设在VisualC++2010中)设指针变量p指向了数组a的某个元素(保存了某个元素的地址),如何通过指针变量p,得到它所指元素的下标呢?p-数组0号元素的地址p-数组名

(数组名就是0号元素的地址)

p-q则得2,即p所指元素a[2]的下标p-a则得2,即p所指元素a[2]的下标一维数组的指针a:a[0]a[1]a[2]a[3]a[4]1234510001004100810121016inta[5]={1,2,3,4,5};

一维数组名a

①是数组名(一维数组)②是一个假想的指针变量③a值为数组起始地址,也是元素a[0]的地址④指针变量a本身的地址(a所在“内存”位置)也是数组的起始地址,也是元素a[0]的地址⑤a值不可被改变,是常量

a:[1000]1000两个重要公式——语法糖a:a[0]a[1]a[2]a[3]a[4]1234510001004100810121016a+0&a[0][1000]

a+1&a[1][1004]

a+2&a[2][1008]

a+i&a[i]*(a+i)*&a[i]a[i]*(a+i)a[i]编译时编译系统将a[i]全部变为*(a+i)。a[i]这种写法只不过是C语言为便于我们理解而特意设计的——语法糖我只认得*(a+i),不知道a[i]是什么东东!

a[2]a[0]a[4]a[3]a[1]语法糖a:[1000]1000inta[5]={1,2,3,4,5};两个重要公式(2)x为数组名、或指针变量,均适用(但对普通变量不适用)C语言规定:指针变量也可写为数组的形式如有int

*p;可写为:p[0]p[1]p[2]当x是数组名时,x本身也是指针变量(假想的),因此无论x是数组名还是指针变量实际是。*(p+i)p[i]p+i&p[i]*(a+i)a[i]a+i&a[i]*(x+i)x[i]x+i&x[i]一回事指针变量与一维数组名的统一inta[5];p=&a[0];inta[5];int*p;p=a;p:[1000]2000p[0]*(p+0)

*[1000]

a[0]*p

p[1]*(p+1)

*[1004]

a[1]p[i]a[i]*(p+i)*(a+i)pap的值(地址)可被修改,a的值(地址)不能被修改p是变量,a是假想的“指针变量”(是常量)p=&a[1];p++;p=0;p=NULL;p=a;a=&a[1];a++;a=0;a=NULL;a=p;a:a[0]a[1]a[2]a[3]a[4]1234510001004100810121016a:[1000]1000指针变量与一维数组名的统一数组名指针变量指针变量与数组名互换使用的前提①指针变量保存数组起始地址;②数组名(假想的指针变量)不能被修改值数组首地址&a[0]ap数组元素

a[i]p[i]*(a+i)*(p+i)指针访问效率更高inta[5];p=&a[0];inta[5];int*p;p=a;p:[1000]2000a:a[0]a[1]a[2]a[3]a[4]1234510001004100810121016a:[1000]1000练习(1)设有定义doublea[10],*s=a;以下能够代表数组元素a[3]的是A)(*s)[3]B)*(s+3)C)*s[3]D)*s+3a:a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]a:[1000]100010001008101610241072s:[1000]200011[3]s[3]a[3]sa(注意a的值不可被改变)*a[3]4*41+3

*[1024]方法2练习(2)设有定义doublea[10],*s=&a[2];能够代表数组元素a[3]的是___________a:a[0]a[1]a[2]a[3]a[4]a[5]a[6]a[7]a[8]a[9]a:[1000]100010001008101610241072s:[1016]2000sa(s不是a的起始地址)*(s+1)

或s[1]

s+1:[1024]*(s+3)

或s[3]

代表的是a[5]s+3:[1040]10321040*(x+i)x[i]x+i&x[i]以不变应万变x为指针变量或数组名s[]与a[]的下标差2语法糖公式永远成立求字节运算符sizeof(类型或表达式)求占用多少字节

(结果为整数)sizeof是关键字是运算符,不是函数!sizeof用于数组名sizeof(指针变量):得4sizeof(数组名):获得数组所有元素共占字节数#include<stdio.h>intmain(){

inta[5]={1,2,3},i; //最后2个元素自动补初值0

int*p=a;

intlen=sizeof(a)/sizeof(int);

//len=5,即数组元素个数

printf("%d",len);

//输出5

printf("%d\n",sizeof(p));

//输出4

//依次输出数组每元素值

for(i=0;i<len;i++)

//i<len即i<5

printf("%d",a[i]);

return0;}54123002044指针运算的优先级#include<stdio.h>main(){ inta[]={1,3,5},*p=a+1; printf("%d,",*p++); printf("%d\n",(*p)++);}a:a[0]a[1]a[2]135100010041008p:[1004]2000a:[1000]1000*、&

的优先级与++、--相同,都非常高,仅次于()与++、--同级运算时,从右至左结合3,[1008]*(p++)a[2]++3,5

6[1004]二维数组的指针**[[写字台抽屉]]

“二级”指针变量a:11000p:

[1000]2000q:

[[2000]]3000软件学院B310

上课地点在: 软件学院B310上课地点的地址在: 写字台抽屉

上课地点在: 软件学院B310

地址的地址地址一级指针变量二级指针变量指针变量 *[[写字台抽屉]]

[软件学院B310]

*[软件学院B310]

上课教室

*q

p**q

*pa**[[2000]]

*[1000]1*[[2000]]

[1000]二维数组的地址intb[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

123456789101112[1000]1[1004]2[1008]3[1012]4[1016]5[1020]6[1024]7[1028]8[1032]9[1036]10[1040]11[1044]121000b[0][1000]1[1004]2[1008]3[1012]4b[1][1016]5[1020]6[1024]7[1028]8b[2][1032]9[1036]10[1040]11[1044]12三个一维数组b[0]:[1000]1000b[1]:[1016]1016b[2]:[1032]1032int*p;b:[[1000]]1000一级指针变量二级指针变量p:[5000]2000①是数组名(二维数组)②是一个假想的二级指针变量③b值为数组第0行的地址(一维数组b[0]的地址),数值上与b[0][0]的地址相等,但它是二级的④指针变量b本身的地址(b所在“内存”位置)数值上也与b[0][0]的地址相等,但它是三级的⑤b值不可被改变,是常量

二维数组名b

二维数组的地址(2)b[0]:

[1000]1000b[2]:

[1032]1032b[0][1000]1[1004]2[1008]3[1012]4b[1][1016]5[1020]6[1024]7[1028]8b[2][1032]

9[1036]10[1040]11[1044]12b[1]:

1016[1016]一级“指针变量”(假想的)

二级“指针变量”(假想的)

零级具体数据级别不同int*p;p=b;级别相同才能彼此赋值

p=b[0];p=b[1];p=b[2];inta[5];

p=a;p:[]2000

1000

[1016][1032]b:

[[

1000

]]1000b[0]:

[1000]1000b[2]:

[1032]1032b[1]:

1016[1016]行指针行指针特殊的专用变量保存int(*q)[4];*、()、[4]三者都不可少

q=b;

q=b[0];q=b[1];q=b[0][0];b[0][1000]1[1004]2[1008]3[1012]4b[1][1016]5[1020]6[1024]7[1028]8b[2][1032]

9[1036]10[1040]11[1044]12Hi,这是指针变量,存地址的!不是存数据的普通变量哦!定义形式够复杂了!但表示的意义很简单——定义一个二级指针变量q

[[]]q:20001000b:

[[

1000

]]1000行指针±整数q++;指向第0行指向第1行指向第2行q++;b++;b++;b是假想的指针变量,值不能改b[0]:

[1000]1000b[2]:

[1032]1032b[1]:

1016[1016]b[0][1000]1[1004]2[1008]3[1012]4b[1][1016]5[1020]6[1024]7[1028]8b[2][1032]

9[1036]10[1040]11[1044]12[[]]q:20001000

[[1016]][[1032]]

int

b[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};int(*q)[4];q=b;b:

[[

1000

]]1000行指针±整数,或二维数组的数组名±整数:移动一行指针变量±整数后,“级别”不变。两个重要公式(语法糖)同样适用对二级指针变量q或二维数组名b两个重要公式同样适用b[i]

*(b+i)

b[i][j]

*(b[i]+j)

*(*(b+i)+j)

特殊地,i=0、j=0时,b[0][0]

**b&b[0][0]

*b行指针与二维数组名可互换使用。二维数组元素的写法

原来是的b[i][j]

*(*(b+i)+j)

语法糖q[i]

*(q+i)

q[i][j]

*(q[i]+j)

*(*(q+i)+j)

*(q+i)q[i]q+i&q[i]*(b+i)b[i]b+i&b[i]*(x+i)x[i]x+i&x[i]指针变量与一维数组名的统一a:

[3000]3000行指针和二维数组名的统一b:[[1000]]1000q:[[]]2000

1000a:a[4]a[3]a[2]a[1]a[0]3000

inta[5];

int*p;p=a;p:

[3000]4000p[i]a[i]p的值能改;a的值不能改p

a

intb[3][4];

int(*q)[4];q=b;0123012b:1000

q的值能改;b的值不能改q

b

q[i]b[i]q[i][j]b[i][j][[1016]]b[1]:[1016]1016

q[0][0] b[0][0]q[1] b[1]q=b; b=q;q=&b[1]; b=&b[1];q++; b++; q=0;或q=NULL; b=0;或b=NULL;b的值不能被改所有的错误同样原因:[[1032]][[0]]一个表格、两句法则草稿写法±1效果定义二级指针

移动一行int(*q)[4];int

b[3][4];中的b

必移动4字节int

**r;int

*s[3];中的s一级指针

移动一个单位(int型4字节,char型1字节…)int

*p;int

a[2];中的a普通变量

变量值±1int

x;法则:①定义变量时:一个*或一个[]

升一级 ②使用时:一个*或一个[]降一级;一个&升一级[[]][[]][]q与b统一p与a统一r与s统一看做不同级别,不能互相赋值行指针和指针赋值小结intx[3][10];int(*p)[4];p=x;一行4个元素!int(*q)[10];q=x;一行10个元素!double(*r)[10];r=x;基类型不同p:[[]]20000123456789012q:[[]]3000r:[[]]4000int*s;s=x;x:[[1000]]1000x[0]:[1000]1000级不同s=x[0];s:[]50001000

1000

x=q;x不能改x[0]=s;x:1000

x[0]不能改两个指针变量间的赋值必须同时满足:①级别相同(二级指针变量分两类,两类之间还是不同级);②对行指针和二维数组,每行的元素个数相同;③两个指针变量的基类型相同;④数组名不能被赋值,其值不能被改变。A)p=s; B)p=k;C)p=s[0];D)s[0]=p;E)k=s;F)s=k;G)p=&s[1][2];H)k=&s[1][2];练习若有定义语句:chars[3][10], *p;以下赋值语句正确的是级不同二级二级一级级不同s[0]是假想的指针变量,是s的第0行这个一维数组的首地址,将之 赋值给p[1000]一行几个元素不同s是假想的二级指针变量,其值不能改s[0]的值不能改元素s[1][2]的地址 赋值给p级不同s是假想的指针变量,将其值(数组首地址) 赋值给k[[1000]][1012]法则: ①定义变量时:一个*或一个[]

升一级 ②使用时:一个*或一个[]降一级;一个&升一级(*k)[3],(*k)[10],

指针数组一个数组,各元素都是指针变量,都保存地址。指针数组所有元素基类型相同,即都要指向相同数据类型的变量。int*s[3];s:s[0]s[1]s[2][][][]i

温馨提示

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

评论

0/150

提交评论