递归程序设计:
适用范围:操作步骤类型不多,有重复的要求,但重复步骤不尽相同,很难描述出明确的重复性规律,难以用递推法循环实现。此时,就选择递归法,使用递归函数解决。
递归的两个关键点:递归出口和递归调用式子。
函数递归调用的两种形式:
(1)直接递归调用:
int f(int x){
int y;
...
y=f(x-1)
...
return y;
}
(2)间接递归调用:
int f(int x){
int y;
...
y=g(x)
...
return y;
}
int g(x){
int z;
...
z=f(x-1)
...
return z;
}
用递归函数求1+2+.....+n.
#include<stdio.h>
int fact(int n);
int main()
{
int n;
printf("Enter n:");
scanf("%d",&n);
printf("Number of sum is %d\n",fact(n));
return 0;
}
int fact(int n){
if(n<1){
return 0;
}else{
return n+fact(n-1);
}
}
用递归函数求两整数最大公约数
#include<stdio.h>
int gcd(int m,int n);
int main()
{
int m,n;
printf("Enter m,n:");
scanf("%d %d",&m,&n);
gcd(m,n);
printf("%d",n);
}
int gcd(int m,int n){
if(m%n==0){
return 0;
}else{
return gcd(n,m%n);
}
}
函数的嵌套调用:归根到底就是通过嵌套函数把复杂的问题细分,简单化,交给不同函数处理
(1)限时函数长度
(2)避免函数之间功能的重复
(3)减少全局变量的使用(丰田汽车案例是个惨痛的教训)
用嵌套函数设计有序表操作(这个源程序有一点问题,如果有人知道可以找出来)
/*有序表的操作*/
#include<stdio.h>
#define MAXN 100
int count=0; /*用全局变量表示count表示数组a中待处理的元素个数*/
void select(int a[],int option,int value); /*决定对有序数组a进行何种操作的控制函数*/
void input_array(int a[]); /*输出数组a的函数*/
void print_array(int a[]); /*输入....*/
void insert(int a[],int value); /*插入一个值为value的元素*/
void delete(int a[],int value); /*删除....*/
void query(int a[],int value); /*使用二分法在有序数组a中查找元素value的函数*/
int main(void)
{
int option,value,a[MAXN];
input_array(a); /*调用函数输入数组a*/
/*菜单*/
printf("[1] Insert\n");
printf("[2] Remove\n");
printf("[3] Query\n");
printf("[Other option]end\n");
while(1){
printf("Enter option:"); /*输入编号*/
scanf("%d",&option);
if(option<1||option>3){
break;
}
printf("Input value:"); /*输入参数*/
scanf("%d",&value);
select(a,option,value); /*调用控制函数*/
printf("\n");
}
printf("Thanks.\n");
return 0;
}
/*控制函数*/
void select(int a[],int option,int value){
switch(option){
case1:
insert(a,value);
break;
case2:
delete(a,value);
break;
case3:
query(a,value);
break;
}
}
/*有序表输入函数*/
void input_array(int a[]){
int i;
printf("Input the number of array elementa:");
scanf("%d",&count);
printf("Input an ordered array element:");
for(i=0;i<count;i++){
scanf("%d",&a[i]);
}
}
/*有序表输出函数*/
void print_array(int a[]){
int i;
printf("The ordered array a is:");
for(i=0;i<count;i++){ /*输出时相邻数字用一个空格分开,行末无空格*/
printf("%d",a[i]);
}
}
/*有序表插入函数*/
void insert(int a[],int value){
int i,j;
for(i=0;i<count;i++){ /*定位:找到待插入的位置,即退出循环时i的值*/
if(value<a[i]){
break;
}
}
for(j=count-1;j>=i;j--){ /*腾位:将a[i]-a[count-1]向后顺移一位*/
a[j+1]=a[j];
}
a[i]=value;
count++;
print_array(a);
}
/*有序表删除函数*/
void delete(int a[],int value){
int i,index=1;
for(i=0;i<count;i++){ /*定位:如果找到待删除的元素,用index记录其下标*/
if(value==a[i]){
index=i;
break;
}
}
if(index==-1){
printf("Failed to find the data,deletion failed.");
}else{
for(i=index;i<count-1;i++){ /*将a[count-1]-a[index+1]向前移一位*/
a[i]=a[i+1];
}
}
count--;
print_array(a);
}
/*有序表二分法查询函数*/
void query(int a[],int value){
int mid,left=0,right=count-1;
while(left<right){
mid=(left+right)/2;
if(value==a[mid]){
printf("The index is:%d",mid);
return;
}else if(value<a[mid]){
right=mid-1;
}else{
left=mid+1;
}
}
printf("This element does not exist.");
}
宏定义#define
宏定义的格式:
#define 宏名 宏定义字符串
宏允许嵌套定义。
宏定义结束末尾不能加 ‘ ;’
宏的用途:
(1)符号常量,如 : PI ,数组大小定义。用来增加程序的灵活性,可读性。
(2)简单的函数功能实现。
(3)当程序需要多次书写一些相同内容时,将它简写为宏。
如:#define MAXN "It has 100 \
value."
printf(MAXN);
其中的 \ 表示该行未结束,与下一行连接。
注意:宏的引用方式和函数调用的实现过程完全不相同。
.h 文件通常被称为头文件。除了像stdio.h等系统的头文件,也可以自己编写头文件。
将长度转换的宏定义成头文件 length.h ,并写出主函数文件:
/*头文件 length.h 源程序*/
#define Mile_to_meter 1609
#define Foot_to_centimeter 30.48
#define Inch_to_centimeter 2.54
/*主函数文件 prog.c 源程序*/
#include<stdio.h>
#include "length.h"
int main(void)
{
...
}
常用标准头文件
字符处理 | ctype.h |
与数学处理函数有关的说明与定义 | math.h |
输入输出函数中使用的有关说明与定义 | stdio.h |
字符串函数的有关说明和定义 | string.h |
定义某些常用内容 | stddef.h |
杂项说明 | stdlib.h |
支持系统时间函数 | time.h |
编译预处理:
这里只讲条件编译,一般的程序经过编译后,所有的C语句都生成到目标程序中,如果只想把源程序中的一部分语句生成目标代码,可以使用条件编译。
条件编译运用广泛,可以为一个程序提供不同版本,不同的用户使用不同的版本,
例如:
#define FLAG 1
#if FLAG
程序段1
#else
程序段2
#endif
/*用带参宏实现输出三个数中最大的数*/
#include<stdio.h>
#define max(a,b,c) (a>b?a:b)>c?(a>b?a:b):c
int main()
{
double a,b,c;
printf("Enter a,b,c:");
scanf("%lf %lf %lf",&a,&b,&c);
printf("%.2f",max(a,b,c));
return 0;
}
“?:”是一个三目运算符(唯一的)
?的前面是一个逻辑语句,?和:之间表示语句为真时的值,:后面是语句不成立的值。
条件编译指令均以 # 开头,其意义与C语言中的 if - else 语句完全不同,if - else 语句两个分支程序段都会被生成到目标代码1中,由程序运行时根据条件决定执行哪一段,而条件编译的另一段会被舍弃。#if 的条件只能是宏名,不能是程序表达式,因为在编译预处理时是无法计算表达式的。
采用条件编译的好处:
(1)目标代码精简,不包含无关代码。
(2)系统代码保护性强
这是转载的:
#define 定义一个预处理宏
#undef 取消一个预处理宏
#ifdef 判断某个预处理宏是否被定义,若定义则编译后续程序段
#ifndef 判断某个预处理宏是否没有被定义,若没定义则编译后续程序段
#if 判断某个预处理宏的值是否不为0,不为0则编译后续程序段,相当于C语法中的if语句
#elif 相当于C语法中的else if 与#if配套使用
#else 相当于C语法中的else 与#if、#elif配合使用
#endif' 结束条件命令的判断,与#if、#ifdef、#ifndef配套使用
程序文件模块:
首先应明白程序 ,程序文件模块 与函数之间的关系:一个大程序可由几个程序文件模块组成,每一个程序文件模块又可能包含若干个函数。
文件模块间的通信:
外部变量:全局变量在整个程序所有的文件模块中起作用,如果在每一个文件模块中都定义一次全局变量,模块单独编译时不会发生错误,一旦把各模块连接一起时,就会产生对同一全局变量多次定义的错误。全局变量只能在某一模块定义一次,其他模块要使用需要通过外部变量的声明。
其格式为:
extern 类型名 变量名表;
静态全局变量:当程序由多个文件模块构成时,静态全局变量用于限时全局变量作用域的扩展,即不影响其他不相关的文件模块。即使其他文件使用外部变量声明,也不能使用该变量。
对于函数也是同样的道理:调用外部函数时用 extern 声明,同样的,也可以把函数设为静态函数,静态函数的定义格式为:static 函数类型 函数名(参数表说明);