printf(“\\n mmm”,n,m,p); //提倡使用的语句 第一行输出是: 102030
第二行输出是: 10 20 30
2. 在输入语句scanf()之前先使用printf()输出提示信息,但是在printf()最后不能使用换
行符。
int x;
printf(“\\n x=?”); //句尾不应使用换行符
scanf( “%d”,&x);
这样使光标与提示信息出现在同一行上,光标停在问号后边:X=?□ 。
3. 在该换行的地方,要及时换行。
int i;
printf(“数据输出如下:\\n”); // 需要换行
for (i=0; i<8; i++) printf(“m”, i ); // 几个数据在同一行输出,不能换行
4. 在调试程序时多加几个输出语句,以便监视中间运行状况。程序调式成功后,再去掉这些辅助输出语句。
二、函数与参数传递
函数的设计和调用是程序设计必不可少的技能,是程序设计最重要的基础。一些初学者之之所以感到编程难,就是忽视了这个基础。在传统的面向过程的程序设计中,往往提倡模块化结构化程序设计,不论BASIC、 FONFTRAN、PASCAL还是其他高级语言,最终要涉及到子函数的设计和使用。
C语言的源程序是由一个主函数和若干(或零个)子函数构成,函数是组成C语言程序的基本单位。函数具有相对独立的功能,可以被其他函数调用,也可调用其他函数。当函数直接或间接的调用自身时,这样的函数称为递归函数。
是否能够熟练的设计和使用函数,是体现一个人程序设计能力高低的基本条件。因此有必要回顾和复习C语言函数的基本概念。
1函数的设计
函数设计的一般格式是:
类型名 函数名(形参表)
{ 函数体;}
函数设计一般是处理一些数据获得某个结果,因此函数可以具有返回值,上面的类型名就是函数返回值的类型,可以是int, float…..等。例如:
float funx(形参表){ 函数体;.} 函数也可无返回值,此时类型是void。例如:
void funy(形参表){ 函数体;}
而函数体内所需处理的数据往往通过形参表传送,函数也可以不设形参表,此时写为:
类型名 函数名(void){ 函数体;}
例1.2 设计一个函数计算三个整数之和,再设计一个函数仅输出一条线。设计主函数调用两个函数。
6
#include
int sumx (int a, int b, int c) /* 计算三个整数之和的函数 */
{ int s; s=a+b+c; return s;
}
void display(void) /* 输出一条线的函数 */ { printf(”----------------------\\n“); } void main( )
{ int x,y, z ,sa; x=y=z=2;
display(); /* 画一条线 */ printf(“\\n sum=%d”,sumx(x,y,z)); /* 在输出语句中直接调用函数sumx( ) */ printf(“\\n mmm”,x,y,z); display(); x=5; y=6; z=7;
sa=sumx(x, y, z); /* 在赋值语句中调用函数sumx( ) */ printf(“\\n “ sum=%d”,sa); printf(“\\n mmm”,x,y,z); display();
} /* 程序结束 */
运行结果: ---------------------- sum= 6
2 2 2 ---------------------- sum=48
15 16 17
----------------------
2. 关于函数的参数传递
函数在被调用时,由主调程序提供实参,将信息传递给形参。在调用结束后,有时形参可以返回新的数据给主调程序。这就是所谓参数传递。各种算法语言实现参数传递的方法通常分为传值和传址两大类。
在上例中函数sumx()的设计和主函数对它的调用,就是传值调用。第一、第二次调用,带入的实参均是三个整型变量。调用函数返回后,在主程序中输出实参的值仍与调用之前相同。传值调用的主要特点是数据的单向传递,由实参通过形参将数据代入被调用函数,不论在调用期间形参值是否改变,调用结束返回主调函数之后,实参值都不会改变。 在不同的算法语言中,传址调用的语法有所不同。在PASCAL语言中用变参实现传址。
7
在C语言中采用指针变量做形参来实现传址。传址调用的主要特点是可以实现数据双向传递,在调用时实参将地址传给形参,该地址中的数据代入被调用函数。如果在调用期间形参值被改变,也即该地址中的数据发生变化,调用结束返回主调函数之后,实参地址仍然不变,但是该地址中的数据发生相应改变。这就是数据的双向传递。现看一例题: 例1.3 设计一个函数实现两个数据的交换,在主程序中调用。
#include
viod swap( int *a, int *b) ; /* 函数原型声明 */ void main( )
{ int x=100, y=800;
printf(“\\n mm”, x, y); /* 输出原始数据 */
swap(&x, &y); /* 调用交换数据的函数swap() */ printf(“\\n mm”, x ,y); /* 输出交换后的数据 */ }
viod swap( int *a, int *b) { int c;
c=*a; *a = *b; *b=c; } 运行结果: 100
800
800 100
实践证明x,y 的数据在调用函数前后发生了交换变化。形参是指向整形的指针变量a和b,在函数体内需要交换的是指针所指的存储单元的内容,因此使用*a = *b;这样的写法。在调用时,要求实参个数、类型位置与形参一致。因为实参应该是指针地址,所以调用语句swap(&x, &y)中,实参&x,和& y代入的是整型变量x,y的地址。在函数体内交换的是实参地址中的内容,而作为主函数变量x,y的地址仍然没有改变。从整数交换的角度看,本例题实现了双向数据传递。若从指针地址角度看,调用前后指针地址不变。
现在回过头来看P5页[复数ADT实现的面向过程C语言源程序]的创建复数的函数:
void creat(complex *c){ …….; c->x=x1; c->y=y1;}
在函数体中人们容易认识和习惯的写法c.x和c.y,也必须写成c->x和c->y。在调用该函数时,还必须将结构体变量a求地址做实参:creat(&a)。初学者应该特别注意这一点。
如果需要在函数体中改变指针的地址,这就需要在原指针基础之上再加一级指针:
void funz( int **a){ /* 改变*a */ …}
函数调用返回后**a仍然不变,而*a发生了变化。由此可以看出C语言的传址调用比较复杂。不如PASCAL的变量参数简便,也不如C++的引用调用方便。
三、 结构体及运用
数据结构课程所研究的问题均运用到“结构体”。在C语言中结构体的定义、输入/输出是数据结构程序设计的重要语法基础。定义结构体的一般格式:
struct 结构体类型名
8
{ 类型名1 变量名1; //数据子域
类型名2 变量名2;……
类型名n 变量名n; };
其中struct是保留字。结构体类型名由用户自己命名。在使用时必须声明一个具体的结构体类型的变量,声明创建一个结构体变量的方法是: struct 结构体类型名 结构体变量名; 例如: struct ElemType /* 定义结构体 */
{ int num; char name[10]; } ;
struct ElemType x; /* 声明结构体变量x */
另外有一种方法使用typedef 语句定义结构体,在声明结构体变量时可以不写struct,使得书写更加简便。例如:
typedef struct
{ int num;
char name[10]; } ElemType;
ElemType就是一个新的类型名,并且是结构体类型名。声明变量x的语句是:
ElemType x;
一个结构体中可以包含多个数据子域。数据子域的类型名一般指基本数据类型(int char 等),也可是已经定义的另一结构体名。数据子域变量名可以是简单变量,也可以是数组。它们也可以称为结构体的数据成员。
通过“结构体变量名.数据子域” 可以访问数据子域。 例1.6 设计Student结构体,在主程序中运用。
#include
#include
typedef struct /* 定义结构体Student */
{ long num; /* 学号 */ int x; /* 成绩 */ char name[10]; /* 姓名 */
} Student; void main( )
{ Student s1; /* 声明创建一个结构体变量s1 */
s1.num=1001 ; /* 为s1的数据子域提供数据 */ s1. x=83; strcpy( s1.name, “ 李 明”);
printf( “\\n 姓名: %s”, s1.name); /* 输出结构体变量s1 的内容 */ printf( “\\n 学号: %d”, s1.num); printf( “\\n 成绩: %d”, s1.x);
9
}
或者使用键盘输入: { scanf(“%d”, s1.num);
scanf(“%d”, s1.x); scanf(“%s”, s1.name);
}
还可以通过“结构体指针->数据子域” 来访问数据域。在实际问题中还会使用到指向结构体的指针,通过以下语句段可以说明结构体指针的一般用法。
{ Student *p; /* 声明指针变量p */
p=( Student *)malloc(sizeof( Student)); /* 分配存储单元,首地址赋给p指针 */ p->num=101; p->x=83; strcpy( p->name, “李 明 ”); printf(“\\n smm”,p->name,p->num,p->x);
}
设计一个一维数组,每个数组元素是Student结构体类型,通过以下语句段可以说明结构体数组的一般用法。可以通过“结构体数组名[下标].数据子域”访问数据域。
{ Student a[5]; /* 声明创建一个结构体数组a */
int i ;
for( i=0, i<5, i++){
printf(“\\n 学号:%d”,a[i].num) ;
printf(“\\n 姓名:%s”,a[i].name) ; printf(“\\n 成绩:%d”,a[i].x) ;
}
}
以上是关于结构体的基本概念和简单运用。
10