如何提高编程能力:
第一步理清解题思路,用伪代码描述清楚解题步骤 (自顶向下,
逐步细化 );第二步用 N-S图将算法准确地予以表示 (此时分析算法是否有错 ),第三步根据 N-S图上机调试 (调试语法是否有错 )并验证结果正确性 (不正确则看算法 )
关于字符与字符串输入的说明:
int i,j;
char c1,c2,ctemp;
char str1[20],str2[20];
/*以下语句执行结果与通常预期不同,注意测试 */
scanf("%d",&i);scanf("%c",&c1);printf("error1\n");
scanf("%c",&c1);scanf("%c",&c2);printf("error2\n");
scanf("%d",&i);gets(str1);printf("error3\n");
scanf("%c",&c1);gets(str1);printf("error4\n");
scanf("%s",str1);gets(str1);printf("error5\n");
/*以下形式的语句则能避免上述语句的问题 */
scanf("%c",&c1);scanf(" %c",&c2);printf("%c ok7\n",c2);
/*第二个 %c前有空格 */
scanf("%c",&c1);scanf("%s",&str1);printf("%s ok8\n",str1);
gets(str1);gets(str2);printf("ok9\n");
scanf("%d",&i);scanf("%c",&ctemp);scanf("%c",&c1);printf("ok10\n");
第八章本章要点:
8.1 什么是函数,为什么用函数?
8.2-8.4 如何定义函数,函数工作原理如何?
8.8 局部变量与全局变量
8.9/8.10 内部函数与外部函数,变量存储类别函数的嵌套调用、递归调用与数组作函数参数
§ 8.1概述 --什么是函数,为什么用函数?
编程求解复杂问题时通常把整个程序划分为若干功能较为单一的程序模块,然后分别予以实现,最后再把所有的程序模块像搭积木一样装配起来,这种在程序设计中分而治之的策略,被称为 模块化 程序设计方法
C语言把每个模块都编写成一个 C函数,然后通过主函数调用这些功能相对独立的模块从而实现大型问题的求解。
这样,一方面可以 使程序设计简单直观,提高了程序的易读性和可维护性 ;另一方面可以 把常用的一些计算或操作编成通用的函数供随时调用,这样可以大大地减轻程序员的代码工作量 。
void main()
{
int i;
while(1)
{
welcome();
scanf("%d",&i);
if(i==1)
huiwen ();
else if(i==2)
erfen();
else if(i==3)
diedai();
else if(i==4)
diamond();
else if(i==5)
break;
else
printf(“输入有误 !重新输入 ");
}
}
/*函数 welcome用以输出一个欢迎界面 */
void welcome()
{
printf("使用菜单选择趣味程序 \n");
printf(" 1---求某范围内的回文数 \n");
printf(" 2---二分法求一元二次方程根 \n");
printf(" 3---牛顿迭代法求一元三次方程根 \n");
printf(" 4---输出菱形图 \n");
printf(" 5---退出 \n");
printf("***************************************\n");
}
/*函数 huiwen用以输入两个正整数,求两数之间的回文数 */
void huiwen()
{
函数声明部分函数执行部分
}
程序从 main函数开始执行,它可以调用其它函数,但不能被别的函数所调用,main
函数之外的函数相互之间可以调用,此外,函数是平行的,不能嵌套定义从用户使用角度看,函数分 标准函数
( 库函数)和 用户自定义函数 ; 从函数形式看,
函数分 无参函数 和 有参函数函数说明与分类:
§ 8.2函数的定义形式类型标识符 函数名( 形参及其类型 )
{
声明部分语句部分
}
int max( int x,int y)
{ int z;
z=x>y?x ∶ y;
return(z);
}
定义函数时要用
,类型标识符,指定函数返回值的类型,默认为 int型
§ 8.3函数工作原理
8.3,1形式参数 /实际参数 /函数返回值定义函数时函数头部括弧中的变量称为,
形式参数,;发生调用时,调用语句中函数名后括弧内的参数称为,实际参数,;函数体内 return后括弧中的值称 函数返回值
int max(int x,int y )
{
int z;
z=x>y? x ∶ y;
return( z ) ;
}
void main ( )
{
int a,b;
scanf(“%d%d”,&a,&b);
c=max ( a,b ) ;
}
说明:
(1) 形参只有在发生函数调用时,才被分配内存单元 ;在调用结束后,形参所占的内存单元即被释放,考虑两次调用 max函数的情况
(2) 发生调用时将实参的值传递给形参,实参是常量、变量或表达式均可,如:
max(3,a+b);
(4) 实参与形参的类型应相同或赋值兼容
(5)在C语言中,实参向对形参的数据传递是
,值传递,,单向传递,只由实参传给形参,
而不能由形参传回来给实参,形参变量的改变不影响实参的取值,通常 通过函数返回值带回信息 。如两实参变量值的互换目前无法用函数实现,因为在内存中,实参单元与形参单元是不同的单元。
8.3.2( 3) 定义函数时指定的函数类型一般应和
return语句中的表达式类型一致,若不一致,则以函数类型为准进行类型转换补充,一旦遇到 return语句则函数停止执行并返回例 8.3 返回值类型与函数类型不同
# include <stdio.h>
void main()
{ int max( float x,float y) ;
float a,b;
int c;
scanf("%f,%f,",&a,&b);
c=max(a,b);
printf("Max is %d\n",c);
}
int max( float x,float y)
{ float z;
z=x>y?x ∶ y;
return(z);
}
运行情况如下:
1.5,2.5 ↙
Max is 2
/*若将 c改为浮点型? */
§ 8.4 函数的调用
8.4,1 函数调用的一般形式形式,函数名 (实参表列)
即使无参括弧也不能省参数间用逗号隔开对实参求值的顺序并不是确定的,如 f(i,++i)。应避免歧义的发生,如用 j=++i;f(i,j);
§ 8.4,2函数调用的方式
1.函数语句,如 printstar( ),不要求函数带回值,只要求函数完成一定的操作
2.函数表达式,如 c=2 *max(a,b); 要求函数带回一个确定的值,并参加表达式的运算
3.函数参数,函数调用作为实参。如
m=max (a,max ( b,c ) )
§ 8.4,3对被调用函数的声明和函数原型§ 4 3对被调用函数的声明和函数原型如使用库函数,应用#include命令将用到的信息“包含”到本文件中,如使用自定义函数,
而该函数的位置在主调函数的后面则应 对被调用的函数作声明,这种在主调函数中的声明称为 函数原型形式:
float add(float x,float y);
float add(float,float);
/*注意 P165形式( 2)错 */
§ 8.8局部变量和全局变量
§ 8.8.1局部变量在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,在此函数以外是不能使用这些变量的,这称为“局部变量”。
float f1( int a)/*形参只在 f1内有效 */
{int b,c;
… /* 形参 a及 b c在 f1内有效,调用时分配空间,返回时释放空间 */
}
void main( )
{int b,m,n; /*b,m,n在主函数内 有效
… 调用子函数时无效 */
}
(1) 主函数中定义的变量也只在主函数中有效,主函数也不能使用其他函数中定义的变量。
(2) 不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰
(3) 形式参数也是局部变量。例如上面 f1函数中的形参 a,也只在 f1函数中有效。
(4) 在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为
“分程序”或“程序块”。
说明
void main ( )
{int a,b;
…
{int c;
c=a+b; /* c只在此复合语句内有效,而 a,b在整个 main()有效 */
…
}
…
}
§ 8.8.2 全局变量在函数之外定义的变量称为 外部变量,外部变量是全局变量 (也称全程变量 )。全局变量有效范围是从定义位置开始到本源文件结束说明:全局变量增强了函数间的数据联系,但影响函数间的独立性,不提倡例 8.15 有一个一维数组,内放10个学生成绩,写一个函数,求出平均分、最高分和最低分。
#include <stdio.h>
float Max=0,Min=0; /*全局变量,首字母大写 */
void main()
{ float average( float array[ ],int n) ;
float ave,score[10];
int i;
for(i=0;i<10;i++)
scanf( ″%f ″,&score[i]);
ave= average(score,10);
printf(“max=%6.2f \ nmin=%6.2f\ n
average=%6.2f\ n“,Max,Min,ave);
}
float average( float array[ ],int n)
/ * 定义函数,形参为数组 */
{ int i;
float aver,sum=array[0];
Max=Min=array[0];
for(i =1;i<n;i++)
{ if( array[i]> Max) Max= array[i];
else if( array[i]< Min) Min= array[i];
sum=sum+array[i];
}
aver=sum/n;
return(aver);
}
例 8.16外部变量与局部变量同名的处理:
在局部变量的作用范围内,外部变量被屏蔽
#include <stdio.h>
int a=3,b=5; /* a,b为外部变量 */
void main ( )
{ int a=8; /*a为局部变量 */
printf (″%d″,max (a,b));
}
max (int a,int b) /*a,b为局部变量 */
{ int c;
c=a> b?a∶ b; return (c);
}
§ 8.10 内部函数和外部函数
§ 8.10.1内部函数如果一个函数 只能被本文件中其他函数所调用,它称为内部函数 。在定义内部函数时,在函数名和函数类型的前面加 static。即
static 类型标识符 函数名 (形参表 )
如 static int fun ( int a,int b )
作用:避免冲突
§ 8.10.2外部函数能被其它文件调用的函数称为外部函数
(1)形式:
extern int fun (int a,int b)
extern可省略,隐含即为外部函数
(2) 在需调用此函数的文件中,要用 extern对函数作声明,表示该函数是在其他文件中定义的外部函数,extern也可省略例 8.22 有一个字符串,内有若干个字符,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现
file1.c
#include <stdio.h>
void main()
{ extern void enter_string(char str[]);
extern void detele_string(char str[],char ch);
extern void print_string(char str[]);
char c;
char str[80];
enter_string(str);
scanf("%c",&c);
detele_string(str,c);
print_string(str);
}
file2.c
#include <stdio.h>
void enter_string(char str[80])
{ gets(str); }
file3.c
void delete_string(char str[],char ch)
{ int i,j;
for(i=j=0;str[i]!='\0';i++)
if(str[i]!=ch) str[j++]=str[i];/*注意该技巧 */
str[i]='\0';
}
file4.c
#include <stdio.h>
void print_string(char str[])
{ printf("%s\n",str);}
§ 8.9 变量的存储类别
§ 8.9,1 动态存储方式与静态存储方式根据变量的作用域(即从空间)角度分 全局变量 和局部变量 。从变量值存在的时间(即生存期)又可分为 静态存储方式 和 动态存储方式类似全局变量,由系统分配固定的存储空间,直至整个程序执行完毕才释放,这称为 静态存储方式,
这些数据放在内存的 静态存储区 。
类似形参在子函数调用时分配空间,而子函数结束时释放空间的存储方式称 动态存储方式 ;这些数据放在 动态存储区定义变量时可指定存储类别,
存储类别 数据类型 变量名局部变量默认或用 auto声明,如 auto int b,c=3; 动态用 static声明,如 static int b,c=3;编译时赋初值,静态用 register声明,如 register long i;自动处理,动态全局变量默认:作用域从定义处始到 本文件 结束止,静态若 作用域外 用,需 extern作外部变量声明,静态用 static声明外部变量,则该变量只在本文件能用,
静态,如 static int A
例 8.18静态局部变量使用举例 输出1到5的阶乘值。
#include <stdio.h>
void main()
{ int fac( int n) ;
int i;
for(i=1;i<=5;i++)
printf( ″%d! =%d\n ″,i,fac(i));
}
int fac( int n)
{ static int f=1 ;/*静态局部变量,编译时赋初值 */
f=f *n;
return(f);
}
作 业作业,8.1 8.3 8.16之 N-S图实验报告,8.2 8.10 8.18之 N-S图如何提高编程能力 (以求鞍点为例 ):
第一步理清解题思路,用伪代码描述清楚解题步骤 (自顶向下,
逐步细化 );第二步用 N-S图将算法准确地予以表示 (此时分析算法是否有错 );第三步根据 N-S图上机调试 (调试语法是否有错 )并验证结果正确性 (不正确则重新看 N-S
图分析算法 )
关于字符与字符串输入的说明
int i,j;char c1,c2,ctemp;char str1[20],str2[20];
/*以下语句执行结果与通常预期不同,注意测试,因为回车会被当作第二个输入语句的输入加以接收 */
scanf("%d",&i);scanf("%c",&c1);printf("error1\n");
scanf("%c",&c1);scanf("%c",&c2);printf("error2\n");
scanf("%d",&i);gets(str1);printf("error3\n");
scanf("%c",&c1);gets(str1);printf("error4\n");
scanf("%s",str1);gets(str1);printf("error5\n");
/*以下形式的语句则能避免上述语句的问题,注意分析测试 */
scanf("%c",&c1);scanf(" %c",&c2);printf("%c ok7\n",c2);/*第二个
%c前有空格 */
scanf("%c",&c1);scanf("%s",&str1);printf("%s ok8\n",str1);
gets(str1);gets(str2);printf("ok9\n");
scanf("%d",&i);scanf("%c",&ctemp);scanf("%c",&c1);printf("ok\n");
第八章作业提示
(1)定义 时函数头要写全,如 int f(int x,int y),其后不能有分号 ;声明 时函数形参的类型可以省略,如 int f(int,int)或 int f(int x,int y)均可,且其后必须有分号; 调用 函数时给出函数名和实参即可,如 f(a,3),不能写 int f(int a,int 3)
float f1(float a,float b,float c);float f2(float a,float b,float c);
float f3(float a,float b,float c);
void main(){float a,bloat b,float c;f1(a,b,c); f1(a,b,c) ;f1(a,b,c);}
(2)函数内部定义的变量( 局部变量 )只在本函数内有效,函数外定义的变量( 全局变量 )在定义位置后的各个函数都有效,不同函数中的 局部变量可以重名,各自在其定义的函数内有效;全局变量与局部变量重名时,
在局部变量所在函数内,局部变量有效第八章作业提示
(3)函数应包含几个参数由函数 完成其功能需要接收几个值决定,如定义子函数求两个数的最大公约数,显然只需知道这两个数是多少,故需两个形参来接收这两个值;函数 返回值只能有一个或没有 。 如求一元二次方程的根,若有两个不等的实根,则目前无法利用子函数一次返回两个值,有两种处理方法,其一,将 x1与 x2定义为全局变量,此时不需要返回值,
因子函数中的 x1与 x2与主函数中的 x1与 x2指的是同一个变量,只要在子函数为两者赋值,主函数中也相应改变,故函数返回值类型可为空 ;其二,
不用全局变量,直接在子函数中将两个根求出并 输出,这样也不需返回值
(4)当程序含有多个函数时,每个函数画一个 N-S图,子函数前说明函数作用并给出函数头部,发生调用的语句对应框中直接写调用语句,如
,x=gcd(a,45)”,再如 f(a,b)
§ 8.5 函数的嵌套调用例 6弦截法求方程 x3-5x2+16x-80= 0根
(1)主函数,输入合理区间,调用 root函数求根
y= x3+16x
return(y)
x0=x1+(-f(x1)*(x2-x1))/(f(x2)-f(x1))
return(x0)
(2)求函数值子函数 float f(float x)
(3)求区间 (x1,x2)的实根子函数
float root (float x1,float x2)
(4) 求 弦截点子 函数
float xpoint (float x1,float x2)
while(fabs(y0)>1e-6)
return(x0)
y1*y0>0Y N
x1=x0,y1=y0 x2=x0,y2=y0
x0=xpoint (x1,x2),y0=f(x0)
直到 y1*y2<0
y1=f(x1),y2=f(x2)
输入 x1与 x2
x0= root(x1,x2)
输出 x0
8.6函数的递归调用
:参考递归课件
§ 8.7数组作函数参数
§ 8.7.1 数组元素作函数参数 void main{
int a[2]={0,1};
exchange(a[0],a[1]);
pintf(“%d %d”,a[0],a[1]);
}
void exchange(int x;int y)
{ int tmp;
tmp=x;
x=y;
y=tmp;
} /*莫忘声明! */
数组元素作参数是将 数组元素的值 传递到形参对应的内存空间中,
之后操作是对形参对应单元的数值进行,故原来的数组内容不变;
实参是数组某元素,如 a[i],形参是普通变量,如 int x;
§ 8.7.2 数组名作函数参数数组名作参数是将 数组名的值 ( 即数组首地址 ) 传递到形参对应的单元中,从而形参的值就是原数组的首地址,之后通过形参进行操作实际就是通过原数组的首地址进行操作,从而原数组的内容改变,此时形参是类似数组名的变量,能接收地址,如 int a[];实参是数组名,如 a
float average ( float array[],int n)
{ int i;
float aver,sum=0;
for (i= 0;i<10;i++ )
sum +=array[i];
aver=sum/10;
return( aver);
}
例 8.11 数组 score内放 10个学生成绩,求平均成绩数组名作参数,发生调用时只分配一个单元接收首地址,
不会重新建立数组
§ 8.7.3 多维数组名作函数参数一维数组名作参数时只需传递首地址,多维数组名作参数时,除传递首地址外,还要传递第二维及以后各维大小,否则,无法计算元素的地址例:求矩阵最大元素
max_value ( int array[][4],int m)
{ int i,j,k,max;
max =array[0][0];
for(i=0;i<m;i++)
for(j=0;j<4;j++)
if(array[i][j]>max)
max=array[i][j];
return(max);
} /*符号常量不能作形参!也不必作形参! */
作 业作业本,8.10 8.13(同时用递推和递归求解)
实验报告,8.11 8.14
要求:课下看课本,提前画 N-S图,上机据 N-S图写程序!
第九章 编译预处理命令
(1)宏定义,#define PI 3.14或 #define S(r) PI*r*r 直接替换若出现 S(a+b)则变成 PI*a+b*a+b,故常要用括号 PI*(r)*(r)
(2)文件包含,#include<stdio.h>或 #include,max.c”,文件插入
(3)条件编译:
#ifdef TurboC /*标识符或者表达式 */
#define INTEGER_SIZE 16
#else
#define INTEGER_SIZE 32
#endif
开头加 #define TurboC 1或# define TurboC均可
第一步理清解题思路,用伪代码描述清楚解题步骤 (自顶向下,
逐步细化 );第二步用 N-S图将算法准确地予以表示 (此时分析算法是否有错 ),第三步根据 N-S图上机调试 (调试语法是否有错 )并验证结果正确性 (不正确则看算法 )
关于字符与字符串输入的说明:
int i,j;
char c1,c2,ctemp;
char str1[20],str2[20];
/*以下语句执行结果与通常预期不同,注意测试 */
scanf("%d",&i);scanf("%c",&c1);printf("error1\n");
scanf("%c",&c1);scanf("%c",&c2);printf("error2\n");
scanf("%d",&i);gets(str1);printf("error3\n");
scanf("%c",&c1);gets(str1);printf("error4\n");
scanf("%s",str1);gets(str1);printf("error5\n");
/*以下形式的语句则能避免上述语句的问题 */
scanf("%c",&c1);scanf(" %c",&c2);printf("%c ok7\n",c2);
/*第二个 %c前有空格 */
scanf("%c",&c1);scanf("%s",&str1);printf("%s ok8\n",str1);
gets(str1);gets(str2);printf("ok9\n");
scanf("%d",&i);scanf("%c",&ctemp);scanf("%c",&c1);printf("ok10\n");
第八章本章要点:
8.1 什么是函数,为什么用函数?
8.2-8.4 如何定义函数,函数工作原理如何?
8.8 局部变量与全局变量
8.9/8.10 内部函数与外部函数,变量存储类别函数的嵌套调用、递归调用与数组作函数参数
§ 8.1概述 --什么是函数,为什么用函数?
编程求解复杂问题时通常把整个程序划分为若干功能较为单一的程序模块,然后分别予以实现,最后再把所有的程序模块像搭积木一样装配起来,这种在程序设计中分而治之的策略,被称为 模块化 程序设计方法
C语言把每个模块都编写成一个 C函数,然后通过主函数调用这些功能相对独立的模块从而实现大型问题的求解。
这样,一方面可以 使程序设计简单直观,提高了程序的易读性和可维护性 ;另一方面可以 把常用的一些计算或操作编成通用的函数供随时调用,这样可以大大地减轻程序员的代码工作量 。
void main()
{
int i;
while(1)
{
welcome();
scanf("%d",&i);
if(i==1)
huiwen ();
else if(i==2)
erfen();
else if(i==3)
diedai();
else if(i==4)
diamond();
else if(i==5)
break;
else
printf(“输入有误 !重新输入 ");
}
}
/*函数 welcome用以输出一个欢迎界面 */
void welcome()
{
printf("使用菜单选择趣味程序 \n");
printf(" 1---求某范围内的回文数 \n");
printf(" 2---二分法求一元二次方程根 \n");
printf(" 3---牛顿迭代法求一元三次方程根 \n");
printf(" 4---输出菱形图 \n");
printf(" 5---退出 \n");
printf("***************************************\n");
}
/*函数 huiwen用以输入两个正整数,求两数之间的回文数 */
void huiwen()
{
函数声明部分函数执行部分
}
程序从 main函数开始执行,它可以调用其它函数,但不能被别的函数所调用,main
函数之外的函数相互之间可以调用,此外,函数是平行的,不能嵌套定义从用户使用角度看,函数分 标准函数
( 库函数)和 用户自定义函数 ; 从函数形式看,
函数分 无参函数 和 有参函数函数说明与分类:
§ 8.2函数的定义形式类型标识符 函数名( 形参及其类型 )
{
声明部分语句部分
}
int max( int x,int y)
{ int z;
z=x>y?x ∶ y;
return(z);
}
定义函数时要用
,类型标识符,指定函数返回值的类型,默认为 int型
§ 8.3函数工作原理
8.3,1形式参数 /实际参数 /函数返回值定义函数时函数头部括弧中的变量称为,
形式参数,;发生调用时,调用语句中函数名后括弧内的参数称为,实际参数,;函数体内 return后括弧中的值称 函数返回值
int max(int x,int y )
{
int z;
z=x>y? x ∶ y;
return( z ) ;
}
void main ( )
{
int a,b;
scanf(“%d%d”,&a,&b);
c=max ( a,b ) ;
}
说明:
(1) 形参只有在发生函数调用时,才被分配内存单元 ;在调用结束后,形参所占的内存单元即被释放,考虑两次调用 max函数的情况
(2) 发生调用时将实参的值传递给形参,实参是常量、变量或表达式均可,如:
max(3,a+b);
(4) 实参与形参的类型应相同或赋值兼容
(5)在C语言中,实参向对形参的数据传递是
,值传递,,单向传递,只由实参传给形参,
而不能由形参传回来给实参,形参变量的改变不影响实参的取值,通常 通过函数返回值带回信息 。如两实参变量值的互换目前无法用函数实现,因为在内存中,实参单元与形参单元是不同的单元。
8.3.2( 3) 定义函数时指定的函数类型一般应和
return语句中的表达式类型一致,若不一致,则以函数类型为准进行类型转换补充,一旦遇到 return语句则函数停止执行并返回例 8.3 返回值类型与函数类型不同
# include <stdio.h>
void main()
{ int max( float x,float y) ;
float a,b;
int c;
scanf("%f,%f,",&a,&b);
c=max(a,b);
printf("Max is %d\n",c);
}
int max( float x,float y)
{ float z;
z=x>y?x ∶ y;
return(z);
}
运行情况如下:
1.5,2.5 ↙
Max is 2
/*若将 c改为浮点型? */
§ 8.4 函数的调用
8.4,1 函数调用的一般形式形式,函数名 (实参表列)
即使无参括弧也不能省参数间用逗号隔开对实参求值的顺序并不是确定的,如 f(i,++i)。应避免歧义的发生,如用 j=++i;f(i,j);
§ 8.4,2函数调用的方式
1.函数语句,如 printstar( ),不要求函数带回值,只要求函数完成一定的操作
2.函数表达式,如 c=2 *max(a,b); 要求函数带回一个确定的值,并参加表达式的运算
3.函数参数,函数调用作为实参。如
m=max (a,max ( b,c ) )
§ 8.4,3对被调用函数的声明和函数原型§ 4 3对被调用函数的声明和函数原型如使用库函数,应用#include命令将用到的信息“包含”到本文件中,如使用自定义函数,
而该函数的位置在主调函数的后面则应 对被调用的函数作声明,这种在主调函数中的声明称为 函数原型形式:
float add(float x,float y);
float add(float,float);
/*注意 P165形式( 2)错 */
§ 8.8局部变量和全局变量
§ 8.8.1局部变量在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,在此函数以外是不能使用这些变量的,这称为“局部变量”。
float f1( int a)/*形参只在 f1内有效 */
{int b,c;
… /* 形参 a及 b c在 f1内有效,调用时分配空间,返回时释放空间 */
}
void main( )
{int b,m,n; /*b,m,n在主函数内 有效
… 调用子函数时无效 */
}
(1) 主函数中定义的变量也只在主函数中有效,主函数也不能使用其他函数中定义的变量。
(2) 不同函数中可以使用相同名字的变量,它们代表不同的对象,互不干扰
(3) 形式参数也是局部变量。例如上面 f1函数中的形参 a,也只在 f1函数中有效。
(4) 在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为
“分程序”或“程序块”。
说明
void main ( )
{int a,b;
…
{int c;
c=a+b; /* c只在此复合语句内有效,而 a,b在整个 main()有效 */
…
}
…
}
§ 8.8.2 全局变量在函数之外定义的变量称为 外部变量,外部变量是全局变量 (也称全程变量 )。全局变量有效范围是从定义位置开始到本源文件结束说明:全局变量增强了函数间的数据联系,但影响函数间的独立性,不提倡例 8.15 有一个一维数组,内放10个学生成绩,写一个函数,求出平均分、最高分和最低分。
#include <stdio.h>
float Max=0,Min=0; /*全局变量,首字母大写 */
void main()
{ float average( float array[ ],int n) ;
float ave,score[10];
int i;
for(i=0;i<10;i++)
scanf( ″%f ″,&score[i]);
ave= average(score,10);
printf(“max=%6.2f \ nmin=%6.2f\ n
average=%6.2f\ n“,Max,Min,ave);
}
float average( float array[ ],int n)
/ * 定义函数,形参为数组 */
{ int i;
float aver,sum=array[0];
Max=Min=array[0];
for(i =1;i<n;i++)
{ if( array[i]> Max) Max= array[i];
else if( array[i]< Min) Min= array[i];
sum=sum+array[i];
}
aver=sum/n;
return(aver);
}
例 8.16外部变量与局部变量同名的处理:
在局部变量的作用范围内,外部变量被屏蔽
#include <stdio.h>
int a=3,b=5; /* a,b为外部变量 */
void main ( )
{ int a=8; /*a为局部变量 */
printf (″%d″,max (a,b));
}
max (int a,int b) /*a,b为局部变量 */
{ int c;
c=a> b?a∶ b; return (c);
}
§ 8.10 内部函数和外部函数
§ 8.10.1内部函数如果一个函数 只能被本文件中其他函数所调用,它称为内部函数 。在定义内部函数时,在函数名和函数类型的前面加 static。即
static 类型标识符 函数名 (形参表 )
如 static int fun ( int a,int b )
作用:避免冲突
§ 8.10.2外部函数能被其它文件调用的函数称为外部函数
(1)形式:
extern int fun (int a,int b)
extern可省略,隐含即为外部函数
(2) 在需调用此函数的文件中,要用 extern对函数作声明,表示该函数是在其他文件中定义的外部函数,extern也可省略例 8.22 有一个字符串,内有若干个字符,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现
file1.c
#include <stdio.h>
void main()
{ extern void enter_string(char str[]);
extern void detele_string(char str[],char ch);
extern void print_string(char str[]);
char c;
char str[80];
enter_string(str);
scanf("%c",&c);
detele_string(str,c);
print_string(str);
}
file2.c
#include <stdio.h>
void enter_string(char str[80])
{ gets(str); }
file3.c
void delete_string(char str[],char ch)
{ int i,j;
for(i=j=0;str[i]!='\0';i++)
if(str[i]!=ch) str[j++]=str[i];/*注意该技巧 */
str[i]='\0';
}
file4.c
#include <stdio.h>
void print_string(char str[])
{ printf("%s\n",str);}
§ 8.9 变量的存储类别
§ 8.9,1 动态存储方式与静态存储方式根据变量的作用域(即从空间)角度分 全局变量 和局部变量 。从变量值存在的时间(即生存期)又可分为 静态存储方式 和 动态存储方式类似全局变量,由系统分配固定的存储空间,直至整个程序执行完毕才释放,这称为 静态存储方式,
这些数据放在内存的 静态存储区 。
类似形参在子函数调用时分配空间,而子函数结束时释放空间的存储方式称 动态存储方式 ;这些数据放在 动态存储区定义变量时可指定存储类别,
存储类别 数据类型 变量名局部变量默认或用 auto声明,如 auto int b,c=3; 动态用 static声明,如 static int b,c=3;编译时赋初值,静态用 register声明,如 register long i;自动处理,动态全局变量默认:作用域从定义处始到 本文件 结束止,静态若 作用域外 用,需 extern作外部变量声明,静态用 static声明外部变量,则该变量只在本文件能用,
静态,如 static int A
例 8.18静态局部变量使用举例 输出1到5的阶乘值。
#include <stdio.h>
void main()
{ int fac( int n) ;
int i;
for(i=1;i<=5;i++)
printf( ″%d! =%d\n ″,i,fac(i));
}
int fac( int n)
{ static int f=1 ;/*静态局部变量,编译时赋初值 */
f=f *n;
return(f);
}
作 业作业,8.1 8.3 8.16之 N-S图实验报告,8.2 8.10 8.18之 N-S图如何提高编程能力 (以求鞍点为例 ):
第一步理清解题思路,用伪代码描述清楚解题步骤 (自顶向下,
逐步细化 );第二步用 N-S图将算法准确地予以表示 (此时分析算法是否有错 );第三步根据 N-S图上机调试 (调试语法是否有错 )并验证结果正确性 (不正确则重新看 N-S
图分析算法 )
关于字符与字符串输入的说明
int i,j;char c1,c2,ctemp;char str1[20],str2[20];
/*以下语句执行结果与通常预期不同,注意测试,因为回车会被当作第二个输入语句的输入加以接收 */
scanf("%d",&i);scanf("%c",&c1);printf("error1\n");
scanf("%c",&c1);scanf("%c",&c2);printf("error2\n");
scanf("%d",&i);gets(str1);printf("error3\n");
scanf("%c",&c1);gets(str1);printf("error4\n");
scanf("%s",str1);gets(str1);printf("error5\n");
/*以下形式的语句则能避免上述语句的问题,注意分析测试 */
scanf("%c",&c1);scanf(" %c",&c2);printf("%c ok7\n",c2);/*第二个
%c前有空格 */
scanf("%c",&c1);scanf("%s",&str1);printf("%s ok8\n",str1);
gets(str1);gets(str2);printf("ok9\n");
scanf("%d",&i);scanf("%c",&ctemp);scanf("%c",&c1);printf("ok\n");
第八章作业提示
(1)定义 时函数头要写全,如 int f(int x,int y),其后不能有分号 ;声明 时函数形参的类型可以省略,如 int f(int,int)或 int f(int x,int y)均可,且其后必须有分号; 调用 函数时给出函数名和实参即可,如 f(a,3),不能写 int f(int a,int 3)
float f1(float a,float b,float c);float f2(float a,float b,float c);
float f3(float a,float b,float c);
void main(){float a,bloat b,float c;f1(a,b,c); f1(a,b,c) ;f1(a,b,c);}
(2)函数内部定义的变量( 局部变量 )只在本函数内有效,函数外定义的变量( 全局变量 )在定义位置后的各个函数都有效,不同函数中的 局部变量可以重名,各自在其定义的函数内有效;全局变量与局部变量重名时,
在局部变量所在函数内,局部变量有效第八章作业提示
(3)函数应包含几个参数由函数 完成其功能需要接收几个值决定,如定义子函数求两个数的最大公约数,显然只需知道这两个数是多少,故需两个形参来接收这两个值;函数 返回值只能有一个或没有 。 如求一元二次方程的根,若有两个不等的实根,则目前无法利用子函数一次返回两个值,有两种处理方法,其一,将 x1与 x2定义为全局变量,此时不需要返回值,
因子函数中的 x1与 x2与主函数中的 x1与 x2指的是同一个变量,只要在子函数为两者赋值,主函数中也相应改变,故函数返回值类型可为空 ;其二,
不用全局变量,直接在子函数中将两个根求出并 输出,这样也不需返回值
(4)当程序含有多个函数时,每个函数画一个 N-S图,子函数前说明函数作用并给出函数头部,发生调用的语句对应框中直接写调用语句,如
,x=gcd(a,45)”,再如 f(a,b)
§ 8.5 函数的嵌套调用例 6弦截法求方程 x3-5x2+16x-80= 0根
(1)主函数,输入合理区间,调用 root函数求根
y= x3+16x
return(y)
x0=x1+(-f(x1)*(x2-x1))/(f(x2)-f(x1))
return(x0)
(2)求函数值子函数 float f(float x)
(3)求区间 (x1,x2)的实根子函数
float root (float x1,float x2)
(4) 求 弦截点子 函数
float xpoint (float x1,float x2)
while(fabs(y0)>1e-6)
return(x0)
y1*y0>0Y N
x1=x0,y1=y0 x2=x0,y2=y0
x0=xpoint (x1,x2),y0=f(x0)
直到 y1*y2<0
y1=f(x1),y2=f(x2)
输入 x1与 x2
x0= root(x1,x2)
输出 x0
8.6函数的递归调用
:参考递归课件
§ 8.7数组作函数参数
§ 8.7.1 数组元素作函数参数 void main{
int a[2]={0,1};
exchange(a[0],a[1]);
pintf(“%d %d”,a[0],a[1]);
}
void exchange(int x;int y)
{ int tmp;
tmp=x;
x=y;
y=tmp;
} /*莫忘声明! */
数组元素作参数是将 数组元素的值 传递到形参对应的内存空间中,
之后操作是对形参对应单元的数值进行,故原来的数组内容不变;
实参是数组某元素,如 a[i],形参是普通变量,如 int x;
§ 8.7.2 数组名作函数参数数组名作参数是将 数组名的值 ( 即数组首地址 ) 传递到形参对应的单元中,从而形参的值就是原数组的首地址,之后通过形参进行操作实际就是通过原数组的首地址进行操作,从而原数组的内容改变,此时形参是类似数组名的变量,能接收地址,如 int a[];实参是数组名,如 a
float average ( float array[],int n)
{ int i;
float aver,sum=0;
for (i= 0;i<10;i++ )
sum +=array[i];
aver=sum/10;
return( aver);
}
例 8.11 数组 score内放 10个学生成绩,求平均成绩数组名作参数,发生调用时只分配一个单元接收首地址,
不会重新建立数组
§ 8.7.3 多维数组名作函数参数一维数组名作参数时只需传递首地址,多维数组名作参数时,除传递首地址外,还要传递第二维及以后各维大小,否则,无法计算元素的地址例:求矩阵最大元素
max_value ( int array[][4],int m)
{ int i,j,k,max;
max =array[0][0];
for(i=0;i<m;i++)
for(j=0;j<4;j++)
if(array[i][j]>max)
max=array[i][j];
return(max);
} /*符号常量不能作形参!也不必作形参! */
作 业作业本,8.10 8.13(同时用递推和递归求解)
实验报告,8.11 8.14
要求:课下看课本,提前画 N-S图,上机据 N-S图写程序!
第九章 编译预处理命令
(1)宏定义,#define PI 3.14或 #define S(r) PI*r*r 直接替换若出现 S(a+b)则变成 PI*a+b*a+b,故常要用括号 PI*(r)*(r)
(2)文件包含,#include<stdio.h>或 #include,max.c”,文件插入
(3)条件编译:
#ifdef TurboC /*标识符或者表达式 */
#define INTEGER_SIZE 16
#else
#define INTEGER_SIZE 32
#endif
开头加 #define TurboC 1或# define TurboC均可