理学C语言程序设计教程-第6章_第1页
理学C语言程序设计教程-第6章_第2页
理学C语言程序设计教程-第6章_第3页
理学C语言程序设计教程-第6章_第4页
理学C语言程序设计教程-第6章_第5页
已阅读5页,还剩82页未读 继续免费阅读

下载本文档

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

文档简介

第六章函数与编译预处理6.1模块化程序设计与函数6.2函数的定义与调用6.3函数的递归调用6.4变量的作用域与存取方式6.5编译预处理C语言程序设计教程2025/1/1516.1模块化程序设计与函数在设计较复杂的程序时,我们一般采用的方法是:把问题分成几个部分,每部分又可分成更细的若干小部分,逐步细化,直至分解成很容易求解的小问题。这样的话,原来问题的解就可以用这些小问题来表示。2基本概念基本模块模块模块模块模块模块模块模块模块模块2025/1/153模块与函数C语言程序由基本语句和函数组成,每个函数可完成相对独立的任务,依一定的规则调用这些函数,就组成了解决某个特定问题的程序。4模块与函数把大任务分解成若干功能模块,用多个函数来实现这些功能模块。通过函数的调用来实现完成大任务的全部功能。

5模块与函数任务、模块与函数的关系:一个大任务分成多个功能模块,

功能模块则由一个或多函数实现。

模块化的程序设计是靠设计函数和调用函数实现的。6例:分数排序任务:输入三个数,从大到小的顺序的输出。如果大 于等于85,在该数后面输出‘A’,小于85且大 于等于70,则输出‘B’,小于70且大于等于60, 输出‘C’,如果小于60,则输出‘D’。思路:scanf()输入分数

另建一个排序函数

判断并输出等级函数

打印分数及等级的函数虽然也可以由一个主函数来完成,但这样做可读性及操作性会更好。7

voidmain(){floata,b,c;

scanf("%f,%f,%f",&a,&b,&c);/*输入*/

sortabc(&a,&b,&c);/*排序*/

putabc(a,b,c);/*输出a,b,c三个数*/}8voidsortabc(a,b,c)floata,b,c;{floatt;if(a<b){t=a;a=b;b=t;}/*交换a,和b的值*/

if(b<c){t=b;b=c;c=t;}/*交换b,和c的值*/

if(a<b){t=a;a=b;b=t;}/*交换a,和b的值*/}9chargrade(x)/*根据x的值,得到等级标准*/

floatx;{if(x>=85)return('A');elseif(x>=70)return('B');elseif(x>=60)return('C');else

return('D');

}10

voidputabc(a,b,c)floata,b,c;{charg;g=grade(a);/*判别等级*/

printf("%6.1f:%c",a,g);g=grade(b);printf("%6.1f:%c",b,g);g=grade(c);printf("%6.1f:%c",c,g);}

11模块设计的原则模块独立规模适当层次分明功能专一12独立性原则表现在模块完成独立的功能,和其它模块间的关系简单,各模块可以单独调试。修改某一模块,不会造成整个程序的混乱。每个模块完成一个相对独立的特定子功能。在对任务逐步分解时,要注意对问题的综合。例如,一些模块的相似的子任务,可以把它们综合起来考虑,找出它们的共性,把它们做成一个完成特定任务的单独模块。每个模块有特定功能13模块之间最好只通过数据传递发生联系,而不发生控制联系。例如,C语言禁止goto语句作用到另一个函数,就是为了保证函数的独立性。每个模块力求简单14模块内使用的数据,对于不需要这些数据的其它模块来说,应该不允许使用;在一个模块内的变量的修改不会影响其它模块的数据。即模块的私有数据只属于这个模块。C语言的局部变量,就是满足模块独立的的需要。每个模块应用独立变量15模块不能太大,但也不能太小。模块的功能复杂,可读性就不好,而且也违背独立性原则。但如果做得太小,实际上也会复杂各个模块间反复调用,可读性也会降低。这点需要慢慢积累经验,好好把握。16算法简介算法简介算法简介什么是算法?通俗地说,算法是解决一类特定问题的方法和步骤。

算法是一个有限操作的序列。算法的每一步都是确定的。算法的每一步计算机都能操作。有一个或多个的输入或输出。17算法的描述算法描述的任务是将解题步骤和方法用一定的形式表示出来,要清楚、准确、严谨,还要可读性好,方便实现。

算法两大要素:

一是操作,用类计算机语句或自然语言描述。

二是控制结构,描述算法一般可以用流程图描述。18例6.2

设计算法:找出a,b两数中的较大者,并输出分析:这个问题分三个步骤:

输入两个数;

找出其中的大数;

输出大数。19开始输入a,ba<b交换a,b输出a结束非00图6.3找出a,b两数中的较大者算法流程图

2025/1/15206.2函数的定义与调用在C语言中,函数(Function)是一个处理过程,可以进行数值运算、信息处理、控制决策,即一段程序的工作放在函数中进行,函数结束时可以携带或不带处理结果。

库函数(标准函数):系统提供

自定义函数:用户自己写

21C语言程序处理过程全部都是以函数形式出现,最简单的程序至少也有一个main函数。函数必须先定义和声明后才能调用。22标准库函数C语言有丰富的库函数,这些函数的说明在不同的头文件(*.h)中。想要调用标准的库函数,就必须include。#include<stdio.h>

main()

{printf(“%d”,1024*768);

}调用printf函数时,

必须include<stdio.h>23自定义函数可以把完成一个任务的过程写成函数。int

A_to_a(intcapital)

{intsmall;

if(capital>=‘A’&&capital<=‘Z’)

small=capital–(‘A’-’a’);

returnsmall;

}返回值类型名函数名注意不要与已有库函数重名参数说明和参数列表调用函数时输入参数的格式要与之相同定义局部变量最好只使用局部变量,这样将方便调试。返回值如果不需返回则可return0;另外请注意这样的判断,如写成‘A’<capital<‘Z’是不行的24“函数”的主要知识点

函数的定义函数的参数和返回值

函数的调用嵌套和递归变量的作用域25函数举例#include<conio.h>

main()

{inta,b,m;

/*说明变量*/

int

max(int

a,intb);

/*函数声明*/

scanf("%d,%d",&a,&b);

/*调用库函数scanf*/

m=max(a,b);

/*调用字定义函数max*/

printf("max=%d\n",m));

/*调用库函数printf*/

getch();

/*调用库函数getch*/

}

26函数举例int

max(int

a,intb)

/*定义函数max*/

{

inty;

y=(a>b)?a:b;/*条件表达式*/

returny;

}if(a>b)y=a;

elsey=b;27自定义函数的声明自定义函数在调用前应先声明。使系统知道将要用到某个函数及它的类型,以便处理。函数声明应与该函数定义时给出的函数类型与名字、形参的个数、类型、次序相一致。#include“stdio.h”

voidmain()

{floatx,y;

intn;

floatpower(floatx,intn);

scanf("%f,%d",&x,&n);

y=power(x,n);printf(“%8.2f”,y);

}floatpower(floatx,intn)

{inti;

floatt=1;

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

t=t*x;

returnt;

}28求1!+2!+3!+…+10!算法

i=1;s=0;

当i<=10s=s+

i!

定义求i!的函数29求1!+2!+3!+…+10!程序voidmain(){longmm(int);/*自定义求阶乘函数应先声明*/

inti;longs=0;for(i=1;i<=10;i++)s+=mm(i);/*调用求阶乘函数,求I的阶乘*/

printf(“\n%ld”,s);}30定义求n!的函数longmm(intn){longt=1;inti;for(i=1;i<=n;i++)t*=i;returnt;}31同样的,在调用

m=max(a,b)时,其形参

的值是a和b

而m将会得到y的值函数的参数int

max(int

a,intb)

{

inty;

y=(a>b)?a:b;

returny;

}调用时:m=max(3,6);

m=max(a,b);

括号里是形式参数返回值括号里是实参在这一句调用时,

形参的值是3和6其返回值y将被赋给

调用语句中的m32形式参数与实际参数的关系形式参数在函数中是变量名,

在函数调用时,形参被分配相应的内存实际参数是表达式

负责向对应的形参标识的内存单元传递数据实参与形参必须个数相同对应的形参和实参的类型必须一致

实参给形参传递值得时候,按顺序传递,与形参名无关。所以实参与形参可以不同名。33实参与形参例:主调函数中有如下语句:

scanf("%d,%d",&a,&b);

m=max(a,b+3);如果输入6,2函数int

max(int

a,intb)形参a得到第一个实际参数a的值6形参b得到第二个实际参数b+3的值5

34函数返回值函数返回值通过return语句获得函数返回值的类型就是函数的类型

returny;

将变量y的值返回给调用者

returny+3;

将表达式的值返回给调用者35return的数据类型与函数的类型矛盾时,自动将数据转换成函数的类型intfunct1(){charch;

while

((ch=getch())<'a'||(ch>'z')

;

returnch;}调用:i=funct1();/*返回的是int类型*/36函数没有返回值,函数定义成空类型voidputline()

{inti;

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

printf("-");

printf("\n");

}函数的功能就是输出35个‘-’

调用:putline();

应该的语句形式

i=putline();是错的37调用函数a=function(x,y);

或者

function(x,y);

取返回值

只是操作解决更复杂问题时可以嵌套调用。longfac(intk)

{longf=1;

inti;

for(i=1;i<=k;i++)

f=f*i;

returnf;

}

longcombination(intn,intm)

{longc;

inti;

c=fac(m)/(fac(n)*fac(m-n));

returnc;

}

主函数:

main()

{intn,m;

longc;

scanf(“%d,%d”,&n,&m);

c=combination(n,m);

printf(“%ld”,c);

}理论上可以a(b(d(e(x))),c(f))

般嵌套无数层。386.3函数的递归调用函数调用它本身,称为递归。直接在函数内调用自己为直接递归,通过别的函数调用自己为间接递归。voida()

{......

a();

......

}voida()

{......

b();......

}

voidb()

{......

a();

......

}递归在解决某些问题中,是一个十分有用的方法。因为其一,有的问题它本身就是递归定义的;其二,它可以使某些看起来不易解决的问题变得容易解决,写出的程序较简短。39递归方法求n!由于n!=n*(n-1)!是递归定义所以求n!

(n-1)!

(n-1)!

(n-2)!

(n–2)!

(n-3)!

……

0!的问题,

根据公式有0!=1。

再反过来依次求出1!,2!……直到最后求出n!。40递归方法求n!longfac(intn)

{longf;

if(n==0)

f=1;

else

f=n*fac(n-1);

returnf;

}

main()

{longy;

intn;

scanf(“%d”,&n);

y=fac(n);

printf(“%d!=%ld”,n,y);

}刚开始的时候,这个n是前面

输入的需要阶乘的n所以在这里带入的值是n而这个函数里又调用

了本身,不过参数已经

变成了n-1所以这里再次调用时

参数已经变成了n-1注意:上次调用fac(n)

还没有完,只是由于遇到

了fac(n-1)而执行fac(n-1)

去了.而在调用fac(n-1)时同样

遇到了要调用fac(n-2)的问题,于是一层一层的

包裹下去,每次调用的

时候都会在内部调用一

个结构相同但变量不同

的函数,直到。。。直到调用到fac(0)时,由于内部if判断,已经

不需要再继续调用另一

个fac(n-1),而直接有了f=1fac(0)已经执行完毕,它的

返回值被fac(1)中的f=n*fac(n-1)

语句赋给了f值,同时返回了f。而这个返回的f又被fac(2)乘上

当前的n值以后继续返回f直到最后的fac(n)都做完了,

f的值被返回到了它的调用点:

主函数中,这样就是一个递归

运算。41递归举例问题:第1个月有1对兔子过2个月,兔子就可每个月生1对兔子问第n个月有多少对兔子?

分析:设第n个月有f(n)对兔子根据题意有f(0)=0,f(1)=1f(n)=f(n-1)+f(n-2)f(n-1):前一个月的兔子数

f(n-2):本月生的兔子数

42斐波那契其人1170年生于意大利的比萨,在北非的布吉亚,即今阿尔及利亚的贝加亚长大并且接受教育。大约在1200年,他才重新回到比萨。斐波那契无疑在启蒙教育时期就受到过阿拉伯数学家的影响或者接受过他们的辅导。他写过大量的数学论文,取得了一些重大的数学发现。这使他的著作在意大利非常流行,并且引发了当时罗马帝国皇帝弗雷德里克二世的注意,他曾邀请斐波那契到他在比萨宫廷觐见。斐波那契于1250年去世。1202年,他在所著的《算珠原理》中,提出了一个著名而有趣的兔子问题:假定一对小兔子经过一个月后能够长成一对大兔子,而一对大兔子经过一个月后能够生了一对小兔子.现在我们从一对小兔子开始,用表示第个月兔子的总对数,显然,(第1个月只有一对小兔子,第2个月只有一对大兔子),(第3个月一对大兔子生出一对小兔子,总共两对兔子.

于是我们得到一个数列:1,1,2,3,5,8,13,…

仔细观察这个数列,从第3项起每一项都是它前相邻两项的和,这就是著名的斐波那契数列.43定义函数f(n)longf(intn)

{

switch(n){case0:return0;break;case1:return1;break;

default:returnf(n-1)+f(n-2);/*调用函数f(n)*/}}44兔子问题主函数voidmain(){longf(intn);/*自定义函数声明*/

intn;

printf(“\ninputn:”);

scanf(“%d”,&n);

printf(“\nf(%d)=%ld”,n,f(n));

/*调用函数f(n)*/}45斐波那契数列有一系列奇妙的性质,现简列以下几条,供大家欣赏.

1.从首项开始,我们依次计算每一项与它的后一项的比值,并精确到小数是第四位.如果将这一工作不断地继续下去,这个比值将无限趋近于某一个常数,这个常数位于1.6180与1.6181之间,它还能准确地用黄金数表示出黄金分割率。

2.在自然界中,斐波那契数列也常见到,比如:向日葵花冠上的螺旋,如果前一道螺旋直径为21的话,下一道螺旋直径则为34,依次形成连续的斐波那契数字;松果的外弧为顺时针或逆时针方向的螺旋,期相同间隔之间螺旋的直径也能构成斐波那契数列;在上等的鹦鹉螺身上,每圈罗纹的直径与相邻罗纹直径之比亦是1:1.618,菠萝是又一种可以检验斐波那契数的植物;菠萝表皮方块形鳞苞形成两组旋向相反的螺线,它们的条数必须是这个级数中紧邻的两个数字(如左旋8行,右旋13行)。

463.有一种两人游戏,名叫“尼姆”。游戏方法是由两个人轮流取一堆粒数不限的砂子。先取的一方可以取任意粒,但不能把这堆砂子全部取走。后取的一方,取数也多少不拘,但最多不能超过对方所取砂子数的一倍。然后又轮到先取的一方来取,但也不能超过对方最后一次所取砂子的一倍。这样交替地进行下去,直到全部砂子被取光为止,谁能拿到最后一粒砂子,谁就算胜利者。在这个游戏中,若所有砂子的粒数是个斐波那契数的话,那么后取的一方稳操胜券,但所有的砂子不是一个斐波那契数的话,那么先取的一方稳胜。47辗转相除法求最大公约数求m和n的公约数算法if(m%n)==0

n是公约数;

else

求n和m%n的公约数;

48用欧几里德算法(辗转相除法)求两个数的最大公约数的步骤如下:

1.若r是a÷b的余数,则

gcd(a,b)=gcd(b,r)

2.a和其倍数之最大公因子为a。

49求最大公约数的递归算法

int

gcd(intm,intn)

{if(m%n)==0

returnn;

else

returngcd(n,

m%n);}50求最大公约数的主函数voidmain(){intm,n,t;

int

gcd(intm,intn);

scanf(“%d%d”,&m,&n);

if(m<n)

{t=m;m=n;n=t;}

t=gcd(m,n);/*调用函数gcd(m,n);

*/print(“\ngcd=%d”,t);}51汉诺塔(又称河内塔)问题是印度的一个古老的传说。开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。面对庞大的数字(移动圆片的次数)18446744073709551615,看来,众僧们耗尽毕生精力也不可能完成金片的移动。汉诺塔52后来,这个传说就演变为汉诺塔游戏:

1.有三根杆子A,B,C。A杆上有若干碟子。

2.每次移动一块碟子,小的只能叠在大的上面。

3.把所有碟子从A杆全部移到C杆上。经过研究发现,汉诺塔的破解很简单,就是按照移动规则向一个方向移动金片,如3阶汉诺塔的移动:A→C,A→B,C→B,A→C,B→A,B→C,A→C此外,汉诺塔问题也是程序设计中的经典递归问题。

算法思路:

1.如果只有一个金片,则把该金片从源移动到目标棒,结束。

2.如果有n个金片,则把前n-1个金片移动到辅助的棒,然后把自己移动到目标棒,最后再把前n-1个移动到目标棒

53汉诺塔是一个很繁杂的游戏,但用递归的方法解决起来异常简单。规则:(1)一次只能移动一个

(2)大的不能放在小的上面

(3)只能在三个位置中移动54问题可分为三个步骤对于把n个金片从第一根针a上移到第三根针c的问题可以分解成如下步骤:

(1)将n-1个金片从a经过c移动到b。(2)将第n个金片移动到c。(3)再将n-1个盘子从b经过a移动到c。这样我们就将移动n个金片的问题变成了移动n-1个金片的问题。这样做下去的话最后就会变成移动一个金片的问题。55递归方法解汉诺塔voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}n=1时,直接将金片

从a移动到cn-1个金片从a经过

c移动到b将第n个金片

从a移动到c再将n-1个金片从

b经过a移动到cmain()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}56递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}输入3。则n=357递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}

主函数调用hanoi(n,1,2,3);第一次调用。第一次调用hanoi(n,a,b,c)(第一层)即要把三个金片移到cn=358递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}由于n>1则执行hanoi(n-1,a,c,b)

(第二次调用)n=359递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}由于仍然n>1则执行

hanoi(n-1,a,c,b)

(第三次调用)n=260递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}由于n=1则printf(“%d->%d”,a,c);

即把金片从a移动到c

n=161递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}第三层执行完毕,返回到第二层,即下去执行printf(“%d->%d”,a,c);把第二个金片摆到第二根针上n=262递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}执行下一条语句,又调用第三层hanoi(1,3,1,2)n=263递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}n=1,执行结果为32n=164递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}第二层也执行完了,返回第一层,执行接下来的语句,结果为13。n=365递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}执行接下来的语句,再次调用

第二层hanoi(2,2,1,3)n=366递归汉诺塔步骤voidhanoi(intn,inta,intb,intc)

{

if(n==1)

printf(“%d->%d”,a,c);

else

{hanoi(n-1,a,c,b);

printf(“%d->%d”,a,c);

hanoi(n-1,b,a,c);

}

}main()

{intn;

printf(“inputn:”);

scanf(“%d”,&n);

hanoi(n,1,2,3);

}676.4变量的作用域与存储方式先看一个例子,错在那里?:voidf1(){intt=2;a*=t;b/=t;}main(){inta,b;

printf(“Entera,b:”);

scanf(“%d,%d”,&a,&b);f1();/*调用函数f1()*/

printf(“a=%d,b=%d”,a,b);}编译程序会提示出错:Undefinedsymbol‘a’和Undefinedsymbol‘b’

。为什么?2025/1/1568一.变量的作用域

即变量的有效范围1.变量按作用域分为全局变量和局部变量2.比较:全局变量(外部变量)局部变量(内部变量)定义位置:函数体外函数体内作用域:从定义处到本源从定义处到本函数结束文件结束举例:所有函数体外定义的变量(1)所有在函数体内定义(2)形式参数注意与局部变量同名的处理局部变量屏蔽全局变量不同函数中同名局部变量互不干扰

2025/1/1569#include<stdio.h>inta,b;/*a,b为全局变量*/voidf1(intx){intt1,t2,a;a=t1=x*4;t2=b*3;b=10;

printf(“f1:t1=%d,t2=%d,a=%d,b=%d\n”,t1,t2,a,b);}main(){a=2;b=4;/*此a,b是全局变量,赋值*/

f1(a);/*调用函数f1()*/

printf(“main:a=%d,b=%d”,a,b);}

程序输出结果为:

f1:t1=8,t2=12,a=8,b=10main:a=2,b=102025/1/1570若将程序改为:#include<stdio.h>inta=2,b=4;/*a,b为全局变量*/

voidf1(){intt1,t2;t1=a*2;t2=b*3;b=100;

printf(“t1=%d,t2=%d,b=%d\n”,t1,t2,b);}main(){intb=4;/*此b是局部变量,赋值*/

f1();/*调用函数f1()*/

printf(“a=%d,b=%d”,a,b);}结论:全局变量与局部变量同名时,局部变量起作用,全局变量被屏蔽(不影响),应小心使用程序输出结果为:t1=4,t2=12,b=100a=2,b=42025/1/1571二.变量的存储特性1.变量按存在时间分

静态变量动态变量静态存储类型的变量的生存期为程序执行的整个过程,在该过程中占有固定的存储空间,通常称它们为永久存储。动态存储类型变量只生存在某一段时间内。例如,函数的形参和函数体或分程序中定义的变量,只是在程序进入该函数或分程序时才分配存储空间,当该函数或分程序执行完后,变量对应的存储空间又被撤销了。2.c语言中每一个变量有两个属性:数据类型,存储特性完整的变量定义:[存储特性][数据类型]变量名;2025/1/15723.变量的存储特性自动型auto

静态型static

寄存器型register

外部型extern(1)auto型每次进入程序是自动分配内存,不长期占用内存例如:形式参数,自动型局部变量(2)static型①局部静态变量②全局静态变量长期占用内存2025/1/1573例1:分析执行结果f(inta){intb=0;staticintc=3;b++;c++;printf(“%5d%5d%5d”,a,b,c);return(a+b+c);}main(){inta=2,k;for(k=0;k<3;k++)printf(“%5d\n”,f(a));}静态变量只初始化一次。再次调用定义它的函数时变量保存了前一次被调用后留下的值。结果:214(a,b,c)7(f(a))215821692025/1/1574(3)register型将使用频率高的变量定义为register型,可以提高运行速度.数据内存运算器运算器结果控制器数据寄存器寄存器变量只限于整型、字符型、指针型的局部变量。寄存器变量是动态变量,而且数目有限,一般仅允许说明两个寄存器变量。例如:

registerintd;registercharc;2025/1/1575(4)extern型引用:extern类型变量名;如果某个模块文件中要用到另一个模块文件中的全局变量,就要用extern说明例如:程序模块file1.c中定义了全局变量

ints;而在另一个程序模块file2.c中的函数fun1()中需要使用这个变量s。为此,可以在file2.c的函数fun1()中加上外部变量说明语句:fun1(){externints;/*表明变量s是在其他文件定义的*/.......}定义时分配内存,其他文件引用时不再分配内存.2025/1/15766.5编译预处理

“编译预处理”是C语言编译系统的一个组成部分。是在编译前由编译系统中的预处理程序对源程序的预处理命令进行加工。源程序中的预处理命令均以“#”开头,结束不加分号,以区别源程序中的语句,它们可以写在程序中的任何位置,作用域是自出现点到源程序的末尾。预处理命令包括执行宏定义(宏替换)、包含文件和条件编译。2025/1/1577一.宏定义简单宏定义1.一般形式为:#define宏名串(宏体)如:#definePI3.14159/*定义后,可以用PI来代替串3.14159*/2.宏定义的作用在宏定义之后,该程序中宏名就代表了该字符串。3.说明①可以用#undef命令终止宏定义的作用域。例如:#undefPI②宏定义的嵌套使用#defineR3.0#definePI3.1415926#defineL2*PI*R/*宏体是表达式*/#defineSPI*R*R2025/1/1578main(){printf("L=%f\nS=%f\n",L,S);/*2*PI*R替换L,PI*R*R替换S*/}程序运行结果如下:L=18.849556S=28.247333③双引号内与宏同名的字母不作宏展开.(见上例)带参数的宏定义1.带参数的宏定义的一般形式为#define宏名(参数表)字符串如:#defineS(a,b)a*b#definePR(x)printf("s=%f\n”,x)2025/1/15792.带实参的宏名被展开宏名被所定义的宏体替换,宏体中的形参按从左到右的顺序被实参替换。例如:#defineL(x)(x*x+2*x+x)宏调用:y=L(5);调用时用实参5去代替形参

温馨提示

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

评论

0/150

提交评论