C语言程序设计基础
前言
今天终于把这个笔记弄完了。再整理笔记期间经历了几次危机——文档丢失,数据出错等等,甚至一度不想写这个了,还是感谢d2hoDQo=,这个笔记是整理了大一所学习的一些知识,以及结合了老师上课所讲制作的,希望能帮助大家。不足的地方希望指出。
后续还会进行一些补充。。。
第1章 c语言编程
1.1 课程地位


1.1.1 C语言能用来做什么?

1.2 如何学好C语言
-
了解C语言的运行环境。 -
熟悉关键字的使用语法。 -
掌握各种解决问题的手段或方法。 -
反复练习动手,从中反馈。 -
学会做梦。
1.2.1 课程目标
- 理解算法、流程图以及程序的概念
- 理解程序逻辑
- 掌握用C语言进行程序设计的基本方法。
- 掌握C语言的基础知识,包括基本数据类型、表达式、控制结构等
- 掌握C语言的高级知识,包括数组、指针、函数、字符串、结构等
1.3 什么是程序
- 程序一词来自生活,通常指完成某些事务的一种既定方式和过程
- 在日常生活中,可以将程序看成对一系列动作的执行过程的描述
1.3.1 日常生活中的程序

1.3.2 计算机中的程序

程序:为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合
1.4 C 语言简介
- C 语言是贝尔实验室的 Dennis Ritchie 在1973年设计的。
- C 最初用于开发系统级程序。
- 在微机上,有许多性能良好的商品C 语言系统可用。包括Turbo C、Borland C/C++;Microsoft Visual C/C++ 等。
1.4.1 特点
结构化的程序设计语言:层次清晰,便于按模块化方式组织程序,易于调试和维护
语句简洁:学习时入门相对容易,C 语言很好地总结了其他语言提出的程序库概念
功能强大:既可用于系统软件的开发,也适合于应用软件的开发。
移植性好:只要对这种语言稍加修改,便可以适应不同型号机器或各类操作系统。
1.4.2 C语言发展历史

机器语言:CPU指令系统,由0、1序列构成的指令码组成
如:10000000 加
? 10010000 减
汇编语言:用助记符号描述的指令系统,可进行地址、位操作
如 ADD A, B
编写系统软件,直接对硬件操作,可读性,移植性差
高级语言:可读性,移植性好,编写应用程序一般较难实现汇编语言的某些功能
如:地址和位的操作
C语言兼有高级和低级语言的功能适合写系统软件和应用软件又称中级语言
1.4.3 C 程序的基本结构
#include <stdio.h>
void main()
{
printf("Hello World\n");
}
以**#**开始的语句称为预处理器指令
#include语句不是必需的,但是,如果程序有该语句,就必须将它放在程序的开始处
以==.h为后缀的文件被称为头文件==,可以是 C 程序中现成的标准库文件,也可以是自定义的库文件。
**stdio.h**文件中包含了有关输入输出语句的函数
main() 函数是 C 程序处理的**起点**
main() 函数可以返回一个值,也可以不返回值。如果某个函数没有返回值,那么在它的前面有一个关键字 **void**
它表示函数的开始,后面是函数的主体
在函数定义的后面有一个左大括号,即**{**
大括号也可以用于将语句块括起来
在函数定义的结尾处有一个右大括号,即 }
在屏幕上产生一行输出**“Hello world”**,并换行(\n)
函数主体中的每个语句都**以分号结束**。
C 程序中的一个语句可以跨越多行,并且用分号通知编译器该语句已结束。
1.4.4 C 程序中的注释
#include <stdio.h>
void main()
{
printf("Hello World\n");
}
C 程序可以包含注释,以便向读者作一般说明
编译器并不处理这些注释
在程序中添加注释是一个好的编程习惯,可以增强程序的可读性。
1.4.5 高级语言的编译和执行
高级语言程序
编译程序解释程序编译器解释器
机器代码
计算机硬件
高级语言的编译和执行
1.4.6 编译和执行C程序
C源程序
编译
目标文件
连接
可执行程序
C语言函数库
编译和执行C程序
源程序:是用户创建的文件,以==“.c”或者“.cpp”==为文件扩展名保存
目标文件:是编译器的输出结果。这类文件的常见扩展名为==“.o”或“.obj”==
可执行文件:是连接器的输出结果。可执行文件的扩展名为==“.exe”==
头文件:含有函数的声明和预处理语句,用于帮助访问外部定义的函数。头文件的扩展名为==“.h”==。
1.4.7 C程序的开发过程
分析问题
编制程序
编译
连接
调试运行
完成
C程序的开发过程
- 编译中发现错误,转回修改源程序
- 连接中发现错误,转回修改源程序
- 调试运行中发现问题,表明分析本身有错误,重新分析问题
1.5 Visual Studio IDE工具
- 为了方便程序开发,人们开发了一类称作IDE的软件
- Visual Studio是目前国内比较流行的一种C++语言源程序的编译系统,使用该系统也可以编辑和运行C语言的源程序
- 使用Microsoft Visual Studio可以创建控制台应用程序也可以创建Windows应用程序
- 用 Visual Studio创建的 C 程序被存储为一个独立工程
Microsoft Visio Studio 2008
下载地址
https://msdn.itellyou.cn/
 
安装过程
CSDN搜Visual Studio安装就会有
另外一个比较好的编辑工具:
Source Insight
学习用:Dev-C++
1.6 小结
- 算法就是解决问题的具体方法与步骤
- 流程图是算法的一种图形化表示方式
- 程序是为让计算机完成某项任务而编写的逐条执行的指令序列
- C语言的特点包括:结构化的程序设计语言、语句简洁、功能强大、移植性好
- C程序的基本结构包括:预处理语句、main函数,main函数中的内容使用{ }括起来,每条语句必须用分号结束
- C程序编写完成后,首先需要通过编译转换成目标文件,然后通过连接创建可执行程序,最后才可以执行该程序
- 可以使用Visual C++ 6.0 IDE编辑和运行C程序
第2章 变量和数据类型
2.1 回顾
- 程序是为执行一项任务而编写的有序指令集
- 算法是解决问题的具体方法和步骤
- 流程图是算法的图形化表现形式
- C语言的特点
- C程序的编译和运行过程
- 编译器将源程序转换成机器能理解的程序
- 连接器用于连接相关的目标文件以生成可执行程序
2.2 本章目标
- 理解变量和常量的含义
- 熟悉基本数据类型 int、char、float 和 double
- 使用算术运算符
- 理解类型转换
- 熟练使用 scanf() 和 printf() 函数
- 熟练使用 getchar() 和==putchar()==函数
2.3 C语言中的基本元素

2.3.1 常量
常量用于定义具有如下特点的数据:
- 在程序中保持不变
- 在程序内部频繁使用.
- 需要用比较简单的方式替代某些值
2.3.2 变量
- 编写程序时,常常需要将数据存储在内存中,方便后面使用这个数据或者修改这个数据的值。
- 通常使用变量来存储数据。使用变量可以引用存储在内存中的数据,并随时根据需要显示数据或执行数据操纵。
存储 Rate
10
将值存储为DiscAmt
0.5
将值存储为Result
9.5
Rate-DiscAmt
Rate * 5%
2.3.3 声明和使用变量
-
声明变量:Datatype variablename; -
定义时初始化变量:Datatype variablename = value; -
定义后初始化变量:variablename = value;
给变量赋值,除了给一个直接的值以外,还可以通过计算获得。
2.3.4 变量命名
变量的命名规则:
- 变量名可以由字母、数字和==__==(下划线)组合而成
- 变量名不能包含除 _ 以外的任何特殊字符,如:%、# 、逗号、空格等
- 变量名必须以字母或 _(下划线)开头
- 变量名不能包含空白字符(换行符、空格和制表符称为空白字符)
- C 语言中的某些词(例如 int 和 float 等)称为保留字,具有特殊意义,不能用作变量名
- C 语言区分大小写,因此变量 price 与变量 PRICE 是两个不同的变量
2.4 基本数据类型
数据类型
数值
非数值
整型
非整型
int
short int
long int
float
double
char
2.4.1 整型
名称 | 全称类型说明符 | 缩写类型说明符 | 位数 | 范围 |
---|
整型 | int | int | 16 | -32768 至 +32767 | 无符号整型 | unsigned int | unsigned | 16 | 0 至 65,535 | 短整型 | short int | short | 16 | -32768 至 +32767 | 无符号短整型 | unsigned short int | unsigned short | 16 | 0 至 65,535 | 长整型 | long int | long | 32 | -2,147,483,648 至 2,147,483,647 | 无符号长整型 | unsigned long int | unsigned long | 32 | 0 至 4,294,967,295 |
2.4.1.1 使用整型变量
声明:
int page_number;
long int population;
unsigned int age;
可按如下方式初始化:
page_number=0;
int max_marks = 100;
在同一语句中可以声明多个类型相同的变量
2.4.2 浮点型
名称 | 类型说明符 | 位数 | 范围 | 有效数字 |
---|
单精度浮点型 | float | 32 | -3.4E38~3.4E38 | 7 | 双精度浮点型 | double | 64 | -1.79E+308 ~ +1.79E+308 | 16 |
2.4.2.1 单精度浮点型
声明:
float selling_price;
初始化:
float selling_pric = 11.3;
selling_price = 65.90;
2.4.2.2 双精度浮点型
声明:
double pressure_level;
初始化:
pressure_level = 213.5671435568967;
udouble dvalue = 35.4;
2.4.3 字符型
char
值 | 符号 | 值 | 符号 | 值 | 符号 |
---|
0 | 空字符 | 44 | , | 91 | [ | 32 | 空格 | 45 | - | 92 | ** | 33 | ! | 46 | . | 93 | ] | 34 | " | 47 | / | 94 | ^ | 35 | # | 48 ~ 57 | 0 ~ 9 | 95 | - | 36 | $ | 58 | : | 96 | ` | 37 | % | 59 | ; | 97 ~ 122 | a ~ z | 38 | & | 60 | < | 123 | { | 39 | ’ | 61 | = | 124 | | | 40 | ( | 62 | > | 125 | } | 41 | ) | 63 | ? | 126 | ~ | 42 | ***** | 64 | @ | 127 | DEL (Delete键**)** | 43 | + | 65 ~ 90 | A ~ Z | | |
2.5 输入/输出函数
2.5.1 printf函数
实例
#include <stdio.h>
void main()
{
int num;
printf("请输入一个数:");
scanf("%d",&num);
printf("\n%d 的平方为 %d \n",num,num*num);
}
int visitor_count = 150;
printf ("%d" , visitor_count);
int salary = 5500;
printf ("%10d" , salary);
float circumference = 9.4786789;
printf (" %f" , circumference);
double mercury_level = 168.2251074;
printf ("%7.2f" , mercury_level);
#include <stdio.h>
void main()
{
float radius=1.5, high=2.0;
float pi=3.14159, vol;
vol=pi*radius*radius*high;
printf("vol=%7.2f\n",vol);
}
2.5.2 转换字符串
转换字符串 | 说 明 |
---|
%d | 将参数按整数形式转换输出,对应参数应是int 类型 | %ld | 将参数按长整数形式转换输出,对应参数应是long 类型 | %c | 输出一个字符,对应参数应该是一个字符 | %s | 输出一个字符串,对应参数应该是一个字符串 | %f | 将参数按带小数点数形式输出,对应参数应是double 类型,默认情况下精确到 6 位小数 |
2.5.3 转义序列
转义序列 | 名称 | 描述 |
---|
\a | 警告 | 产生一则警告。 | \b | 退格 | 将光标回退一格。 | \f | 换页 | 将光标移到下一页的第一格。 | \n | 换行 | 将光标移到下一行的第一格。 | \r | 回车 | 将光标移到当前行的第一格。 | \t | 水平制表 | 将光标移到下一个水平制表位置。 | \v | 垂直制表 | 将光标移到下一个垂直制表位置。 | \’ | 单引号 | 产生一个单引号。 | \" | 双引号 | 产生一个双引号。 | ? | 问号 | 产生一个问号。 | \\ | 反斜线 | 产生一条反斜线。 | \0 | 空 | 产生一个空字符。 |
2.5.4 scanf 函数
scanf 函数从标准输入(键盘)读取信息,按照格式描述把读入的信息转换为指定数据类型的数据,并把这些数据赋给指定的程序变量。
scanf("%d",&num);
转换字符串 | 参数变量的类型 | 要求的实际输入 |
---|
%d | int | 十进制数字序列 | %ld | long | 十进制数字序列 | %f | float | 十进制数,可以有小数点及指数部分 | %lf | double | 十进制数,可以有小数点及指数部分 |
实例
#include <stdio.h>
void main()
{
double radius,high,vol;
printf("请输入圆柱体底面积的半径和圆柱体的高: ");
scanf("%lf%lf",&radius,&high);
vol=3.14*radius*radius*high;
printf("radius=%7.2f,high=%7.2f,vol=%7.2f\n",
radius,high,vol);
}
2.5.5 算术运算符
 
2.5.5.1 算术运算符示例
#include <stdio.h>
void main()
{
int a = 5, b = 3, c = 25, d = 12;
float qu;
int re,in,de;
qu = a / b;
re = a % b;
in = ++c;
de = --d;
printf ("商为 %f\n",qu);
printf ("余数为 %d\n",re);
printf ("加 1 后为 %d\n",in);
printf ("减 1 后为 %d\n",de);
}
2.5.6 类型转换
2.5.6.1 自动类型转换
原则:把表示范围小的类型的值转换到表示范围大的类型的值
short
int
long
float
double
2.5.6.2 强制类型转换
int a = 5, b = 3;
float qu = float(a) / b;
2.5.7 接受并显示字符
2.5.7.1 getchar() 函数
语法:
char variablename;
variablename = functionname;
2.5.7.2 getchar()和putchar()示例
#include <stdio.h>
void main()
{
char a,b;
printf(" 请输入两个字符:\n");
a=getchar();
fflush(stdin);
b=getchar();
fflush(stdin);
putchar(a);
putchar(b);
putchar('\n');
}
2.6 小结
- 常量是在程序中不能被更改的值;而变量在程序中可以被更改的,通过变量可以引用存储在内存中的数据
- C语言中的基本数据类型包括整型、单精度浮点型、双精度浮点型和字符型
- 整型分为短整型、整型、长整型,每种整型又可分为有符号型和无符号型
- 单精度浮点型和双精度浮点型变量可以存储实数,但双精度型取值范围要比单精度型大的多
- 字符型变量可以存储单个字符,其值是该字符的ASCII码
- 算术运算符提供运算功能,包括+、-、*、/、%、++和—
- printf() 和 scanf() 函数属于格式输入输出函数
- getchar() 和 putchar() 函数用来输入输出单个字符的函数
第3章 条件判断
3.1 回顾
- 表达式是操作数和运算符的集合
- 关系运算符运用测试两个操作数之间的关系
- 条件结构解决了程序种需要根据不同情况进行判断的情况
- 逻辑运算符用于组合多个条件(&& 和 ||)或者为某一条件取反(!)
- sizeof 运算符用于在程序中测试某一数据类型占用多少字节
- 在复杂表达式中,通过运算符的优先级确定各种运算符的执行顺序
3.2 本节目标
- 熟练使用多重 if 结构
- 熟练使用==嵌套 if ==结构
- 熟练使用switch结构
- 理解条件运算符的用法
3.3 多重条件判断
有
没有
有
没有
开始
是否有黄瓜
做黄瓜沙拉
可以上菜
结束
是否有胡萝卜
做胡萝卜沙拉
不能上菜
3.4 多重条件结构
要处理多重条件判断的情况,需要使用多重条件结构
多重条件结构
多重if
嵌套if
switch结构
3.5 多重 if 结构
多重 if 结构是if-else 的另一种形式 ,这种形式也称为阶梯式 if-else-if
#include <stdio.h>
void main()
{
float grade;
printf("\n 请输入期末考试成绩: ");
scanf("%f", &grade);
if(grade>=90)
printf("\n 优");
else if ((grade>=80) && (grade<90))
printf("\n 良");
else if ((grade>=60) && (grade<80))
printf("\n 中");
else
printf("\n 差");
printf("\n");
}
3.6 嵌套 if 结构
嵌套 if 结构就是将整个 if 块插入另一个 if 块中
if (表达式1)
if (表达式2)
if (表达式3)
语句;
else
语句;
if (x > 0)
if (y > 1)
z = 1;
else
z = 2;
C语言规定,每个 else 部分总属于前面最近的那个缺少对应的 else 部分的 if 语句。
提倡使用大括号括起来以避免看起来有二义性。
示例:
#include<stdio.h>
void main()
{
int a,b;
printf("\n 请输入 A 和 B 的值: ");
scanf("%d%d",&a,&b);
if(a!=b)
if(a>b)
printf("\n A>B\n");
else
printf("\n A<B\n");
else
printf("\n A=B\n");
}
3.7 switch 结构

- switch-case 语句是多路判断语句
- switch 语句计算条件表达式并对照多个常数值进行检查
switch (表达式)
{
case 常量 1:
语句;
break;
case 常量 2:
语句;
break;
default:
语句;
}
在使用switch结构时应注意以下几点:
- 在case后的各常量表达式的值不能相同,否则会出现错误;
- 在case后,允许有多个语句,可以不用{}括起来;
- 每个case语句后都必须有一个break语句,否则会出现错误;
- 各case和default子句的先后顺序可以变动,而不会影响程序执行结果;
- default子句可以省略;
char in_char;
printf("\n 请输入一个小写字母: ");
scanf("%c", &in_char);
switch(in_char)
{
case 'a': printf("\n 您输入的是元音字母 a\n");
break;
case 'e': printf("\n 您输入的是元音字母 e\n");
break;
case 'i': printf("\n 您输入的是元音字母 i\n");
break;
case 'o': printf("\n 您输入的是元音字母 o\n");
break;
case 'u': printf("\n 您输入的是元音字母 u\n");
break;
default: printf("\n 您输入的不是元音字母 \n");
}
3.8 比较多重 if 和 switch 结构
- 多重if结构和switch结构都可以用来实现多路分支
- 多重if结构用来实现两路、三路分支比较方便,而switch结构实现三路以上分支比较方便
- 在使用switch结构时,应注意分支条件要求是整型表达式,而且case语句后面必须是常量表达式
- 有些问题只能使用多重if结构来实现,例如要判断一个值是否处在某个区间的情况
void main()
{
char c;
printf("\n 请输入一个字符: ");
c=getchar();
if(c<32)
printf("\n 该字符是一个控制字符。\n");
else if(c>='0'&&c<='9')
printf("\n 该字符是一个数字。\n");
else if(c>='A'&&c<='Z')
printf("\n 该字符是一个大写字母。\n");
else if(c>='a'&&c<='z')
printf("\n 该字符是一个小写字母。\n");
else
printf("\n 该字符是其他字符。\n");
}
示例
int a,b; char op;
printf("\n 输入操作数1,运算符,操作数2: ");
scanf("%d,%c,%d",&a,&op,&b);
switch(op)
{
case '+': printf("\n %d+%d=%d\n",a,b,a+b);
break;
case '-': printf("\n %d-%d=%d\n",a,b,a-b);
break;
case '*': printf("\n %d×%d=%d\n",a,b,a*b);
break;
case '/': printf("\n %d/%d=%d\n",a,b,a/b);
break;
default: printf("\n 运算符错误!");
}
3.9 条件运算符
 
if (num>100)
{
value=‘y’;
}
else
{
value=‘n’;
}
示例
#include <stdio.h>
void main()
{
double sal;
double rate;
printf("\n 请输入基本工资:");
scanf("%lf",&sal);
rate= (sal<=1000) ? 0 : 0.05;
sal=sal-(sal-1000)*rate;
printf("\n 税后工资为:%7.2f \n",sal);
}
3.10 小结
- 多重if结构就是在主if块的else部分中还包含其他if块
- 嵌套if结构是在主if块中还包含另一个if 语句
- C语言规定,嵌套if结构中每个else部分总是属于前面最近的那个缺少对应的else部分的if语句
- switch结构也可以用于多分支选择。用于分支条件是整型表达式,而且判断该整型表达式的值是否等于某些值(可以罗列的),然后根据不同的情况,执行不同的操作
- 条件运算符是 if–else 语句的另一种表现形式
第4章 循环结构while
4.1 回顾
- 多重if结构就是在主if块的else部分中还包含其他if块,以else if体现
- 嵌套if结构是在主if块中还包含另一个if 语句
- switch结构也可以用于多分支选择。用于分支条件是整型表达式,而且判断该整型表达式的值是否等于某些值(可以罗列的),然后根据不同的情况,执行不同的操作
- 条件运算符是 if–else 语句的另一种表现形式
4.2 目标
- 理解为什么使用循环结构
- 熟练掌握while循环的使用
- 熟练掌握do-while循环的使用
- 理解while 和 do-while 循环的区别
4.3 循环的必要性
int result1,result2,result3;
int result4,result5;
result1 = 1 * 10;
printf("1 × 10 = %d \n",result1);
result2 = 2 * 10;
printf("2 × 10 = %d \n",result2);
result3 = 3 * 10;
printf("3 × 10 = %d \n",result3);
result4 = 4 * 10;
printf("4 × 10 = %d \n",result4);
result5 = 5 * 10;
printf("5 × 10 = %d \n",result5);
4.3.1 为什么需要循环控制
例如:全班有50个学生,统计各学生三门课的平均成绩。
scanf(“%f,%f,%f”,&s1,&s2,&s3);
aver=(s1+s2+s3)/3;
printf(“aver=%7.2f”,aver);
scanf(“%f,%f,%f”,&s1,&s2,&s3);
aver=(s1+s2+s3)/3;
printf(“aver=%7.2f”,aver);
用while循环结构实现

while(i<=50)
{ scanf…… ;
aver=…… ;
printf…… ;
i++;
}
4.4 while 循环
4.4.1 while 循环的一般语法
while (表达式)
{
语句;
}
规则1:
[<初始化>]
while(循环条件)
{
<循环体>
}
规则2:
while (index < 100)
{
. . .
. . .
index++;
}
4.4.2 工作原理
计算表达式的值,当值为真(非0)时,执行循环体语句,一旦条件为假,就停止执行循环体。
如果条件在开始时就为假,那么不执行循环体语句直接退出循环。
4.4.3 while循环的特点是
先判断条件表达式,后执行循环体语句
4.4.4 例题
4.4.4.1 示例1
求1+2+3+…+100,即
∑
n
=
1
100
n
\sum_{n=1}^{100} n
n=1∑100?n
解题思路:
- 这是累加问题,需要先后将100个数相加
- 要重复100次加法运算,可用循环实现
- 后一个数是前一个数加1而得
- 加完上一个数i后,使i加1可得到下一个数
#include <stdio.h>
int main()
{
int i=1,sum=0;
while (i<=100)
{ sum=sum+i;
i++;
}
printf("sum=%d\n",sum);
return 0;
}
4.4.4.2 示例2
#include<stdio.h>
void main ()
{
int num=1,result;
while (num<=10)
{
result=num*10;
printf("%d × 10 = %d \n",num,result);
num++;
}
}

4.4.4.3 示例3
#include <stdio.h>
void main ()
{
int c=0,count=0;
double f;
while (c <= 250 && count<10)
{
count++;
printf("%d: ",count);
f=c * 9 / 5.0 + 32.0;
printf("C = %d, F = %7.2f\n", c, f);
c = c + 20;
}
}

4.5 do—while
4.5.1 Do-while 循环的一般语法:
do
{
语句;
} while (表达式);
4.5.2 工作原理
它先执行循环体中的语句,然后再判断条件是否为真,如果为真则继续循环;如果为假,则终止循环。
4.5.3 do–while语句的特点
先无条件地执行循环体,然后判断循环条件是否成立
4.5.4 例题
4.5.4.1 示例1
用do–while语句求: 1+2+3+…+100,即
∑
n
=
1
100
n
\sum_{n=1}^{100} n
n=1∑100?n
解题思路

#include <stdio.h>
int main()
{ int i=1,sum=0;
do
{
sum=sum+i;
i++;
}while(i<=100);
printf("sum=%d\n",sum);
return 0;
}
4.5.4.2 示例2
输入数字 5 后,do…while 循环中的条件为假, 输出结果消息后,程序终止。
int number=5,guess;
printf ("猜一个介于 1 与 10 之间的数\n");
do
{
printf("请输入您猜测的数:");
scanf("%d",&guess);
if (guess > number)
printf("太大\n");
else if (guess < number)
printf("太小\n");
} while (guess != number);
printf("您猜中了! 答案为 %d\n",number);
4.6 嵌套循环
4.6.1 嵌套 while 循环
4.6.1.1 语法
while(i <= 10)
{
. . .
while (i <= j)
{
. . .
. . .
}
. . .
}
只有在内循环完全结束后,外循环才会进行下一趟。
4.6.1.2 示例
用“*”打印一个直角三角形图案。
void main()
{
int nstars=1,stars;
while(nstars <= 10)
{
stars=1;
while (stars <= nstars)
{
printf("*");
stars++;
}
printf("\n");
nstars++;
}
}
4.6.2 嵌套 do-while 循环
4.6.2.1 语法
do
{
. . .
do
{
. . .
}while( . . .)
. . .
}while( . . . )
4.6.2.2 示例
int x;
char i, ans;
ans='y';
do
{
x=0;
printf("\n请输入字符序列:");
fflush(stdin);
do{
i=getchar();
x++;
}while( i !='\n' );
printf("\n输入的字符数为:%d", --x);
printf("\n是否需要输入更多序列 (Y/N) ? ");
ans = getchar();
}while(ans =='Y' || ans == 'y');
4.7 小结
- 循环结构的特点是,在给定条件成立时,重复执行某程序段,直到条件不成立为止
- while 循环用于在给定条件为真的情况下重复执行一组操作,while循环先判断后执行
- do-while循环先执行后判断,因此循环将至少执行一次
- 在循环中,需要修改循环变量的值以改变循环条件,否则有可能形成死循环
- 循环嵌套必须将内层循环完整的包含在外层循环中
第4章 循环结构for
4.1 回顾
- 循环结构的特点是,在给定条件成立时,重复执行某程序段,直到条件不成立为止
- while 循环用于在给定条件为真的情况下重复执行一组操作,while循环先判断后执行
- do-while循环先执行后判断,因此循环将至少执行一次
- 在循环中,需要修改循环变量的值以改变循环条件,否则有可能形成死循环
- 循环嵌套必须将内层循环完整的包含在外层循环中
4.2 目标
熟练使用for循环
理解break 和 continue 语句的用法
熟练使用嵌套循环
4.3 用for 语句实现循环
- for语句不仅可以用于循环次数已经确定的情况,还可以用于循环次数不确定而只给出循环结束条件的情况
- for语句完全可以代替while语句
for (i=1;i<=100;i++)
{
printf("%d ", i );
}

4.4 语法
- for 循环中有三个表达式
- for 语句中的各个表达式都可以省略
- 分号分隔符不能省略
for(<初始化循环变量> ;<循环条件> ; <修改循环变量的值>)
{
<循环体语句>;
}
4.5 工作原理
- 计算表达式1的值,通常为循环变量赋初值;
- 计算表达式2的值,即判断循环条件是否为真,若值为真则执行循环体一次, 否则跳出循环;
- 计算表达式3的值,这里通常写更新循环变量的赋值表达式,然后转回第2步重复执行;
4.6 示例
#include <stdio.h>
void main()
{
int number,count,factorial=1;
printf("\n 请输入任意一个正整数:");
scanf("%d",&number);
for(count = 1; count <=number; count++)
factorial=factorial*count;
printf("\n %d的阶乘 = %d\n",number,factorial);
}
4.7 逗号运算符
- for语句中的三个表达式都可以是逗号表达式
- 逗号表达式就是通过“,”运算符隔开的多个表达式组成的表达式
- 逗号表达式从左往右计算。逗号运算符在 C 语言运算符中的优先级最低
#include <stdio.h>
void main()
{
int i,j,max;
printf("请输入一个值 \n");
printf("根据这个值可以输出以下加法表:");
scanf("%d",&max);
for(i = 0,j = max ; i <=max ; i++,j--)
printf("\n %d + %d = %d",i,j,i + j);
printf("\n");
}

改变循环执行的状态
- 用break语句提前终止循环
- 用continue语句提前结束本次循环
- break语句和continue语句的区别
4.8 break 语句
- break语句可以改变程序的控制流程
- break语句用于do-while、while、for循环中时,可使程序终止循环而执行循环后面的语句
- break语句通常在循环中与条件语句一起使用。若条件值为真,将跳出循环,控制流转向循环后面的语句
- 如果已执行break语句,就不会执行循环体中位于 break 语句后的语句
- 在多层循环中,一个break语句只向外跳一层
跳出 for 循环
for( ; ; )
{
printf("这将一直进行下去");
i = getchar();
if(i == 'X' || i == 'x')
break;
}
跳出 while 循环
while(1)
{
if(x == 10)
break;
}
跳出 do-while 循环
do
{
if (x == 10)
break;
}while (x< 15);
4.8.1 示例
#include<stdio.h>
void main()
{
int count=0,ch;
printf("\n 请输入一行字符:");
while((ch=getchar())!='\n')
{
if(ch==' ')
break;
count++;
}
printf("\n 共有 %d 个有效字符。\n",count);
}
4.8.2 用break语句提前终止循环
在全系1000学生中,征集慈善募捐,当总数达到10万元时就结束,统计此时捐款的人数,以及平均每人捐款的数目。
编程思路:
-
循环次数不确定,但最多循环1000次 -
在循环体中累计捐款总数 -
用if语句检查是否达到10万元 -
如果达到就不再继续执行循环,终止累加 -
计算人均捐款数 -
变量amount,用来存放捐款数 -
变量total,用来存放累加后的总捐款数 -
变量aver,用来存放人均捐款数 -
定义符号常量SUM代表100000
#include <stdio.h>
#define SUM 100000
int main()
{ float amount,aver,total; int i;
for (i=1,total=0;i<=1000;i++)
{ printf("please enter amount:");
scanf("%f",&amount);
total= total+amount;
if (total>=SUM) break;
}
aver=total / i ; printf("num=%d\naver=%10.2f\n",i,aver);
return 0;
}
4.9 continue 语句
- continue 语句只能用在循环里
- continue 语句的作用是跳过循环体中剩余的语句而执行下一次循环
- 对于while和do-while循环,continue语句执行之后的动作是条件判断;对于for循环,随后的动作是变量更新
4.9.1 示例
#include<stdio.h>
void main()
{
int i,sum = 0;
for(i=1; i<=100;i++)
{
if( i % 10 == 3)
continue;
sum += i;
}
printf("sum = %d \n",sum);
}
要求输出100~200之间的不能被3整除的数
编程思路:
- 对100到200之间的每一个整数进行检查
- 如果不能被3整除,输出,否则不输出
- 无论是否输出此数,都要接着检查下一个数(直到200为止)。

for(n=100;n<=200;n++)
{ if (n%3==0)
continue;
printf("%d ",n);
}
4.10 break语句和continue语句的区别
4.11 嵌套循环示例
4.11.1 示例1
问题描述:
用“*”输出一个菱形图案,图案如下:

void main()
{
int i,j,k;
for(i=1;i<=4;i++)
{
for(j=1;j<=4-i;j++)
printf(" ");
for(k=1;k<=2*i-1;k++)
printf("*");
printf("\n");
}
for(i=1;i<=3;i++)
{
for(j=1;j<=i;j++)
printf(" ");
for(k=1;k<=7-2*i;k++)
printf("*");
printf("\n");
}
}
4.11.2 示例2

void main()
{
int i,j,n;
n=0;
for(i=100;i<=200;i++)
{
j=2;
while(i%j!=0)
j++;
if(i==j)
{
printf("%4d",i);
n++;
if(n%8==0)
printf("\n");
}
}
printf("\n");
}
4.11.3 示例3

void main()
{
int i,num;
char answer;
do
{
printf("请输入一个数:");
scanf("%d",&num);
printf("\n");
for (i = 1; i <= 10; i++)
{
printf("=");
}
printf("\n 该数是 %d",num);
printf("\n\n 您是否还要输入其他的数(y/n)?");
fflush(stdin);
answer = getchar();
} while (answer != 'n');
}
4.12 小结
- for 循环与 while 循环类似,属于先判断后执行
- for 语句中有三个表达式:表达式1通常用来给循环变量赋初值;表达式2通常是循环条件;表达式3用来更新循环变量的值
- for 语句中的各个表达式都可以省略,但要注意分号分隔符不能省略
- 如果省略表达式2和表达式3需要在循环体内设法结束循环,否则会导致死循环
- break 语句用在循环中时,可以直接终止循环,将控制转向循环后面的语句
- continue 语句的作用是跳过循环体中剩余的语句而执行下一次循环
- 嵌套循环时,必须将被嵌套的循环语句完整地包含在外层循环的循环体内
第5章 数组
5.1 目标
- 理解为什么要使用数组
- 理解 C 语言中数组
- 熟练掌握一维数组的使用
- 掌握二维数组的使用
- 熟悉用数组实现常用的算法
5.2 为什么要使用数组


5.3 利用数组处理批量数据
- 前几章使用的变量都属于基本类型,例如整型、字符型、浮点型数据,这些都是简单的数据类型。
- 对于有些数据,只用简单的数据类型是不够的,难以反映出数据的特点,也难以有效地进行处理。
如果有1000名学生,每个学生有一个成绩,需要求这1000名学生的平均成绩。
用s1,s2,s3,……,s1000表示每个学生的成绩,能体现内在联系。
C语言用方括号中的数字表示下标,如用s[15]表示
- 数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,下标代表数据在数组中的序号
- 用一个数组名和下标惟一确定数组中的元素
- 数组中的每一个元素都属于同一个数据类型
5.4 C 语言中的数组
- 数组是可以在内存中连续存储多个元素的结构
- 数组中的所有元素必须属于相同的数据类型

5.4.1 数组类型
示例:学员单门课程的成绩

示例:学员两门课程的成绩
 
5.4.2 一维数组
5.4.2.1 声明一维数组
datatype arrayName[size];
datatype | arrayName | size |
---|
类型说明符 int、char、float … | 数组名 | 常量表达式:数组大小 |
示例
int num[50];
char list_of_initials[20];
double pressure_level[6];
#define LIMIT 20
. . .
int emp_codes[LIMIT];
定义一维数组的一般形式为:类型符 数组名[常量表达式];
int a[4+6];
int n=10;
int a[n];
- 在定义数组并对其中各元素赋值后,就可以引用数组中的元素
- 注意:只能引用数组元素而不能一次整体调用整个数组全部元素的值
引用数组元素的表示形式为: 数组名[下标]
a[0]=a[5]+a[7]-a[2*3]
int n=5,a[10];
a[n]=20;
5.4.2.2 初始化一维数组
int arr[10] = {10,9,8,7,6,5,4,3,2,1,0};
int arr[10] = {9,8,7,5};
int arr[] = {9,8,7};
int arr[]={};
在定义数组的同时,给各数组元素赋值
int a[10]={0,1,2,3,4,5,6,7,8,9};
int a[10]={0,1,2,3,4};
int a[10]={0,1,2,3,4,0,0,0,0,0};
int a[10]={0,0,0,0,0,0,0,0,0,0};
int a[10]={0};
int a[5]={1,2,3,4,5};
int a[ ]={1,2,3,4,5};
为一维数组动态赋值
float price[4];
printf(“Enter prices of 4 books\n”);
for (i = 0;i <= 3; i++)
{
scanf(“%f”,&price[i]);
}

例 对10个数组元素依次赋值为0,1,2,3,4,5,6,7,8,9,要求按逆序输出。
- 解题思路:
- 定义一个长度为10的数组,数组定义为整型
- 要赋的值是从0到9,可以用循环来赋值
- 用循环按下标从大到小输出这10个元素
#include <stdio.h>
int main()
{ int i,a[10];
for (i=0; i<=9;i++)
a[i]=i;
for(i=9;i>=0; i--)
printf("%d ",a[i]);
printf("\n");
return 0;
}
a[0] | a[1] | a[2] | a[3] | a[4] | a[5] | a[6] | a[7] | a[8] | a[9] |
---|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
示例

# include <stdio.h>
void main()
{
int i;
float item_rate[5],total=0;
printf("\n 请输入商品价格:");
for(i=0;i<5;i++)
{
scanf("%f",&item_rate[i]);
total=total+item_rate[i];
}
printf(“\n 所有商品的合计费用:%f\n ",total);
}
5.4.3 二维数组
datatype arrayName[rowsize] [colsize];
int num[4] [2];
4 X 2 = 8 8*sizeof(int)字节

int books[4][2] = {{11, 1294},{22,450}, {33,4000}, {44,79}};
int arr[ ][3] = { {1,2,3}, {4,5,6} };
int arr[2][ ] = { {1,2,3}, {4,5,6} };
例

int i, j, num[4][2];
for (i = 0; i <= 3; i++)
{
for (j = 0; j <=1 ; j++)
{
scanf("%d",&num[i][j]);
}
}
示例
int i,j,student[3][2];
for(i = 0;i < 3;i++)
{
printf("\n 输入学号 %d 两个学期的成绩:",i+1);
for(j = 0;j < 2;j++)
scanf("%d",&student[i][j]);
}
printf("\n 学员的学号及其两个学期的成绩为:\n ");
printf("\n \t学号\t第一学期\t第二学期");
for(i = 0;i < 3;i++)
{
printf("\n\t");
printf("%d\t",i+1);
for(j = 0;j < 2;j++)
printf("%d\t\t",student[i][j]);
printf("\n ");
}

5.4.4 数组应用
5.4.4.1 应用1
求一组数中的最大值和最小值 。
void main()
{
int num[5],max,min,i;
printf("请输入5个数:\n");
for(i=0;i<5;i++)
scanf("%d",&num[i]);
max=num[0];
min=num[0];
for(i=1;i<5;i++)
{
if (max<num[i])
max=num[i];
if (min>num[i])
min=num[i];
}
printf("\n最大值为:%d",max);
printf("\n最小值为:%d\n",min);
}
5.4.4.2 应用2
输入10个数,保存在一个数组中,在数组中查找某个数,给出是否找到的信息。如果找到了,要求输出该数在数组中所处的位置;如果找不到,输出“没有找到!”。
#define N 10
……
for(i=0;i<N;i++)
scanf("%d",&num[i]);
printf("\n 请输入要查找的数:");
scanf("%d",&search);
for (i=0;i<N;i++)
{
if (num[i]==search)
break;
}
if(i<N)
printf("\n 在数组的第 %d 个位置找到了数字 %d !\n",i+1,search);
else
printf("\n 没有找到!\n");
……
5.4.4.3 例
有10个地区的面积,要求对它们按由小到大的顺序排列。
解题思路:
- 排序的规律有两种:一种是“升序”,从小到大;另一种是“降序”,从大到小
- 把题目抽象为:“对n个数按升序排序”
- 采用起泡法排序
for(i=0;i<5;i++)
if (a[i]>a[i+1])
{ t=a[i];a[i]=a[i+1];a[i+1]=t; }

for(i=0;i<4;i++)
if (a[i]>a[i+1])
{ t=a[i];a[i]=a[i+1];a[i+1]=t; }

for(i=0;i<3;i++)
if (a[i]>a[i+1])
{ t=a[i];a[i]=a[i+1];a[i+1]=t; }

for(i=0;i<2;i++)
if (a[i]>a[i+1])
{ t=a[i];a[i]=a[i+1];a[i+1]=t; }

for(i=0;i<1;i++)
if (a[i]>a[i+1])
{ t=a[i];a[i]=a[i+1];a[i+1]=t; }


int a[10]; int i,j,t;
printf("input 10 numbers :\n");
for (i=0;i<10;i++) scanf("%d",&a[i]);
printf("\n");
for(j=0;j<9;j++)
for(i=0;i<9-j;i++)
if (a[i]>a[i+1])
{t=a[i];a[i]=a[i+1];a[i+1]=t;}
printf("the sorted numbers :\n");
for(i=0;i<10;i++) printf("%d ",a[i]);
printf("\n");

5.4.4.4 应用3
编写C程序实现冒泡排序算法,按照降序排列一组数。
#define N 5
……
int grade[N],temp;
for(i=0;i<N;i++)
scanf("%d",&grade[i]);
for(i=0;i<N;i++)
{
for(j=0;j<N-i-1; j++)
{
if(grade[j] < grade[j+1])
{
temp = grade[j+1];
grade[j+1] = grade[j];
grade[j] = temp;
}
}
}
……
5.4.4.5 应用4
如果一个数组中保存的元素是有序的(由大到小),向这个数组中插入一个数,使得插入后的数组元素依然保持有序。
#define N 5
……
int num[N+1]={23,45,60,67,88},in;
printf("\n 请输入一个要插入的数:");
scanf("%d",&in);
for(i=0;i<N;i++)
{
if(num[i]>in)
break;
}
for(j=N;j>i;j--)
num[j]=num[j-1];
num[i]=in;
printf("\n 插入后的数组元素:\n");
for(i=0;i<N+1;i++)
printf("%d ",num[i]);
printf("\n");
……
5.5 小结
- 数组是可以在内存中连续存储多个元素的结构数组中的所有元素必须属于相同的数据类型
- 数组必须先声明,然后才能使用。声明一个数组只是为该数组留出内存空间,并不会为其赋任何值
- 数组的元素通过数组下标访问
- 一维数组可用一个循环动态初始化,而二维数组可用嵌套循环动态初始化
- 二维数组可以看作是由一维数组的嵌套而构成的
第6章 字符数组
6.1 学习目标
- 掌握使用字符数组存储和操作字符串的方法
- 理解字符串的存储方式,掌握对字符串元素逐个访问及整体访问方法
- 掌握常用标准字符串处理函数,简化对字符串的操作
6.2 怎样定义字符数组
6.3 字符数组的初始化
char c[10]={’I’,’ ’,’a’,’m’,’ ’,’h’,’a’,’p’,’p’,’y’};
c[0] | c[1] | c[2] | c[3] | c[4] | c[5] | c[6] | c[7] | c[8] | c[9] |
---|
I | | a | m | | h | a | p | p | y |
char c[10]={’c’,’ ’,’p’,’r’,’o’,’g’,’r’,’a’,’m’};
c[0] | c[1] | c[2] | c[3] | c[4] | c[5] | c[6] | c[7] | c[8] | c[9] |
---|
c | | p | r | o | g | r | a | m | \0 |
char diamond[5][5]={{’ ’,’ ’,’*’},
{’ ’,’*’,’ ’,’*’},
{’*’,’ ’,’ ’,’ ’,’*’},
{’ ’,’*’,’ ’,’*’},
{’ ’,’ ’,’*’} };
6.4 怎样引用字符数组中的元素
6.4.1 输出一个已知的字符串。
解题思路:
- 定义一个字符数组,并用“初始化列表”对其赋以初值
- 用循环逐个输出此字符数组中的字符
#include <stdio.h>
int main()
{ char c[15]={'I',' ','a','m',' ','a',' ','s','t','u','d','e','n','t','.'};
int i;
for(i=0;i<15;i++)
printf("%c",c[i]);
printf("\n");
return 0;
}
6.4.2 输出一个菱形图
解题思路:

#include <stdio.h>
int main()
{ char diamond[][5]={{' ',' ','*'},
{' ','*',' ','*'},{'*',' ',' ',' ','*'},
{' ','*',' ','*'},{' ',' ','*'}};
int i,j;
for (i=0;i<5;i++)
{for (j=0;j<5;j++)
printf("%c",diamond[i][j]);
printf("\n");
}
return 0;
}
6.5 字符串和字符串结束标志
- 在C语言中,是将字符串作为字符数组来处理的
- 关心的是字符串的有效长度而不是字符数组的长度
- 为了测定字符串的实际长度,C语言规定了字符串结束标志==’\0’==
- \0’代表ASCII码为0的字符
- 从ASCII码表可以查到,ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做
- 用它作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志
char c[]={”I am happy”};
可写成
char c[]=”I am happy”;
相当于
char c[11]={”I am happy”};
char c[10]={”China”};
可写成
char c[10]=”China”;
从c[5]开始,元素值均为\0
只显示
printf(”%s”,c);

6.6 字符数组的输入输出
? 逐个字符输入输出(%c)
? 整个字符串一次输入输出(%s)
-
输出的字符中不包括结束符’\0’ -
用%s输出字符串时,printf函数中的输出项是字符数组名,不是数组元素名 -
如果一个字符数组中包含多个’\0’,则遇第一个’\0’时输出就结束 -
可以用scanf函数输入一个字符串 -
scanf函数中的输入项c是已定义的字符数组名,输入的字符串应短于已定义的字符数组的长度 char c[6];
scanf(”%s”,c);
char str1[5],str2[5],str3[5];
scanf(”%s%s%s”,str1,str2,str3);
str1 | H | o | w | \0 | \0 |
---|
str2 | a | r | e | \0 | \0 | str3 | y | o | u | ? | \0 |
6.7 善于使用字符串处理函数
-
在C函数库中提供了一些用来专门处理字符串的函数,使用方便
6.7.1 puts函数----输出字符串的函数
? puts (字符数组)
? char str[20]=”China”;
? puts(str);
? 输出China
6.7.2 gets函数----输入字符串的函数
? gets(字符数组)
? char str[20];
? gets(str);
? Computer↙
6.7.3 strcat函数----字符串连接函数
? strcat(字符数组1,字符数组2)
- 其作用是把两个字符串连接起来,把字符串2接到字符串1的后面,结果放在字符数组1中
char str1[30]=”People”; //要足够大
char str2[]=”China”;
printf(”%s”, strcat(str1,str2));
输出:PeopleChina
使用字符串函数时,在程序开头用#include <string.h>
#include <string.h> 包括哪些函数
- strlen求字符串长度
- strcmp比较2个字符串是否一样
- strcat字符串连接操作
- strcpy字符串拷贝操作
- strncat字符串连接操作(前n个字符)
- strncpy字符串拷贝操作(前n个字符)
- strchr查询字串
- strstr 查询子串
6.7.4 strcpy和strncpy函数-字符串复制
-
strcpy一般形式为: strcpy(字符数组1,字符串2) -
作用是将字符串2复制到字符数组1中去
char str1[10],str2[]=”China”;
strcpy(str1,str2);
- 可以用strncpy函数将字符串2中前面n个字符复制到字符数组1中去
strncpy(str1,str2,2);
- 作用是将str2中最前面2个字符复制到str1中,取代str1中原有的最前面2个字符
- 复制的字符个数n不应多于str1中原有的字符
6.7.5 strcmp函数----字符串比较函数
-
其一般形式为 strcmp(字符串1,字符串2) -
作用是比较字符串1和字符串2 -
strcmp(str1,str2); -
strcmp(”China”,”Korea”); -
strcmp(str1,”Beijing”);
- 字符串比较的规则是:将两个字符串自左至右逐个字符相比,直到出现不同的字符或遇到’\0’为止
- 如全部字符相同,认为两个字符串相等
- 若出现不相同的字符,则以第一对不相同的字符的比较结果为准
两个字符串自左向右逐个字符相比
(按ASCII值大小相比较)
”A”<”B” ”a”>”A”
”computer”>”compare”
”these”>”that” ”1A”>”$20”
”CHINA”>”CANADA”
”DOG”<”cat”
”Tsinghua”>”TSINGHUA”
比较的结果由函数值带回
- 如果字符串1=字符串2,则函数值为0
- 如果字符串1>字符串2,则函数值为一个正整数
- 如果字符串1<字符串2,则函数值为一个负整数
if(str1>str2) printf(”yes”);
if(strcmp(str1,str2)>0)
printf(”yes”);
6.7.6 strlen函数----测字符串长度的函数
其一般形式为:
? strlen (字符数组)
它是测试字符串长度的函数
函数的值为字符串中的实际长度
6.8 字符数组应用举例
-
用变量word作为判别当前是否开始了一个新单词的标志,若word=0表示未出现新单词,如出现了新单词,就把word置成1 -
前面一个字符是否空格可以从word的值看出来,若word等于0,则表示前一个字符是空格;如果word等于1,意味着前一个字符为非空格 if(c==' ')
word=0;
else if(word==0)
{ word=1;
num++;
}
当前字符 | I | | a | m | | a | | b | o | y | . |
---|
是否空格 | 否 | 是 | 否 | 否 | 是 | 否 | 是 | 否 | 否 | 否 | 否 | word原值 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 新单词开始否 | 是 | 否 | 是 | 否 | 否 | 是 | 否 | 是 | 否 | 否 | 否 | word新值 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | num值 | 1 | 1 | 2 | 2 | 2 | 3 | 3 | 4 | 4 | 4 | 4 |
……
char string[81],c;
int i,num=0,word=0;
gets(string);
for (i=0;(c=string[i])!=‘\0’;i++)
if(c==‘ ’) word=0;
else if(word==0)
{ word=1;
num++;
}
printf(“%d words\n”,num);
……
例 有3个字符串,要求找出其中最大者
-
解题思路:设一个二维的字符数组str,大小为3×10。每一行存放一个字符串 char str[3][10];
-
经过三次两两比较,就可得到值最大者,把它放在一维字符数组string中
if (strcmp(str[0],str[1])>0)
strcpy(string,str[0]);
else
strcpy(string,str[1]);
if (strcmp(str[2],string)>0)
strcpy(string,str[2]);
可以把**str[0],str[1],str[2]**看作3个一维字符数组,可以把它们如同一维数组那样进行处理
for (i=0;i<3;i++)
gets (str[i]);

#include<stdio.h>
#include<string.h>
int main ( )
{
char str[3][10];
char string[10];
int i;
for (i=0;i<3;i++)
gets (str[i]);
if (strcmp(str[0],str[1])>0)
strcpy(string,str[0]);
else
strcpy(string,str[1]);
if (strcmp(str[2],string)>0)
strcpy(string,str[2]);
printf("\nthe largest:\n%s\n",string);
return 0;
}
.
第7章 函数实现模块化程序设计
7.1为什么要用函数
7.1.1 问题:
- 如果程序的功能比较多,规模比较大,把所有代码都写在main函数中,就会使主函数变得庞杂、头绪不清,阅读和维护变得困难
- 有时程序中要多次实现某一功能,就需要多次重复编写实现此功能的程序代码,这使程序冗长,不精炼
7.1.2 解决的方法:用模块化程序设计的思路
- 可以使用库函数
- 可以使用自己编写的函数
- 在程序设计中要善于利用函数,可以减少重复编写程序段的工作量,同时可以方便地实现模块化的程序设计
7.1.3 例:输出以下的结果,用函数调用实现。
? ************
? How do you do!
? ************
解题思路:
在输出的文字上下分别有一行“*”号,显然不必重复写这段代码,用一个函数print_star来实现输出一行“*”号的功能。
再写一个print_message函数来输出中间一行文字信息
用主函数分别调用这两个函数
#include <stdio.h>
int main()
{ void print_star();
void print_message();
print_star(); print_message();
print_star();
return 0;
}
void print_star()
{ printf(“******************\n”); }
void print_message()
{ printf(“ How do you do!\n”); }
7.1.4 说明:
(1) 一个C程序由一个或多个程序模块组成,每一个程序模块作为一个源程序文件。对较大的程序,一般不希望把所有内容全放在一个文件中,而是将它们分别放在若干个源文件中,由若干个源程序文件组成一个C程序。这样便于分别编写、分别编译,提高调试效率。一个源程序文件可以为多个C程序共用。
(2) 一个源程序文件由一个或多个函数以及其他有关内容(如预处理指令、数据声明与定义等)组成。一个源程序文件是一个编译单位,在程序编译时是以源程序文件为单位进行编译的,而不是以函数为单位进行编译的。
(3) C程序的执行是从main函数开始的,如果在main函数中调用其他函数,在调用后流程返回到main函数,在main函数中结束整个程序的运行。
(4) 所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的。一个函数并不从属于另一个函数,即函数不能嵌套定义。函数间可以互相调用,但不能调用main函数。main函数是被操作系统调用的。
(5) 从用户使用的角度看,函数有两种。
①库函数,它是由系统提供的,用户不必自己定义而直接使用它们。应该说明,不同的C语言编译系统提供的库函数的数量和功能会有一些不同,当然许多基本的函数是共同的。
②用户自己定义的函数。它是用以解决用户专门需要的函数。
(6) 从函数的形式看,函数分两类。
① 无参函数。无参函数一般用来执行指定的一组操作。无参函数可以带回或不带回函数值,但一般以不带回函数值的居多。
② 有参函数。在调用函数时,主调函数在调用被调用函数时,通过参数向被调用函数传递数据,一般情况下,执行被调用函数时会得到一个函数值,供主调函数使用。
7.2怎样定义函数
C语言要求,在程序中用到的所有函数,必须==“先定义,后使用”==
指定函数名字、函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。
7.2.1 为什么要定义函数
- 指定函数的名字,以便以后按名调用
- 指定函数类型,即函数返回值的类型
- 指定函数参数的名字和类型,以便在调用函数时向它们传递数据
- 指定函数的功能。这是最重要的,这是在函数体中解决的
- 对于库函数,程序设计者只需用#include指令把有关的头文件包含到本文件模块中即可
- 程序设计者需要在程序中自己定义想用的而库函数并没有提供的函数
7.2.2 定义函数的方法
1.定义无参函数
定义无参函数的一般形式为:
类型名 函数名(void)
{
函数体
}
2.定义有参函数
定义有参函数的一般形式为:
类型名 函数名(形式参数表列)
{
函数体
}
3. 定义空函数
定义空函数的一般形式为:
类型名 函数名( )
{ }
- 先用空函数占一个位置,以后逐步扩充
- 好处:程序结构清楚,可读性好,以后扩充新功能方便,对程序结构影响不大
该函数名为max,它有两个float类型的参数,返回值为float类型。在函数体内实现了求两个数中较大的数,并将它返回。折扣后的价格。
void displayDiscount()
{
float price, discount_amt;
printf("请输入价格");
scanf("%f, &price);
discount_amt = 0.75 * price;
printf("折扣额为 %f", discount_amt);
}
float max(float x, float y)
{
float m;
if (x > y)
m=x;
else
m=y;
return m;
}
7.3调用函数
7.3.1函数调用的形式
按函数调用在程序中出现的形式和位置来分,可以有以下3种函数调用方式:
1. 函数调用语句
-
把函数调用单独作为一个语句 如printf_star(); -
这时不要求函数带回值,只要求函数完成一定的操作
2. 函数表达式
-
函数调用出现在另一个表达式中 如c=max(a,b); -
这时要求函数带回一个确定的值以参加表达式的运算
3. 函数参数
7.3.2函数调用时的数据传递
7.3.2.1 形式参数和实际参数
- 在调用有参函数时,主调函数和被调用函数之间有数据传递关系
- 定义函数时函数名后面的变量名称为“形式参数”(简称“形参”)
- 主调函数中调用一个函数时,函数名后面参数称为“实际参数”(简称“实参”)
- 实际参数可以是常量、变量或表达式
7.3.2.2 实参和形参间的数据传递
- 在调用函数过程中,系统会把实参的值传递给被调用函数的形参
- 或者说,形参从实参得到一个值
- 该值在函数调用期间有效,可以参加被调函数中的运算
例7.3.2 输入两个整数,要求输出其中值较大者。要求用函数来找到大数。
解题思路:
(1)函数名应是见名知意,今定名为max
(2) 由于给定的两个数是整数,返回主调函数的值(即较大数)应该是整型
(3)max函数应当有两个参数,以便从主函数接收两个整数,因此参数的类型应当是整型
先编写max函数:
int max(int x,int y)
{
int z;
z=x>y?x:y;
return(z);
}
在max函数上面,再编写主函数
#include <stdio.h>
int main()
{ int max(int x,int y); int a,b,c;
printf(“two integer numbers: ");
scanf(“%d,%d”,&a,&b);
c=max(a,b);
printf(“max is %d\n”,c);
}
7.3.3函数调用的过程
在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元。

- 调用结束,形参单元被释放
- 实参单元仍保留并维持原值,没有改变
- 如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的值
7.3.4函数的返回值
通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数值(函数的返回值)
(1)函数的返回值是通过函数中的return语句获得的。
- 一个函数中可以有一个以上的return语句,执行到哪一个return语句,哪一个就起作用
- return语句后面的括号可以不要
(2) 函数值的类型。应当在定义函数时指定函数值的类型
(3)在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致
- 如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准
例7.3.4将例7.3.2稍作改动,将在max函数中定义的变量z改为float型。函数返回值的类型与指定的函数类型不同,分析其处理方法。
解题思路:如果函数返回值的类型与指定的函数类型不同,按照赋值规则处理。
#include <stdio.h>
int 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);
return 0;
}
int max(float x,float y)
{ float z;
z=x>y?x:y;
return( z ) ;
}
7.4对被调用函数的声明和函数原型
在一个函数中调用另一个函数需要具备如下条件:
(1) 被调用函数必须是已经定义的函数(是库函数或用户自己定义的函数)
(2) 如果使用库函数,应该在本文件开头加相应的#include指令
(3) 如果使用自己定义的函数,而该函数的位置在调用它的函数后面,应该声明
例7.4 输入两个实数,用一个函数求出它们之和。
- 解题思路:用add函数实现。首先要定义add函数,它为float型,它应有两个参数,也应为float型。特别要注意的是:要对add函数进行声明。
- 分别编写add函数和main函数,它们组成一个源程序文件
- main函数的位置在add函数之前
- 在main函数中对add函数进行声明
#include <stdio.h>
int main()
{ float add(float x, float y);
float a,b,c;
printf("Please enter a and b:");
scanf("%f,%f",&a,&b);
c=add(a,b);
printf("sum is %f\n",c);
return 0;
}
float add(float x,float y)
{ float z;
z=x+y;
return(z);
}
如 float add(float x, float y);
float add(float, float);
7.5函数的嵌套调用
- C语言的函数定义是互相平行、独立的
- 即函数不能嵌套定义
- 但可以嵌套调用函数
- 即调用一个函数的过程中,又可以调用另一个函数

例7.5 输入4个整数,找出其中最大的数。用函数的嵌套调用来处理。
解题思路:
main中调用max4函数,找4个数中最大者
max4中再调用max2,找两个数中的大者
max4中多次调用max2,可找4个数中的大者,然后把它作为函数值返回main函数
main函数中输出结果
#include <stdio.h>
int main()
{ int max4(int a,int b,int c,int d);
int a,b,c,d,max;
printf(“4 interger numbers:");
scanf("%d%d%d%d",&a,&b,&c,&d);
max=max4(a,b,c,d);
printf("max=%d \n",max);
return 0;
}
int max4(int a,int b,int c,int d)
{ int max2(int a,int b);
int m;
m=max2(a,b);
m=max2(m,c);
m=max2(m,d);
return(m);
}
int max2(int a,int b)
{ if(a>=b)
return a;
else
return b;
}
7.6函数的递归调用
- 在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
- C语言的特点之一就在于允许函数的递归调用。
int f(int x)
{
int y,z;
z=f(y);
return (2*z);
}

例7.6 有5个学生坐在一起**
- 问第5个学生多少岁?他说比第4个学生大2岁
- 问第4个学生岁数,他说比第3个学生大2岁
- 问第3个学生,又说比第2个学生大2岁
- 问第2个学生,说比第1个学生大2岁
- 最后问第1个学生,他说是10岁
- 请问第5个学生多大
解题思路:
-
要求第5个年龄,就必须先知道第4个年龄 -
要求第4个年龄必须先知道第3个年龄 -
第3个年龄又取决于第2个年龄 -
第2个年龄取决于第1个年龄 -
每个学生年龄都比其前1个学生的年龄大2 age(5)=age(4)+2 age(4)=age(3)+2 age(3)=age(2)+2 age(2)=age(1)+2 age(1)=10 

#include <stdio.h>
int main()
{ int age(int n);
printf("NO.5,age:%d\n",age(5));
return 0;
}
int age(int n)
{ int c;
if(n==1) c=10;
else c=age(n-1)+2;
return(c);
}

例 用递归方法求n!。
解题思路:
- 求n!也可以用递归方法,即5!等于4!×5,而4!=3!×4…,1!=1
- 可用下面的递归公式表示:
-
#include <stdio.h>
int main()
{int fac(int n);
int n; int y;
printf("input an integer number:");
scanf("%d",&n);
y=fac(n);
printf("%d!=%d\n",n,y);
return 0;
}
int fac(int n)
{
int f;
if(n<0)
printf("n<0,data error!");
else if(n==0 | | n==1)
f=1;
else f=fac(n-1)*n;
return(f);
}

7.7数组作为函数参数
7.7.1 数组元素作函数实参
例 输入10个数,要求输出其中值最大的元素和该数是第几个数。
解题思路:
- 定义数组a,用来存放10个数**
- 设计函数max,用来求两个数中的大者
- 在主函数中定义变量m,初值为a[0],每次调用max函数后的返回值存放在m中
- 用“打擂台”算法,依次将数组元素a[1]到a[9]与m比较,最后得到的m值就是10个数中的最大者
#include <stdio.h>
int main()
{ int max(int x,int y);
int a[10],m,n,i;
printf(“10 integer numbers:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
for(i=1,m=a[0],n=0;i<10;i++)
{ if (max(m,a[i])>m)
{ m=max(m,a[i]);
n=i;
}
}
printf(“largest number is %d\n",m);
printf(“%dth number.\n“,n+1);
}
int max(int x,int y)
{ return(x>y?x:y); }
7.7.2 数组名作函数参数
- 除了可以用数组元素作为函数参数外,还可以用数组名作函数参数(包括实参和形参)
- 用数组元素作实参时,向形参变量传递的是数组元素的值
- 用数组名作函数实参时,向形参 传递的是数组首元素的地址
例 有一个一维数组score,内放10个学生成绩,求平均成绩。
解题思路:
- 用函数average求平均成绩,用数组名作为函数实参,形参也用数组名
- 在average函数中引用各数组元素,求平均成绩并返回main函数
#include <stdio.h>
int main()
{ float average(float array[10]);
float score[10],aver; int i;
printf("input 10 scores:\n");
for(i=0;i<10;i++)
scanf("%f",&score[i]);
printf("\n");
aver=average(score);
printf("%5.2f\n",aver);
return 0;
}
float average(float array[10])
{ int i;
float aver,sum=array[0];
for(i=1;i<10;i++)
sum=sum+array[i];
aver=sum/10;
return(aver);
}
例7.11 有两个班级,分别有35名和30名学生,调用一个average函数,分别求这两个班的学生的平均成绩。
解题思路:
- 需要解决怎样用同一个函数求两个不同长度的数组的平均值的问题
- 定义average函数时不指定数组的长度,在形参表中增加一个整型变量i
- 从主函数把数组实际长度从实参传递给形参i
- 这个i用来在average函数中控制循环的次数
- 为简化,设两个班的学生数分别为5和10
#include <stdio.h>
int main()
{ float average(float array[ ],int n);
float score1[5]={98.5,97,91.5,60,55};
float score2[10]={67.5,89.5,99,69.5,
77,89.5,76.5,54,60,99.5};
printf(“%6.2f\n”,average(score1,5));
printf(“%6.2f\n”,average(score2,10));
return 0;
}
float average(float array[ ],int n)
{ int i;
float aver,sum=array[0];
for(i=1;i<n;i++)
sum=sum+array[i];
aver=sum/n;
return(aver);
}
7.7.3 多维数组名作函数参数
…
7.8局部变量和全局变量
7.8.1 局部变量
定义变量可能有三种情况:
- 在函数的开头定义
- 在函数内的复合语句内定义
- 在函数的外部定义
在一个函数内部定义的变量只在本函数范围内有效
在复合语句内定义的变量只在本复合语句范围内有效
在函数内部或复合语句内部定义的变量称为==“局部变量”==
float f1( int a)
{ int b,c;
……
}
char f2(int x,int y)
{ int i,j;
……
}
int main( )
{ int m,n;
……
return 0;
}
int main ( )
{ int a,b;
……
{ int c;
c=a+b;
……
}
……
}
7.8.2 全局变量
在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量**
外部变量是全局变量(也称全程变量)
全局变量可以为本文件中其他函数所共用
有效范围为从定义变量的位置开始到本源文件结束
int p=1,q=5
float f1(int a)
{ int b,c; …… }
char c1,c2;
char f2 (int x, int y)
{ int i,j; …… }
int main ( )
{ int m,n;
……
return 0;
}
例1
有一个一维数组,内放10个学生成绩,写一个函数,当主函数调用此函数后,能求出平均分、最高分和最低分。
解题思路:调用一个函数可以得到一个函数返回值,现在希望通过函数调用能得到3个结果。可以利用全局变量来达到此目的。
#include <stdio.h>
float Max=0,Min=0;
int main()
{ float average(float array[ ],int n);
float ave,score[10]; int i;
printf("Please enter 10 scores:\n");
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);
return 0;
}
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);
}

建议不在必要时不要使用全局变量
例2
若外部变量与局部变量同名,分析结果。
#include <stdio.h>
int a=3,b=5;
int main()
{ int max(int a,int b);
int a=8;
printf(“max=%d\n”,max(a,b));
return 0;
}
int max(int a,int b)
{ int c;
c=a>b?a:b;
return(c);
}
7.9变量的存储方式和生存期
7.10 关于变量的声明和定义
7.11 内部函数和外部函数
第八章 指针
8.1 回顾
- 数组是可以在内存中连续存储多个元素的结构数组中的所有元素必须属于相同的数据类型
- 数组必须先声明,然后才能使用。声明一个数组只是为该数组留出内存空间,并不会为其赋任何值
- 数组的元素通过数组下标访问
- 一维数组可用一个循环动态初始化,而二维数组可用嵌套循环动态初始化
8.2 目标
- 理解指针的概念
- 定义指针变量
- 掌握对指针的操作
- 理解指针和数组的关系
8.3 指针的概念
指针是一个变量,它存储另一个对象的内存地址
指针的声明由基本类型、星号 (*) 和变量名组成
为指针赋值,赋值运算符右侧必须是一个地址如果是普通变量需要在前面加一个取地址运算符 &;如果是另一个指针变量或者是一个数组,不需要加 &运算符
运算符 * 用于返回指针指向的内存地址中存储的值
8.4 指针简介

指针也是一个变量,只不过该变量中存储的是另一个对象的内存地址
如果一个变量存储另一个对象的地址,则称该变量指向这个对象
由于指针值是数据,指针变量可以赋值,所以一个指针的指向在程序执行中可以改变。指针p 在执行中某时刻指向变量x,在另一时刻也可以指向变量y
8.5 声明并初始化指针变量

值为NULL的指针称为空指针,这意味着,指针并不指向任何地址。
在头文件 stdio.h 中,NULL 定义为常量。
?
8.6 与指针相关的运算符
int num, *ptrnum;
ptrnum = #
int num, *ptrnum;
ptrnum = #
*ptrnum=15;
8.7 指针的特点
8.7.1 示例
#include <stdio.h>
void main()
{
int var = 10;
int *ptr_var;
ptr_var = &var;
printf(" var 的值是: %d", var);
printf("\n var 的内存地址是: %x", &var);
printf("\n 指针 ptr_var 的地址是: %x\n", &ptr_var);
printf("\n var 的值是: %d", *ptr_var);
printf("\n var 的地址是: %x\n", ptr_var);
}
8.7.2 示例
void main()
{
int num1 = 50, num2 = 100;
int *ptr1, *ptr2;
ptr1 = &num1;
printf(" num1 的值是: %d", *ptr1);
printf("\n num1 的地址是: %x \n", ptr1);
ptr2 = &num2;
printf("\n num2 的值是: %d", *ptr2);
printf("\n num2 的地址是: %x \n", ptr2);
*ptr2 = *ptr1;
printf("\n 重新赋值后 num2 的值是: %d", *ptr2);
printf("\n 重新赋值后 num2 的地址是: %x\n", ptr2);
}

8.8 指针运算
8.8.1 指针赋值运算

8.8.2 指针算术运算
使用递增/递减运算符(++ 和 --)将指针递增或递减

8.8.3 指针算术运算
将指针加上或者减去某个整数值

8.8.4 指针关系运算
比较两个指针
#include<stdio.h>
void main ()
{
int *ptrnum1, *ptrnum2;
int value = 1;
ptrnum1 = &value;
value += 10;
ptrnum2 = &value;
if (ptrnum1 == ptrnum2)
printf("\n 两个指针指向同一个地址\n");
else
printf("\n 两个指针指向不同的地址\n");
}
8.9 指向数组的指针
- 一个数组存储在一块连续内存单元中;数组名就是这块连续内存单元的首地址;
- 第 (i + 1) 个数组元素的地址可表示为 &data[i] 或 (data+i)。
- 可以通过以下方式为指向数组的指针赋值:
? int a[10];
? pa=&a[0]; // 或者 pa=a;
? int *ptr,data[10];
? ptr=data+3;//或者ptr=&data[3]
8.9.1 示例1

#include <stdio.h>
void main()
{
int data[] = {5, 10, 15, 20, 25};
int i = 0;
int *ptr;
ptr = data;
while(i < 5)
{
printf(“\n 第 %d 个元素的存储地址为:%x,
值为: %d\n“,i+1, ptr, *ptr);
i++;
ptr++;
}
}
8.9.2 示例2

void main()
{
char name[5] = {'M', 'A', 'D', 'A', 'M'};
int flag = 1;
char *start=name, *end=name+4;
for(;start <= end; start++, end--){
if(*start != *end)
{
flag = 0;break;
}
}
if(flag)
printf("\n 该字符串是回文串\n");
else
printf("\n 该字符串不是回文串\n");
}
8.10 小结
-
指针的算术运算的含义是指针的移动,将指针执行加上或者减去一个整数值n的运算相当于指针向前或向后移动n个数据单元 -
指针可以执行比较相等的运算,用来判断两个指针是否指向同一个变量 -
指向数组的指针,存储的是数组中元素的地址。数组data的第 (i + 1) 个元素的地址可表示为 &data[i] 或 (data+i)
到此基本上涵盖了 C 语言的基本知识
想了解更多请私信,后续还会补充一些,不足的地方请指出。
|