该笔记主要根据岭南学院专插本的考纲进行编写。用到的教材是谭浩强的《C程序设计》第三版
适用人群:对C有一定基础,针对考点快速复习的考生。但不限于岭南学院专插本考生
亮点:①结合考纲精简笔记。②对教材的课后习题给出了答案,答案都是在vscode执行验证过的。读者可以很方便地进行参考,不需再花费大量时间查找答案。
内容:
每一章节前有考纲要求。原原本本的考纲。之后的 三级标题 笔记 和 课后练习是我编辑的。
笔记主要是提取浓缩,主要针对的是快速复习,不适合初学人群。详细的讲解肯定是以课本为主。
当然也适合非岭南专插本的考生参考。知识点是共通的,相较于其他学校考纲的要求,岭南的考纲没有要求掌握课本第9章的预处理命令。其他考点其实都大同小异。可以使用本笔记进行复习,再按自身情况复习第九章预处理命令这一章。另外:本笔记有上传到到文件,有需要的同学可以在CSDN下载,进行二次编辑。修改成更适合自己的笔记。
题型主要有:填空、选择、阅读程序写结果、程序填空和编程题等题型。
1、识记:
C语言的特点;C程序的结构
2、理解:
运行C程序的步骤和方法;
3、应用:
用C语言编写简单的屏幕输出程序
1.1. C语言是计算机高级语言。可以编写系统软件,也可用来编写应用软件
1.2. 在B语言基础上发展起来的
特点
1.3. 32个关键字
1.4. 34种运算符
1.5. 数据类型丰富
1.6. 具有结构化的控制语句
1.7. 语法限制不太严格
1.8. 可以直接访问物理地址,进行位(bit)操作。可以直接对硬件进行操作。又具有高级语言的功能,又具有低级语言的许多功能**
1.9. 生成目标代码质量高,程序执行效率高**
1.10. 可移植性好
2.1. c程序由函数构成,至少包含一个main函数。函数是C程序的基本单位
2.2 . 一个函数由两部分组成
2.2.1. 函数的首部,即函数的第一行。包括函数名,函数类型,函数属性,函数参数(形式参数)名,参数类型
2.2.1.1 . 一个函数名后面必须跟一对圆括号,括号内写函数的参数名及其类型。函数可以没有参数
2.2.1.2. 函数体。即函数首部下面的花括号内的部分。如果一个函数内有多个花括号,则最外层的一对花括号为函数体的范围。函数体一般包含以下两个部分
2.2.1.2.1. 声明部分
2.2.1.2.2. 执行部分。当然也可以没有声明部分。空函数
例如:void dump(){}
2.3. 程序总是从main函数开始执行。不论放在程序的哪里
2.4. C程序书写格式自由,一个语句可以分在多行上。C程序没有行号
2.5. 每个语句和数据声明的最后必须有一个分号。分号是C语句的必要组成部分。即使是程序中最后一个语句也应包含分号
2.6. C语言本身没有输入输出语句。输入输出的操作由库函数scanf和printf等函数来完成
2.7. 注解 /………/
答:1 简介紧凑,灵活方便 2 运算符丰富 3 数据结构丰富 4 c语言是结构是语言 5 语法限制不太严格,程序设计自由度大 6 允许直接访问物理地址,可以直接对硬件进行操作 7 生成代码质量高,程序执行效率高(只比汇编低10%~20%)8 适用范围大,可移植性好
适合作为系统语言,既可用来编写系统软件,也可以用来编写应用软件,和其他高级语言相比,c语言写的程序运行效率相对较高。可执行性好,可移植性也很好。用它写·的程序只需做很少的修改甚至不用修改就可以再LINUX,UNIX等系统上运行
C程序是由函数构成的。函数由两部分组成:1.函数的首部 2 .函数体(声明部分,执行部分)
在c语言中,函数是程序的基本组成单位,因此可以很方便地用函数作为程序模块来实现C语言程序。利用函数,不仅可以实现程序的模块化,程序设计的简单和直观。提高了程序的易读性和可维护性。而且还可以把握程序中普通用到的一些计算或操作编成通用的函数,以供随时调用,这样可以大大地减轻程序员的代码工作量
***************************
Very good
***************************
1、识记:
算法的概念;算法的特性
2、理解:
最基本的算法;结构化程序设计方法
答:广义地说:为解决一个问题而采取的方法和步骤,就称为“算法”。
计算机的算法可分为两大类别:数值运算算法和非数值运算算法。数值运算的目的是求数值解。非数值运算包括的面十分广泛。最常见的是用于事务管理领域。
一个算法应该具有以下特点
(1) 有穷性。一个算法应包含有限的操作步骤,而不能是无限的
(2) 确定性。算法中的每一个步骤都应当是确定的。而不应当是含糊的,模棱两可的
(3) 有零个或多个输入
(4) 有一个或多个输出
(5) 有效性。算法中的每一个步骤都应当有效地执行,并得到确定的结果
为了表示一个算法,可以用不同的方法。常用的方法有:自然语言,传统流程图,结构化流程图,伪代码,PAD图等
就是人们日常使用的语言。除了很简单的问题以外,一般不用自然语言描述算法
(1)自顶向下
(2)逐步细化
(3)模块化设计
(4)结构化编码
2.1. 什么是算法?试从日常生活中找3个例子,描述他们的算法
2.2. 什么叫结构化的算法?为什么要提倡结构化的算法
2.3. 试述3中基本结构的特点,你能否自己另外设计两种基本结构(要符合基本结构的特点)
2.4. 用传统流程图表示求解一下问题的算法
(1)有两个瓶子A和B,分别盛放醋和酱油,要求将它们互换(即A瓶原来盛醋,现
改盛酱油,B瓶则相反)。
(2)依次将10个数输入,要求将其中最大的数输出。
(3)有3个数a、b、c,要求按大小顺序把它们输出。
(4)求1+2+3+…+100。
(5)判断一个数n能否同时被3和5整除。
(6)将100~200之间的素数输出
(7)求两个数m和n的最大公约数
(8)求方程式ax2+bx+c=0的根。分别考虑:①有两个不等的实根;②有两个相等
的实根;
2.5. 用N-S图表示2.4题中各题的算法
2.6. 用伪代码表示2.4题中各题的算法
2.7. 什么叫结构化程序设计?它的主要内容是什么?
2.8. 用自顶向下、逐步细化的方法进行以下算法的设计:
(1)输出1900—2000年中是闰年的年份,符合下面两个条件之一的年份是闰年
①能被4整除但不能被100整除;②能被100整除且能被400整除。
(2)求ax2+bx+c=0的根。分别考虑D=b2-4ac大于0、等于0和小于0这3种
情况。
(3)输入10个数,输出其中最大的一个数。
第3章 数据类型、运算符与表达式
考核知识点:
1、识记:
(1)常量与变量的概念、常量的几种形式、常量和变量的定义;
(2)标识符和关键字;
(3)变量赋初值
2、理解:
(1)几种基本数据类型的表示形式,以及定义于基本数据类型之上的各种运算(算术、赋值、关系、逻辑、条件、逗号等);
(2)常量的意义及几种基本数据类型的常量的表示形式,符合常量的定义与使用,变量的定义及自定义标识符的规范;
(3)各种数据类型间的混合运算;
(4)不同类型间数据转换的原则与方法。
3、应用:
(1)变量赋初值
(2)算数运算符与算术表达式
(3)赋值运算符与赋值表达式
常量需要使用#define 进行声明
c语言规定标识符只能由字母,数字和下划线3种字符组成,且第一个字符必须为字母或下划线
#define PRICE 30
(1)十进制整数
(2)八进制整数 0开头
(3)十六进制整数0x开头 负数表示 :-0x123
负数的存放形式
(1)基本整型 int
(2)短整型 short
(3)长整型 long
另外还有无符号整型 只需在前面加上 unsigned
(4)一个整常量后面加一个字母 u或U 认为是 unsigned int 型
(5)在一个整常量后面加一个字母l或L则认为是long int 型常量
(1)十进制小数形式
(2)指数形式 如123e3 或 123E3
浮点型数据在内存中的存放形式
浮点型数据都是按照指数形式存储的,系统吧一个浮点型数据分成小数部分和指数部分。分别存放。指数部分采用规范化的指数形式。
浮点型变量的分类
浮点型变量分为单精度(float型)和双精度(double)型。和长双精度(long double) 3类
浮点型数据的舍入误差
#include
void main()
{
float a ,b ;
a = 123456.789e5;
b = a + 20;
printf("%f\n",b);
//结果 为 12345678868.000000
}
c语言的字符常量是用单撇号括起来的一个字符 如 ‘a’
使用 “\”做转义
字符型变量用来存放字符常量,它只能放一个字符
一个字符常量放到一个字符变量中,实际上并不是把该字符本身放到内存单元中去。而是将对应的ASCII代码放到存储单元中。实际上就是存放一个整型数字
#include
void main()
{
char c1, c2 ;
c1 =97;
c2 = 98;
printf("%c %c \n" , c1 , c2);
printf("%d %d \n" , c1 , c2);
//输出结果
// a b
// 97 98
#include
#include
//大小写字母转换
void main()
{
char input;
int diff = 'a' -'A';
int output;
printf("输入任意字母进行大小写字母转换\n");
scanf("%c", &input);
//输入小写字母
if(input>= 'a')
{
output = input - diff;
}else{//输入大写字母
output = input + diff;
}
printf("转换之后的字母为:%c\n",output);
}
字符串是由 “” 双引号括起来的多个字符
‘a’ 和 “a” 的区别: 在每一个字符串常量的结尾加一个“字符串结束标志” ,以便系统据此判断字符串是否结束 C规定以字符**‘\0’** 作为字符串结束标志
不同类型数据进行运算,会转换成其中最高级的类型进行运算
其中float 的运算中,都会转换成double进行运算
每当想找哪个运算符优先级高时,很多时候总是想找的就没有,真让人气愤!现在,终于有个我个人觉得非常全的,分享给大家。
初级运算符( )、[ ]、->、. 高于 单目运算符 高于 算数运算符(先乘除后加减) 高于 关系运算符 高于 逻辑运算符(不包括!) 高于 条件运算符 高于 赋值运算符 高于 逗号运算符。
位运算符的优先级比较分散。
除了赋值运算符、条件运算符、单目运算符三类的平级运算符之间的结合顺序是从右至左,其他都是从左至右。
1,基本的算术运算符
2,算术表达式和运算符的优先级和结合性
3,强制类型转换运算符
4,自增,自减运算符
++i , –i (在使用i之前,先使i的值加减1)
i++,i– (在使用i之后,在i的值加减1)
注意:
(1)只能用于常量或表达式
(2)++ 或 -- 的结合方向是自右向左。
如果有-i++,i的左面是负号运算符,右面是自加运算符。如果i的原值等于3,若按左结合性,
5,有关表达式使用中的问题说明
赋值运算符
类型转换
(1) 将浮点型数据赋给整型变量时,舍弃小数部分
(2)将整型数据赋给单,双精度变量时,数值不变。但以浮点数形式存储到变量中。
(3)将一个double型数据赋给float变量时。截取其前面7位有效数字,存放到float变量的存储单元。但应注意数值范围不能溢出
(4)字符型数据赋给整型变量时
(5)将一个int,short,long型数据赋给一个char型变量时。只将其低8位原封不动地送到char型变量(即截断);
(6)将带符号的整型数据(int)型赋给long型变量时,要进行符号扩展
反之将一个long型数据赋给一个int型变量,值将long 型数据中低16位原封不动地送到整型变量(即截断)
(7)将unsigned int 型数据赋给long int 型变量时,不存在符号扩展问题。只需将最高为补0即可 。将一个unsigned类型数据赋给一个占字节数相同的非unsigned型整型变量,将unsigned型变量的内容原样送到非unsigned型变量中。但如果数据范围超过相应整型的范围,则会出现数据错误。
(8) 将非unsigned型数据赋值给长度相同的unsigned型变量,也是原样赋值(连原有的符号位也作为数值一起传送)
#include
//有符号位的数据类型给没符号的数据类型赋值,会全部作为数值复制过去
void main()
{
unsigned a ;
int b = -1;
a = b;
printf("%u\n",a);
//输出结果为:4294967295
}
**总结:**从大到小都是截断。从小到大会尽量维持原数值
复合的赋值运算符
a+=3 => a=a+3
x*=y+8 => x=x*(y+8)
二目运算符都可以与赋值符一起组合成复合赋值符
赋值表达式
#include
void main()
{
//赋值表达式
int a = 12;
a+=a-=a*a;
printf("a:%d\n",a);
//输出值为-264
//执行顺序
//a+=(a-=(a*a))
}
逗号表达式的一般形式为 表达式1,表达式2
#include
void main()
//逗号表达式
{
int x , a ;
x = (a = 3 , 6 * 3 ); // 18
printf("%d\n",x);
x = a = 3, 6 * 3 ;
printf("%d\n",x); // 3
}
3.1 请将C语言的数据类型和其他高级语言的数据类型作比较。c有哪些特点?
既有一般高级语言的功能,又具有许多低级语言的功能。所以其功能更强大,目标代
码质量更高,执行效率更高。但也存在着语法限制不太严格,容易出现错误,难度较大的
问题
3.2 c语言为什么规定对所有用到的变量要先定义,后使用,这样做有什么好处?
(1)凡未被事先定义的,系统不把它认作变量名,也就是“先定义,后使用“;提醒用户检查错误,避免使用变量名时出错
(2)每一个变量被指定为一个确定类型,在编译时就能为其分配相应的存储单元。
(3)指定每一变量属于一个类型,这就便于在编译时据此检查在程序中要求对改变量进行的运算是否合法
3.3 请将下面各组用八进制数和十六进制数表示
(1)10(2)32(3)75(4)-617(5)-111(6)2483(7)-28654(8)21003
#include
#define INT_SIZE sizeof(int)
#define EIG_BIT (INT_SIZE*8+1)/3
#define HEX_BIT (INT_SIZE*8+2)/4
void main()
{
int n =0;
printf("输入十进制整数\n");
scanf("%d",&n);
toEight(n);
toHex(n);
}
int toEight(int n)
{
//存放新的数字的数组
int numArr[EIG_BIT];
int i ; int temp;
printf("十进制 %d ===> 八进制 ",n);
if (n < 0)
{
n = -n;
printf("-");
}
for(i=0;i<EIG_BIT;i++)
{
numArr[i] = n ;
n >>= 3;
temp = (n <<3);
numArr[i] -= (n << 3);
if(n == 0) break ;
//printf("%d",numArr[i]);
}
for(; i >= 0 ; i--){
printf("%d",numArr[i]);
}
printf("\t");
return 0;
}
int toHex(int n)
{
//存放新的数字的数组
int numArr[HEX_BIT];
int i ; int temp;
printf("十进制 %d ===> 十六进制 ",n);
if (n < 0){
n = -n;
printf("-");
}
for(i=0;i<HEX_BIT;i++)
{
numArr[i] = n ;
n >>= 4;
temp = (n << 4);
numArr[i] -= (n << 4);
if(n == 0) break ;
//printf("%d",numArr[i]);
}
for(; i >= 0 ; i--){
if(numArr[i]<10)
{
printf("%d",numArr[i]);
}else
{
printf("%c",numArr[i]-10+65);
}
}
printf("\t");
return 0;
}
变量的类型 | 25 | -2 | 32769 |
---|---|---|---|
int(16位) | 0000 0000 0001 1001 | 1111 1111 1111 1110 | 0000 0000 0000 0001 |
long(32位) | (0000)x6 0001 1001 | (1111)x6 1111 1110 | (0000)x6 0000 0001 |
short(16) | 0000 0000 0001 1001 | 1111 1111 1111 1110 | 0000 0000 0000 0001 |
signed char(8) | 0001 1001 | 1111 1110 | 0000 0001 |
unsigned int | 0000 0000 0001 1001 | 1111 1111 1111 1110 | 0000 0001 |
unsigned long | (0000)x6 00001 1001 | (0000)x6 1111 1110 | (0000)x6 0000 0001 |
unsigned short | 0000 0000 0001 1001 | 1111 1111 1111 1110 | 0000 0000 0000 0001 |
unsigned char | 0001 1001 | 1111 1110 | 0000 0001 |
**3.5 ** 字符常量和字符串常量有什么区别?
1,字符常量是由一对单引号括起来的单个字符,本质上是一个数字。
2,字符串常量是由一对双括号括起来的字符集合。本质上是一串字符集合的内存地址
3.6 写出一下程序的运行结果
#include
void main()
{
char c1 = 'a',c2='b',c3='c',c4='\101' ,c5='\116';
printf("a%c b%c\tc%c\tabc\n",c1,c2,c3);//aa bb cc abc
printf("\t\b%c %c\n",c4,c5);//A N
}
#include
void main()
{
char c1 = 'C' ,c2 = 'h',c3 = 'i',c4 = 'n' ,c5 = 'a';
int diff = 4 ;
c1+=diff;
c2+=diff;
c3+=diff;
c4+=diff;
c5+=diff;
printf("%c%c%c%c%c",c1,c2,c3,c4,c5);
}
可以,因为char本质上存入的是一个数值,在打印的时候是去查ASCII码表输出对应的字符。
//(1)
#include
void main()
{
double x = 2.5;
int a =7;
double y=4.7;
double result1 = x + a%3*(int)(x+y)%2/4;
printf("%.2f",result1);//2.50
}
//(2)
#include
void main()
{
int a = 2,b=3;
double x=3.5,y=2.5;
double result = (float)(a+b)/2+(int)x%(int)y;
printf("%.2f",result); //3.5
}
3.10 写出下面程序的运行结果
答案:9,11 , 9,10
3.11 写出下面赋值的结果。表3-5中所写出数值是要将它赋给其他类型变量,将所有空格填上赋值后的数值。
3.12
(1)24 (2)10 (3)60 (4)0 (5)0 (6)0
#include
void main()
{
int a = 12; int n = 5;
printf("(1)%d\n",a+=a);
a=12;a-=2;
printf("(2)%d\n",a);
a=12;a*=2+3;
printf("(3)%d\n",a);
//复合运算符的优先级和赋值运算符相等,比计算运算符要低
a=12;a/=a+a;
printf("(4)%d\n",a);
a=12;a&=(n%=2);
printf("(5)%d\n",a);
a=12;a+=a-=a*=a;
printf("(6)%d\n",a);
// 复合运算符的结合方向和 = 号相同,都是从右到左
}
1、C语句概述
2、赋值语句;
3、数据输入输出的概念;
4、字符数据的输入输出
5、格式输入与输出(scanf函数和printf函数)
6、顺序结构程序设计举例
1、识记:
(1)数据的输入输出函数
(2)字符数据的输入输出函数
2、理解:
(1)赋值语句;
(2)数据的输入输出概念。
3、应用:
(1)赋值语句
(5)格式输入、输出函数的使用
(6)字符数据的输入与输出
注意 c语句是用来完成一定操作任务的,声明部分的内容不应成为语句。
C语句分为5类
控制语句:
函数调用语句。函数调用语句由一个函数调用加一个分号构成。例如:
printf(“This is a C statement”);
表达式语句。表达式语句由一个表达式加一个分号构成。最经典的是,由复制表达式构成的一个赋值语句。例如 a=3 是一个赋值表达式,而 a=3;是一个赋值语句
任何表达式都可以加上分号成为语句
空语句。
;
复合语句。
例如:
{
z=x+y;
t=z/100;
printf("%f",t);
}
赋值表达式可以包括在其他表达式中 例如if((a=b)>0) t=a;
c语言本身不提供输入输出语句。由C函数库中的函数来实现
不把输入输出作为C语句的目的是使C语言编译系统简单。可以避免在编译截断处理与硬件有关的问题,可以是编译系统简化,而且通用性强,可移植性好。
4.4.1 **char putchar(char c)**函数 字符输出函数
4.4.2 **char getchar()**函数 字符输入函数 没有参数
注意:一次只能接受一个字符
4.5.1 printf函数
控制符 | 说明 |
---|---|
%d | 按十进制整型数据的实际长度输出。 |
%ld | 输出长整型数据。 |
%md | m 为指定的输出字段的宽度。如果数据的位数小于 m,则左端补以空格,若大于 m,则按实际位数输出。 |
%u | 输出无符号整型(unsigned)。输出无符号整型时也可以用 %d,这时是将无符号转换成有符号数,然后输出。但编程的时候最好不要这么写,因为这样要进行一次转换,使 CPU 多做一次无用功。 |
%c | 用来输出一个字符。 |
%f | 用来输出实数,包括单精度和双精度,以小数形式输出。不指定字段宽度,由系统自动指定,整数部分全部输出,小数部分输出 6 位,超过 6 位的四舍五入。 |
%.mf | 输出实数时小数点后保留 m 位,注意 m 前面有个点。 |
%o | 以八进制整数形式输出,这个就用得很少了,了解一下就行了。 |
%s | 用来输出字符串。用 %s 输出字符串同前面直接输出字符串是一样的。但是此时要先定义字符数组或字符指针存储或指向字符串,这个稍后再讲。 |
%x(或 %X 或 %#x 或 %#X) | 以十六进制形式输出整数,这个很重要。 |
%g | 用来输出实数,它根据数值的大小,自动选择 f 格式或 e 格式(选择输出是占宽度较小的一种) |
4.5.2 scanaf函数
scanf(格式控制,地址列表)
输入数据时不能规定精度
使用scanf函数时应该注意的问题
(1)应该使用变量地址去接受数据而不是变量名
(2)在输入数据时在对应位置应输入与这些字符相同的字符。例如:
scanf(“%d,%d”,&a,&b); 在输入数据时不按格式输入
(3)在用“%c”格式输入字符时,空格字符和转义字符都作为有效字符输入
(4)在输入数据时,遇到以下情况时都认为该数据结束
a:遇空格
b:按指定宽度结束
c:遇非法输入
略
4.1 c语言中的语句有哪几类?c语句与其他语言中的语句有哪些异同?
5类 , 控制语句,函数调用语句,表达式语句,空语句,复合语句
和其他高级语言一样,C语言的语句用来想计算机系统发出操作指令
4.2 怎样区分表达式和表达式语句?c语言为什么要设表达式语句?什么时候用表达式,什么时候用表达式语句?
表达式语句由一个表达式加一个分号构成。以是否有分号结尾做区别。
4.3 C语言为什么要把输入输出的功能作为函数,而不作为语言的基本部分?
不把输入输出作为C语句的目的是使C语言编译系统简单。可以避免在编译截断处理与硬件有关的问题,可以是编译系统简化,而且通用性强,可移植性好。
略;
//源码
#include
void main()
{
int a =5,b=7;
float x = 67.8564,y=-789.124;
char c='A';
long n=1234567;
unsigned u=65535;
printf("%d%d\n",a,b);
printf("%3d%3d\n",a, b);
printf("%f,%f\n",x, y);
printf("%-10f,%-10f\n",x,y);
printf("%8.2f,%8.2f,%.4f,%.4f,%3f,%3f\n",x,y,x,y,x,y);
printf("%e,%10.2e\n",x,y);
printf("%c,%d,%o,%x\n", c, c, c, c);
printf("%ld, %lo,%x\n",n,n,n);
printf("%u,%o,%x,%d\n",u,u, u,u);
printf("%s, %5.3s\n","COMPUTER", "COMPUTER");
}
略:
略:
#include
#define PI 3.14159
void main()
{
double r ; double h ;
printf("请输入半径:\n");
scanf("%lf",&r);
printf("请输入高\n");
scanf("%lf",&h);
printf("圆周长为:%.2f\n",PI*2*r);
printf("圆面积:%.2f\n",PI*r*r);
printf("圆球体积:%.2f\n",4.0/3.0*PI*r*r*r);
printf("圆柱体积:%.2f\n",PI*r*r*h);
}
略:
1、关系运算符和关系表达式;
2、逻辑运算符和逻辑表达式
3、条件运算符和条件表达式;
4、if选择控制语句;
5、条件运算符;
6、switch选择控制语句。
1、识记
(1)掌握关系运算符和逻辑运算符的用法;
(2)if语句、switch语句的形式;
(3)条件运算符的格式
2、理解
(1)选择结构程序设计语句的用法;
(2)if语句和switch语句的嵌套;
(3)条件运算符的用法
3、应用:
(1)关系运算符与关系表达式
(2)逻辑运算符与逻辑表达式
(3)具备分支结构程序设计的能力,灵活选用if语句和switch语句。
1.1. 关系运算符
(1)优先级如上
(2)关系运算符的优先级低于算术运算符
(3)高于赋值运算符
1.2. 关系表达式
c语言没有逻辑型数据,在C的逻辑运算中,以 1 代表真,以 0 代表假
例子 a=3 ,b=2 , c =1 ; (a>b) == c 表达式的值为1;
2.1. 逻辑运算符及其优先次序
在逻辑表达式的求解中,并不是所有的逻辑运算符都被执行,只是在必须执行下一个逻辑运算符才能求出表达式的解释,才执行该运算
a&&b&&c
也就是说,对&&运算符来说,只有a!=0,才继续进行右面的运算。对||运算符来说,只有a=0,才继续进行其右面的运算
2.2. 逻辑表达式
逻辑表达式的值应该是一个逻辑量“真”或“假”。c语言中,表示逻辑运算结果时,以数值1代表“真”,以0代表“假”,但在判断一个量是否为“真”时,以0代表“假”,以非0代表“真”。即将一个非零的数值人作为“真”
表达式1?表达式2 : 表达式3
(1)条件运算符的优先级别比关系运算符和算术运算符都低。
因此 max = (a>b)?a:b; 可以写成 max=a>b?a:b;
(2)**注意:**条件运算符的结合方向为“自右向左”
例如 a > b ? a : c > d ? c : d
相当于 a > b ? a : (c > d ? c : d)
(3)条件表达式还可以写成以下形式:
a>b? printf(“%d”,a):printf(“%d”,b)
即表达式2和表达式3不仅可以是数值表达式,还可以是赋值表达式或函数表达式
if语句的嵌套
应当注意if和else的配对关系。else总是与它上面的最近的未配对的if配对。
第三点
一般形式如下:
switch(表达式)
{
case 常量表达式1: 语句
case 常量表达式2: 语句
...
case 常量表达式n: 语句n
default: 语句n+1
}
说明:
(1)switch后面括号内的“表达式”,允许为任何类型
(2)当表达式的值与某一个case后面的常量表达式的值相等时,就执行此case后面
的语句,若所有的case中的常量表达式的值都没有与表达式的值匹配的,就执行 default
后面的语句
(3)每一个case的常量表达式的值必须互不相同;否则就会出现互相矛盾的现象(对
表达式的同一个值,有两种或多种执行方案)。
(4)各个case和 default的出现次序不影响执行结果。例如,可以先出现
“ default:…”,再出现“case’D’ : …”,然后是“case’A : …”
(5)执行完一个case后面的语句后,流程控制转移到下一个case继续执行。“case
常量表达式”只是起语句标号作用,并不是在该处进行条件判断。在执行 switch语句时
根据 switch后面表达式的值找到匹配的入口标号,就从此标号开始执行下去,不再进行
判断。
因此,应该在执行一个case分支后,使流程跳出 switch结构,即终止 switch语句的执行。
可以用一个 break语句来达到此目的。
在case后面可以包含一个以上的执行语句,但可以不必用花括号括起来,会自动顺序执行本case后面所有的执行语句。当然加上花括号也可以
(6)多个case可以共用一组执行语句
0表示假,1表示真。 0为假,不为0表示真
#include
int main()
{
int a =3 ,b=4,c=5,x,y;
printf("(1)a+b>c && b==c %7d\n",a+b>c && b==c); //0
printf("(2)a || b>c && b-c %7d\n",a || b>c && b-c); //1
printf("(3)!(a>b) && !c||1 %7d\n",!(a>b) && !c||1); //1
printf("(4)!(x=a) && (y=b)&&0 %7d\n",!(x=a) && (y=b)&&0); //0
printf("(5)!(a+b)+c-1 && b+c/2 %7d\n",!(a+b)+c-1 && b+c/2); //1
system("pause");
return 1;
}
5.4.
略
略
略:
#include
int main()
{
int n;
int i;
int arr[5];
int j;
scanf("%5d", &n);
for (i = 0; n != 0; i++)
{
arr[i] = n % 10;
n /= 10;
/* code */
}
printf("(1)是%d位数\n", i);
printf("(2)");
for (j = 0; j < i; j++)
{
printf("%2d", arr[j]);
}
printf("\n(3)");
for (j = i - 1; j >= 0; j--)
{
printf("%2d", arr[j]);
}
system("pause");
return 1;
}
5.9 输入4个整数,要求有小到大的顺序输出
#include
int main()
{
int arr[4];
int i;
int quickSort(int arr[],int length);
scanf("%d %d %d %d", &arr[0], &arr[1], &arr[2], &arr[3]);
quickSort(arr,4);
printf("%7d%7d%7d%7d", arr[0], arr[1], arr[2], arr[3]);
system("pause");
return 1;
}
//快速排序
int quickSort(int arr[],int length)
{
int i, j, k, t;
for (i = 0; i < lenght; i++)
{
k = i;
for (j = i + 1; j < length; j++)
{
if (arr[k] > arr[j])
{
k = j;
}
}
if (k != i)
{
t = arr[k];
arr[k] = arr[i];
arr[i] = t;
}
}
return 1;
}
5.10
#include
#include
int main()
{
double x ,y;
int result;
int isinside(double x,double y,double a, double b);
scanf("%lf %lf",&x,&y);
result = isinside(x,y,2,2) || isinside(x,y,-2,2)|| isinside(x,y,-2,-2) || isinside(x,y,2,-2);
result*=10;
printf("该点建筑高度为:%d",result);
system("pause");
}
int isinside(double x,double y,double a,double b)
{
return pow(x+a,2)+pow(y+b,2) <= 1;
}
1、用while语句实现循环;
2、用do…while语句实现循环;
3、用for语句实现循环;
4、循环的嵌套及几种循环的比较;
5、break语句和continue语句的用法及两者区别。
1、识记
(1) 三种循环语句的形式和使用;
(2) break语句与continue语句对循环语句的控制。
2、理解
(1)for循环与while循环、do-while循环间的区别与转换;
(2)break与continue用法及两者区别;
3、应用:
(1)循环语句的使用
(2)具备循环结构程序设计的能力。灵活选用三种循环语句。
(3)三种循环语句的嵌套使用。
一般形式为 while(表达式)语句
一般形式为 do 循环体语句 while(表达式)
一般形式为 for(表达式1;表达式2;表达式3)语句
4.1.goto语句为无条件转向语句。一般形式为 goto语句标号;
goto语句的使用机会已大大减少,只是需要从多层循环的内层循环跳到外层循环外时才用到goto语句。但不符合结构化原则,一般不采用,只有在不得已的时候(例如:能大大提高效率)
break
break语句可以使流程跳出switch结构,继续执行switch语句下面的一个语句。还可以用来从循环内跳出循环体。即提前结束循环
continue
其作用为结束本次循环,即跳过循环体中下面尚未执行的语句,接着进行下一次是否执行循环的判定。
区别:continue语句和break语句的区别是:continue语句只结束本次循环,而不是终止整个循环的执行。而break语句则是结束整个循环过程。不在判断执行循环的条件是否成立
例题: 把100~200之间的不能被3整除的数输出
#include
void main()
{
int i ;
for(i=100;i<200;i++)
{
if (i%3 ==0)
continue;
printf("%4d",i);
}
printf("\n");
}
#include
void main()
{
double i , PI, endNum = 1e6, sign=-1;
for(i=1;i<=endNum;i+=2)
{
sign *= -1;
PI += sign / i;
}
PI *=4;
printf("%lf",PI);
}
例题
#include
#include
void main()
{
int m,i;
scanf("%d",&m);
for(i=2;i<=sqrt(m);i++)
{
if (m%i==0){
printf("%d是不是素数",m);
i=-1;
break;
}
}
if (i!=-1)
{
printf("%d是素数",n);
}
}
#include
void main()
{
int n1, n2;
int getMaxGys(n1, n2), getMinGbs(n1, n2);
scanf("%d %d", &n1, &n2);
printf("最大公约数为%d:\n", getMaxGys(n1, n2));
printf("最小公倍数为%d:\n", getMinGbs(n1, n2));
}
int getMaxGys(n1, n2)
{
int i;
// 令n1 < n2
if(n1 > n2 ) i = n2, n2 = n1, n1 = i ;
for (i = n1; i > 0; i--)
{
if (n1 % i == 0 && n2 % i == 0)
{
return i;
}
}
return 0;
}
int getMinGbs(n1, n2)
{
int i;
// 令 n1
if(n1 > n2 ) i = n2, n2 = n1, n1 = i;
for (i = 1; i <= n1; i++)
{
if (n2 * i % n1 == 0)
{
return i * n2;
}
}
return 0;
}
#include
void main()
{
char c;
int zm = 0, kg = 0, sz = 0, qt = 0;
while ((c = getchar()) != '\n')
{
if ('A' <= c && 'Z' >= c)
zm++;
else if ('a' <= c && 'z' >= c)
zm++;
else if (c == ' ')
kg++;
else if ('0' <= c && '9' >= c)
sz++;
else
qt++;
}
printf("英文字母%d个\n", zm);
printf("空格%d个\n", kg);
printf("数字%d个\n", sz);
printf("其他字符%d个\n", qt);
}
#include
#include
void main()
{
long sn = 0, an = 0;
int a, n, i, j;
printf("分别输入a和n中间由空格隔开\n");
scanf("%d%d", &a, &n);
printf("Sn=");
for (i = 0; i < n; i++)
{
an += a * pow(10, i);
sn += an;
printf("%d", an);
if (i + 1 == n)
break;
printf("+");
}
printf("=%ld", sn);
}
两个版本都求不了答案:数据太大,long类型也装不下,需要使用其他方法计算
参考地址https://blog.csdn.net/JaneSilver/article/details/80777357
循环版本
#include
void main()
{
long sn = 0, an = 1;
int i, j, end;
end = 20;
printf("Sn=");
for (i = 1; i <= end; i++)
{
sn += an *= i;
printf("%ld", an);
if (i == end)
break;
printf("+");
}
printf("=%ld", sn);
}
递归版本
#include
long fac(int n)
{
long f=1;
int i;
if(n<0)
printf("n<0,data error!\n");
else if(n==0||n==1)
f=1;
else
f=fac(n-1)*n;
return f;
}
int main()
{
int i,j;
long sum=0;
for(i=1;i<=20;i++)
sum=sum+fac(i);
printf("1!+2!+3!+……+20!=%ld",sum);
return 0;
}
#include
void main()
{
double a1, a2, a3, sn, i, j;
for (i = 1; i <= 100; i++)
{
a1 += i;
}
for (i = 1; i <= 50; i++)
{
a2 += i * i;
}
for (i = 1; i < 10; i++)
{
a3 += 1 / i;
}
sn = a1 + a2 + a3;
printf("sn=a1+a2+a3=%lf+%lf+%lf=%lf",a1,a2,a3,sn);
}
#include
#include
void main()
{
int i ,j ;
for(i=100;i<1000;i++)
{
if (i == pow(i%10,3) + pow(i/10%10,3) +pow(i/100%10,3))
{
printf("%4d",i);
}
}
}
#include
void main()
{
int i, j, t, k, arr[10];
for (i = 1; i < 1000; i++)
{
t = 0;
k = -1; //记录因子个数 从0开始
for (j = 1; j <= i / 2; j++)
{
if (i % j == 0)
{
t += j;
arr[++k] = j;
}
}
if (i == t)
{
printf("%d its factors are ", i);
for (j = 0; j <= k; j++)
{
printf("%4d", arr[j]);
}
printf("\n");
}
}
}
#include
void main()
{
double fz = 2, fm = 0, fm1 = 1, fm2 = 2, sn, an, i;
for (i = 0; i < 2; i++)
{
//fz 2 3 5 6 13 21
//fm 1 2 3 5 8 13
fz += i;
if (i < 2)
{
fm = i == 0 ? fm1 : fm2;
}
else
{
fm = fm1 + fm2;
fm1 = fm2;
fm2 = fm;
}
an = fz / fm;
sn += an;
// printf("%lf\n", an);
}
printf("\n%lf", sn);
}
#include
void main()
{
double sn = 0, h = 100;
int i;
for (i = 0; i < 2; i++)
{
sn += (i == 0 ? h : 2 * h);
h /= 2;
}
printf("第%d次落地时,共经过%lf米", i, sn);
printf("第%d次反弹:%lf米", i, h);
}
#include
int main()
{
int day,x1,x2; /*定义 day、x1、x2 3 个变董为基本整型*/
day=1;
x2=1;
while(day>0)
{
x1=(x2+1)*2; /*第一天的桃子数是第二天桃子数加1后的2倍*/
x2=x1;
day--; /*因为从后向前推所以天数递减*/
}
printf("the total is %d\n",x1); /* 输出桃子的总数*/
return 0;
}
递归方式
#include
int main()
{
printf("%d",sumpeach(1));
return 0;
}
int sumpeach(int day)
{
if (day == 10)
{
return 1;
}
return (sumpeach(day + 1) + 1) * 2;
}
#include
#include
void main()
{
double x1 =1 ,x2;
int a=0;
scanf("%d",&a);
while(1)
{
x2 = 0.5*(x1+a/x1);
if (abs(x2-x1)<1e-5)
{
//printf("%lf",(x2-x1));
printf("%lf",x2);
break;
}
x1 = x2;
}
}
#include
#include
void main()
{
//x(n+1) = xn - f(xn)/f`(xn)
double x1 = 1.5, x2 = 0;
while (1)
{
x2 = x1-(2*pow(x1,3)-4*pow(x1,2)+3*x1-6)/(6*pow(x1,2)-8*x1+3);
if (fabs(x2 - x1) < 1e-5)
{
//printf("%lf",(x2-x1));
printf("%lf", x2);
break;
}
x1 = x2;
}
}
略:
#include
#include
int main()
{
int i,j,space,star;
for ( i = -3; i <= 3; i++)
{
space = abs(i);
star = 7 - 2*space;
for ( j = 0; j < space; j++)
{
printf(" ");
}
for ( j = 0; j < star; j++)
{
printf("*");
}
printf("\n");
}
}
略:
1、一维数组的定义和引用;
2、二维数组的定义和引用;
3、字符数组。
1、识记
(1)什么是数组名、数组元素和数组下标
(2)字符数组与字符串。
2、理解
(1)一维数组的定义、初始化与引用;
(2)二维数组的定义、初始化与引用,二维数组与一维数组的关系;
(3)字符串的概念与操作,与数组有关的常用的算法(查找、排序等);
3、应用:
(1)数组下标变量的使用
(2)具备使用数组进行程序设计的能力(包括一维数组的应用,二维数组的简单应用)。
(3)常用的字符串处理函数的使用。
1.1.一维数组的定义
一维数组的定义方式为:类型说明符 数组名[常量表达式]
说明:
(1)数组名命名规则和变量名相同
(2)角标从0开始
(3)常量表达式可以包括常量和符号常量
1.2.以为数组元素的引用
数组名[index]
1.3. 一维数组的初始化
(1)int a[10] = {0,1,2,3,4,5,6,7,8,9}
(2) 只给一部分元素赋值
int a[10]={0,1,2,3,4,5};
后5个元素的值为0
(3)全部初始化为0
int a[10]={0}
(4)可以不指定数组长度
int a[] ={1,2,3,4,5}
2.1 二维数组的定义
二维数组定义的一般形式为
类型说明符 数组名 [常量表达式][常量表达式]
c语言中,二维数组中元素排列的顺序是按行存放的,即在内存中先顺序存放第一行的元素,再放第二行的元素。
2.2 二维数组的引用
二维数组元素的表示形式为
数组名[index][index]
2.3 二维数组的初始化
(1)int a[3][4]={{1,1,1,1},{2,2,2,2},{3,3,3,3}};
(2)int a[3][4]={1,1,1,1,2,2,2,2,3,3,3,3}
(3)int a[3][4]={{1},{5},{9}} ; int a[3][4]={{1,1},{2}}
(4)int a[][4]={1,1,1,1,2,2,2,2,3,3,3,3} 系统会自动算出第一维的长度,但第二维长度不能省
用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符
3.1 字符数组的定义
3.2 字符数组的初始化
初始化方式和其他数组的初始化方式相同
不同地,可以 char c[]={“I am Iron Man”} 注意:数组长度比字符串长度+1.因为字符串常量的最后由系统加上一个‘\0’。
因此上面的初始化与下面的初始化等价
char c[] = {‘I’,‘ ’,‘a’,‘m’,‘ ’,‘I’,‘r’,‘o’,’n‘,’ ‘,’M‘,’a‘,’n‘,‘\0’}
如果在定义字符数组时不进行初始化,则数组中个元素的值是不可预料的。如果初值个数小于数组长度,则只将这些字符赋给数组中前面那些元素。其余的元素自动定义为空字符(即‘\0’)
3.3字符数组的引用
3.4 字符串和字符串结束标志
在c语言中,是将字符串作为字符数组来处理的。字符串中的字符是逐个存放到数组元素中的,这个字符串的实际长度与数组长度相等。在实际工作中,人们关心的往往是字符串的有效长度而不是字符数组的长度。例如:定义一个字符数组长度为100,而实际有效字符只有40个。
为了测定字符串的实际长度,C语言规定了一个“字符串结束标志”,以字符‘\0’作为标
志。如果有一个字符串,前面9个字符都不是空字符(即‘\0′),而第10个字符是‘\0′,则
此字符串的有效字符为9个。也就是说,在遇到字符\0时,表示字符串结束,由它前面
的字符组成字符串
系统对字符串常量也自动加一个‘\0’最为结束符。例如:“Hello World”共有11个字符,但在内存中占10个字节,最后一个字节‘\0’是由系统自动加上的。字符串作为一维数组存放在内存中
char c[]={“I am Iron Man”} ==>
char c[] = {‘I’,‘ ’,‘a’,‘m’,‘ ’,‘I’,‘r’,‘o’,’n‘,’ ‘,’M‘,’a‘,’n‘,‘\0’}
3.5 字符数组的输入输出
char c[]={“china”};
printf(“%s”,c);
注意
char c[10]={“china”}printf(“%s”,c)也只输出字符串的有效符“china”,而不是输出10个字符。
如果一个字符数组中包括一个以上‘\0’,则遇到第一个‘\0’时输出就结束
sccanf(“%s”,c) 输入的字符串应短于已定义的字符数组的长度
scanf函数中的输入项如果是字符数组名,不要再加地址符&,因为在c语言中数组名代表该数组的起始地址
printf(“%s”,c)
实际上是这样执行的:按字符数组名c找到其数组起始地址,然后逐个输出其中的字符。知道遇到‘\0’为止
3.6 字符串处理函数
1.puts函数
puts(字符数组) 在终端输出
在输出时将字符串结束标志‘\0’转换成‘\n’,即输出完字符串后换行
2,gets函数
gets(字符数组) 获取终端输入
3 strcat函数
strcat(字符数组1,字符串2) 连接两个字符串
注意:是把字符串2 拼接到 字符数组1
4.strcpy 和strncpy函数
strcpy(字符数组1,字符串2)
字符串复制函数,将字符串2复制到字符数组1中去
说明:字符数组1必须写成数组名形式。字符串2可以使字符数组名,也可以使一个字符串常量
可以用strncpy函数将字符串2中前面n个字符复制到字符数组1中去,例如:
strncpy(str1,str2,2);
5 strcmp函数
strcmp(字符串1,字符串2)
strcmp(“china”,“korea”)
作用:比较字符串1和字符串2
比较规则,对两个字符串从左至右逐个字符相比
比较的结果: 小于(负整数)| 相等(0) | 大于(正整数)
6 strlen函数
strlen(字符数组)
测试字符串长度的函数。函数的值为字符串中的实际长度(不包括‘\0’在内)
char str[10]={“china”};
printf(“%d”,strlen(str));
输出结果不是10,也不是6,而是5
也可以直接测试字符串常量的长度,例如
strlen(“china”)
strlwr函数
strlwr(字符串)
作用:将字符串中大写字母换成小写字母
strupr函数
strupr(字符串)
7.1 用筛选法求100之内的素数
#include
/*
筛选法又称筛法,具体做法是:
先把N个自然数按次序排列起来。
1不是质数,也不是合数,要划去。
第二个数2是质数留下来,
而把2后面所有能被2整除的数都划去。
2后面第一个没划去的数是3,
把3留下,再把3后面所有能被3整除的数都划去。
3后面第一个没划去的数是5,
把5留下,再把5后面所有能被5整除的数都划去。
这样一直做下去,就会把不超过N的全部合数都筛掉,
留下的就是不超过N的全部质数。
*/
void main()
{
int arr[100];
int i, k, t = 0, count = 0, endIndex = 99;
//初始化
for (i = 0; i < endIndex + 1; i++)
{
arr[i] = i + 1;
}
while (endIndex >= count)
{
if (arr[0] == 1)
{
for (i = 1; i < endIndex + 1; i++)
{
arr[i - 1] = arr[i];
}
endIndex--;
}
else
{
printf("%3d", arr[count]);
count++;
t = 0;
for (i = count; i <= endIndex; i++)
{
if (arr[i] % arr[count - 1] != 0)
{
arr[count + t] = arr[i];
t++;
}
}
endIndex = count + t - 1;
}
}
}
7.2 用选择法对10个整数排序
#include
/*
选择排序法是一种不稳定的排序算法。
它的工作原理是每一次从待排序的数据元素中
选出最小(或最大)的一个元素,存放在序列的起始位置,
然后,再从剩余未排序元素中继续寻找最小(大)元素,
然后放到已排序序列的末尾。以此类推,
直到全部待排序的数据元素排完。
*/
void main()
{
int arr[10];
int i, j, k, t;
for (i = 0; i < 10; i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < 10; i++)
{
k = i;
for (j = i + 1; j < 10; j++)
{
if (arr[k] > arr[j ])
{
k = j ;
}
}
if (k != i)
{
t = arr[i];
arr[i] = arr[k];
arr[k] = t;
}
}
for (i = 0; i < 10; i++)
{
printf("%5d", arr[i]);
}
}
7.3 求一个3x3的整型矩阵对角线元素之和
#include
int main()
{
int i,j,a[3][3],sum=0;
printf("input 3*3 matrix: \n");
for(i=0;i<3;i++)
for(j=0;j<3;j++)
scanf("%d",&a[i][j]);
for(i=0;i<3;i++)
for(j=0;j<3;j++)
if(i==j||i+j==2)
sum+=a[i][j];
printf("sum:%d",sum);
return 0;
}
7.4 已有一个已排好序的数组,要求输入一个数后,按原来排序的规律将它插入数组中
略:
7.5 将一个数组中的值按逆序重新排放
#include
int main()
{
int i, t=0;
int arr[] = {8, 6, 5, 4, 1};
for (i = 0; i < 2; i++)
{
t = arr[i];
arr[i] = arr[4 - i];
arr[4 - i] = t;
}
}
#include
int main()
{
int arr[10][10];
int i, j, k, t;
// 初始化
for (i = 0; i < 10; i++)
{
arr[i][0] = 1;
arr[i][i] = 1;
}
//
for (i = 2; i < 10; i++)
{
for (j = 1; j < i; j++)
{
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
//输出数组
for (i = 0; i < 10; i++)
{
for (j = 0; j <= i; j++)
{
printf("%-4d", arr[i][j]);
}
printf("\n");
}
}
略:
**7.8 **略
7.9 略
7.10 略
7.11 略
7.12 略
7.13 编一程序,将两个字符串连接起来,不要用strcat函数
#include
#include
int main()
{
char str[100];
char str1[] = {"hello "};
char str2[] = {"world"};
int i, j;
strcpy(str, str1);
for (i = strlen(str1), j = 0; j < strlen(str2) + 1; i++, j++)
{
str[i] = str2[j];
}
printf("%s", str);
}
#include
#include
int main()
{
char str1[10];
char str2[10];
int i, dict,len1, len2, min;
gets(str1);
gets(str2);
len1 = strlen(str1);
len2 = strlen(str2);
min = len1 > len2 ? len2 : len1;
for (i = 0; i < min; i++)
{
if (str1[i] == str2[i])
{
continue;
}
dict=str1[i]-str2[i];
printf("%d\n", dict);
break;
}
printf("%d\n", strcmp(str1, str2));
}
#include
#include
int main()
{
char s1[100];
char s2[]={"hello world"};
int i ;
for ( i = 0; i < strlen(s2)+1; i++)
{
s1[i]=s2[i];
}
}
1、函数定义的一般形式和函数返回值;
2、调用函数(函数调用的形式,嵌套调用,递归调用,数组作为函数参数);
3、函数的声明和函数原型
4、局部变量和全局变量;
5、变量的存储方式和生存期。
1、识记
(1)形参与实参
(2)函数的调用
2、理解
(1)函数的作用与意义;
(2)函数的定义格式;
(3)函数参数传递和函数的返回值;
(4)变量的存储属性和作用范围
3、应用:
(1)函数定义的一般形式
(2)函数参数传递和函数的值
(3)函数的调用形式和方法
(4)函数的嵌套调用和递归调用;
(5)变量的存储类别,全局变量和局部变量的区分和作用;
(6)具备使用自定义函数编写程序的能力。
函数:一个源 程序文件由一个或多个子程序模块组成,每一个程序模块作为一个源程序文件
一个源程序文件由一个或多个函数以及其他有关内容组成
函数不能嵌套定义,可以互相调用,不能调用main函数
类型标识符 函数名(形参表列)
{
声明部分
语句部分
}
1.1 关于形参与实参的说明
(1)在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,只有在发生函数调用时,函数中的形参才被分配内存单元。在调用结束后,形参所占的内存单元也被释放
(2)在调用时将实参的值赋给形参
(3)在被定义的函数中,必须指定形参的类型
(4)实参与形参的类型应相同或赋值兼容。否则按第三章的不同类型数值的赋值规则进行转换
(5)在C语言中,实参向形参的数据传递是** “值传递“ **,单向传递,只由实参传给形参,而不能由形参传回给实参。
在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数的实参的值
1.2. 函数的返回值
(1)函数的返回值是通过函数中的return语句获得的
(2)应当在定义函数时指定函数值的类型,在C语言中,凡不加类型说明的函数,自动按整型处理。但不同编译器可能会不通过
(3)指定的函数类型应该和return语句中的表达式类型一致
如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行类型转换,即函数类型界定返回值的类型
对于不带回值的函数,应当用void定义函数。此时函数体中不得出现return语句
一般形式
函数名(实参列表)
说明:如果实参表列包括多个实参,对实参求值的顺序并不确定的,有的系统按从左至右顺序求实参的值,有的系统则按从右至左的顺序求值
2.2 函数调用的方式
在一个函数中调用另一个函数(即被调用函数)需要具备的条件如下。
(1)首先被调用的函数必须是已经存在的函数(是库函数或用户自己定义的函数)。
但光有这一条件还不够。
(2)如果使用库函数,还应该在本文件开头用# include命令将调用有关库函数时所
需用到的信息“包含”到本文件中来。
(3)如果使用用户自定义的函数,而该函数和主调函数在同一文件,应该再主调函数中对被调用的函数作声明。声明的作用是把函数名,函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法
在函数声明中也可以不写形参名,而只写形参的类型。例如
float add (float,float)
编译系统只检查参数个数和参数类型
在进行编译时是从上到下逐行进行
如果被调用函数的定义出现在主调函数之前,可以不必加以声明。
如果已在文件的开头(在所以函数之前)已对本文件中所调用的函数进行了声明,则在各函数中不必对其所调用的函数再作声明
如果被调用的函数类型为整型,C语言允许在调用函数前不必作函数原型声明
3.1 函数的嵌套调用
c语言的函数定义是互相平行,独立。在定义函数时,一个函数内不能包含另一个函数。
3.2 函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用
数组名也可以作实参和形参,传递的是数组首元素的地址
4.1 数组元素作函数实参
4.2 数组名作函数参数
实参数组与形参数组类型应一致
在被调用函数中声明了形参数组大小,在实际上,指定其大小是不起任何作用的。因为c语言编译对形参数组大小不做检查,只是将实参数组的手元素的地址传递给形参数组。
用数组名做函数实参是,不是把数组元素的值传递给形参,而是把实参数组的首元素的地址传递给形参数组。这样两个数就共占同一段内存单元。
4.3多维数组名作为函数参数
多维数组名作为函数的实参和形参,在被调用函数中对形参数组定义时可以指定每一维的大小,也可以省略第一维的大小说明。例如:
int array[3][10]或int array[][10] 二者都合法而且等价。但不能把第二维以及其他高纬度的大小说明省略。如下面的定义时不合法的;
int array[][];
c语言编译系统不检查第一维的大小
5.1 局部变量
在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内餐能使用它们。在此函数以外是不能使用这些变量的。这称为“局部变量”
在一个函数内部,可以再复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”
void main()
{
int a,b;
...
{
int c;//
c=c+b; //c在此范围内有效
...
}
}
//变量c只在复合语句内有效,离开该复合语句该变量就无效,释放内存单元
5.2 全局变量
在函数内定义的变量时局部变量,而在函数之外定义的变量称为外部变量,外部变量时全局变量(也称全程变量)。全局变量可以为本文件中其他函数所共用。它的有效范围从定义变量的位置开始到本源文件结束
规范:将全局变量的第一个字母用大写表示
说明:
(1)可以利用全局变量以减少函数实参与形参的个数,从而减少内存空间以及传递数据时的时间消耗
(2)建议不在必要时不要使用全局变量
A 全局变量在程序的全部执行过程中都占用存储单元,而不是在仅需要的时候才开辟单元
B 它使函数的通用性降低了,因为函数在执行时要依赖于其所在的外部变量。降低了程序的可靠性和通用性
C如果全局变量过多,会降低程序的清晰性,难以清楚地判断出每个书时各个外部变量的值
(3)如果在同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用
6.1 变量的存储类别
动态存储方式与静态存储方式
从变量存在的时间(即生存期)角度来分,可以分为静态存储和动态存储方式
静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式,而动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的方式
内存中供用户使用的存储空间可以分为三部分。
(1)程序区(2)静态存储区(3)动态存储区
全局变量全部存放在静态存储区中,在程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中它们占据固定的存储单元,而不是动态地进行分配和释放
在动态存储区中存放以下数据:
(1)函数形式参数。在调用函数时给形参分配存储空间。
(2)自动变量(未加static声明的局部变量)
(3)函数调用时的现场保护和返回地址等
在c语言中,每一个变量和函数有两个属性;数据类型和数据的存储类型。
存储方式分为两大类:静态存储类和动态存储类。具体包括4种:自动的(auto),静态的(static).寄存器的(register),外部的(extern).
下面分别介绍
auto变量
函数中的局部变量,如果不专门声明为static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中。函数中的形参和在函数中定义的变量(包括在复合语句中定义的变量),都属此类。在调用该函数时系统会给他们分配存储空间,在函数调用结束时,就自动释放这些存储空间。因此此类局部变量称为自动变量。自动变量用关键字auto作为存储类别的声明。例如
int f(int a)//定义f函数,a为形参
{
auto int b,c=3; //定义b,c为自动变量
...
}
实际上,关键字“auto”可以省略,auto不写则隐含确定为“自动存储类别”
static声明局部变量
希望函数中的局部变量的值在函数调用结束后不消失而是保留原值,即其占用的存储单元不释放,在下一次该函数调用时,该变量已有值,就是上一次函数调用结束时的值。这时就可以指定该局部变狼为“静态局部变量”,用关键字static进行声明。
#include
void main()
{
int f(int);
int a = 2, i;
for (i = 0; i < 3; i++)
{
printf("%d", f(a)); //789
}
}
int f(int a)
{
auto int b = 0;
static int c = 3;
b = b + 1;
c = c + 1;
return (a + b + c);
}
对静态局部变量的说明:
(1)静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。
(2)对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值,以后每次调用函数时不再重新赋初值而是只保留上次函数调用结束时的值。而对自动变量赋初值,不是在编译时进行的,而是在函数调用时进行的,没调用一次函数重新给一次初值。相当于执行一次赋值语句。
(3)**如果定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。**而对自动变量来说,如果不服初值则它的值是一个不确定的值
(4)虽然静态局部变量在函数调用结束后仍然存在,但其他函数时不能引用它的。需要使用局部静态变量的情况如下:
a.需要保留函数上一次调用结束时的值
b.如果初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。但会降低程序的可读性。因此若非必要,不要多用静态局部变量
register 变量
#include
void main()
{
long fac(long);
long i, n;
scanf("%ld", &n);
for (i = 0; i <= n; i++)
{
printf("%ld!=%ld\n", i, fac(i));
}
}
long fac(long n)
{
register long i, f = 1;//定义寄存器变量
for (i = 1; i <= n; i++)
{
f = f * i;
}
return f;
}
说明:
(1)只有局部自动变量和形式参数可以作为寄存器变量,其他(如全局变量)不行。在调用一个函数时占用一些寄存器以存放寄存器变量的值,函数调用结束释放寄存器。此后,在调用另一个函数时又可以利用它来存放该函数的寄存器变量
(2)一个计算机系统中的寄存器数目是有限的,不能定义任意多个寄存器变量。不同的系统允许使用的寄存器个数是不同的,而且对register变量的处理方法也是不同的,有的系统对register变量当做自动变量处理,分配内存单元,并不真正把它们存放在寄存器中,有的系统只允许int,char和指针型变量定义为寄存器变量
(3)局部静态变量不能定义为寄存器变量。不能写成
register static int a,b,c;
不能把变量a,b,c既放静态存储区中,又放在寄存器中,二者只能居其一。对一个变量只能声明为一种存储类别
当今的优化编译系统能自动识别使用频繁的变量,从而自动地将这些变量放在寄存器中,而不需要程序设计者指定。因此。实际上register声明变量时不必要的。有一定了解即可
extern声明外部变量
外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为程序中各个函数所引用。编译时将外部变量分配在静态存储区
有时需要用 extern来声明外部变量,以扩展外部变量的作用域。
1.在一个文件内声明外部变量
如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件结束
如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字 extern对该变量作“外部变量声明”,表示该变量是一个已经定义的外部变量。有了此声明,就可以从“声明”处起,合法地使用该外部变量。
#include
void main()
{
int max(int, int);
extern A, B;
printf("%d\n", max(A, B));
}
int A = 13, B = -8;
int max(int x, int y)
{
int z;
z = x > y ? x : y;
return z;
}
2.在多文件的程序中声明外部变量
一个C程序可以由一个或多个源程序文件组成。如果程序只由一个源文件组成,使
用外部变量的方法前面已经介绍。如果程序由多个源程序文件组成,那么在一个文件中想引用另一个文件中已定义的外部变量,有什么办法呢?
如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量Num,不能分
别在两个文件中各自定义一个外部变量Num,否则在进行程序的连接时会出现“重复定义”的错误。正确的做法是:在任一个文件中定义外部变量Num,而在另一文件中用extern对Num作“外部变量声明”。即“ extern Num;”。在编译和连接时,系统会由此知道Num是一个已在别处定义的外部变量,并将在另一文件中定义的外部变量的作用域扩展到本文件,在本文件中可以合法地引用外部变量Num
用static声明外部变量
这种加上static声明,只能用于本文件的外部变量称为静态外部变量
内部函数和外部函数
函数本质上是全局的,因为一个函数要被另外的函数调用,但是,也可以指定函数不
能被其他文件调用。根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。
内部函数
static 类型标识符 函数名(形参表);
外部函数
略:
#include
void main()
{
int p(int, int);
int n, x;
printf("please enter n x\n");
scanf("%d %d", &n, &x);
printf("the p(%d,%d) = %d", n, x, p(n, x));
system("pause");
}
int p(int n, int x)
{
if (n == 0)
{
return 1;
}
else if (n == 1)
{
return x;
}
else if (n >= 1)
{
return ((2 * n - 1) * x - p(n - 1, x) - (n - 1) * p(n - 2, x)) / n;
}
else
{
printf("data error \n");
}
}
略:
#include
void main()
{
int n;
scanf("%X", &n);
printf("%d\n", n);
}
#include
#include
#include
int i = 0;
void int_string(int n, char* str) {
if (n > 9) {
int_string(n / 10, str);
}
str[i++] = n % 10 + '0';
}
void main() {
int n;
char str[12] = { '\0' };
printf("请输入一个整数\n");
scanf("%d", &n);
if (n < 0) {
n = -n;
str[i++] = '-';
}
int_string(n, str);
printf("字符串为:%s\n", str);
system("pause");
}
略:
1、指针的定义,指针与地址的关系,指针变量的定义和引用;
2、通过指针引用数组;
3、通过指针引用字符串;
4、指向函数的指针。
1、识记
(1)变量的指针和指针变量;
(2)数组的指针和指向数组的指针变量
2、理解
(1)地址和指针的基本概念
(2)字符串的指针和指向字符串的指针变量
(3)返回指针值的函数
(4)指针数组和多级指针
3、应用:
(1)灵活使用指针编写基本程序
(2)数组指针的使用
一个变量的地址称为该变量的“指针”
下面两个语句作用相同
(1)i=3;
(2)*i_pointer = 3
第二个语句的含义是将3赋值给指针变量i_pointer所指向的变量
1.2.1 定义一个指针变量
定义指针变量的一般形式为:
基类型 *指针变量名
int *pointer_1,*pointer_2
pointer_1=&i;
pointer_2=&j;
指针变量的基类型用来指定该指针变量可以指向的变量的类型
在定义指针变量时要注意两点
(1)指针变量前面的“*”表示该变量的类型为指针型变量。指针变量名是pointer_1,pointer_2.而不是 *pointer_1,*pointer_2。这是与定义整型或浮点型变量的形式不同的
(2)在定义指针变量时必须指定基类型。因为不同类型的数据在内存中所占的字节数是不相同的。一个指针变量智能指向同一个类型的变量,不能忽而指向一个整型变量,忽而指向一个实型变量。
1.2.2 指针变量的引用
指针变量中只能存放地址(指针),不要将一个整数(或任何其他非地址类型的数据)赋给一个指针变量
有两个有关的运算符:
(1)&:取地址运算符
(2)*:指针运算符(或成“间接访问”运算符),取其指向的内容
下面对“&”和“*”运算符在做些说明:
(1)&*pointer_1 的含义是什么?
两个运算符的优先级别相同,但按自右而左方向结合,因此
===》 &(*pointer_1)
(2)*&a的含义还是a
(3)(*pointer_1)++ 相当于a++ 。注意括号是必要的,如果没有括号,就成为了*pointer_1++。
1.2.3指针变量作为函数参数
函数的参数不仅可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中
int a[10];
int *p;
c语言规定数组名(不包括形参数组名,形参数组,并不占据实际的内存单元)代表数组中首元素(即序号为0的元素)的地址。因此下面两个语句等价
p=&a[0];
p=a;
注意数组名a不代表整个数组,上述“p=a;”的作用是“把a数组的首元素的地址赋给指针变量p”,而不是“把数组a个元素的值赋给p”
C语言规定:如果指针变量p已指向数组中的一个元素,则p+1指向通一数组中的下一个元素,而不是将p的值(地址)简单地加1.
如果p的初值为&a[0],则
(1)p+i 和 a+i 就是a[i]的地址,或者说,它们指向a数组的第 i 个元素,这里需要特别注意的是a代表数组收元素的地址,a+i也是地址,它的计算方法同p+i,即它的实际地址为a+ixd.
(2)*(p+i) 或 *(a+i) 是 p+i 或 a+i 所指向的数组元素。即a[i] . 例如,*(p+5)或
*(a+5)就是a[5]。即***(p+5),*(a+5),a[5]三者等价**
(3)指向数组的指针变量也可以带下标。如p[i]与*(p+i)等价
根据以上论述,引用一个数组元素,可以用:
(1)下标法,如a[i]形式
(2)指针法,如*(a+i)或*(p+i)。其中a是数组名,p是指向数组元素的指针变量,其初值p=a
例题,输出数组中的全部元素
用指针变量指向数组元素
#include
void main()
{
int a[10];
int *p, i;
for (i = 0; i < 10; i++)
{
scanf("%d", &a[i]);
}
printf("\n");
for (p = a; p < a + 10; p++)
{
printf("%d", *p);
}
printf("\n");
}
这种用指针变量直接指向元素,不必每次都重新计算地址,像p++这样的自加操作是比较快的。这种有规律地改变地址值(p++)能大大提高执行效率
注意:
如果不用p而使用数组名a变化(例如,用a++).是不行的。因为数组名a代表数组首元素地址,它是一个指针常量,它的值在程序运行期间是固定不变的。既然a是常量,所以a++是无法实现的
指针变量p可以指向数组以后的内存单元,应切实保证指向数组中有效地元素
*p++ 等价于 *(p++) 作用是先得到p指向的变量的值(即*p),然后再使p=p+1
f(int arr[] , int n) 和f(int *arr,int n)这两种写法是等价的
需要说明的是:C语言调用函数时虚实结合的方法都是采用“值传递”方式,当用变量
名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。
应该注意:实参数组名代表一个固定的地址,或者说是指针常量,但形参数组并不是
一个固定的地址值,而是作为指针变量,在函数调用开始时,它的值等于实参数组首元素的地址,在函数执行期间,它可以再被赋值。
2.4.1 多维数组与指针
int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};
从二维数组的角度来看,a代表二维数组首元素的地址,现在的首元素不是一个简单的整型元素,而是由4个整型元素所组成的一堆数组。因此a代表的是首行(即第0行)的首地址。a+1代表第1行的首地址。如果二维数组的首行的首地址为2000,则在Turbo C中,a+1为2008.因为第0行有4个整型数据。因此a+1的含义是a[1]的地址,即a+4*2=2008.
a[0]、a[1]、a[2]既然是一维数组名,而C语言又规定了数组名代表数组首元素地址,
因此a[0]代表一维数组a[0]中第0列元素的地址,即&a[0][0]。a[1]的值是
&a[1][0],a[2]的值是&a[2][0]。
请考虑0行1列元素的地址怎么表示?a[0]为一维数组名,该一维数组中序号为1
的元素的地址显然应该用a[0]+1来表示
a[0]的值是2000,a[0]+1的值是2002(而不是2008)
a[0]+0、a[0]+1、a[0]+2、a[0]+3分别是a[0][0]、a[0][1]、a[0][2]、a[0][3]元素的地址
*务请记住 (a+i)和a[i]是等价的
容易搞混的点:a+1 和 *(a+1)都是2008
2.4.2 指向多维数组元素的指针变量
printf(“addr=%o,value=%2d\n”,p,*p);
注意地址是以八进制数表示的(格式输出符为%o)
2.4.3用指向数组的指针做函数参数
在用指针变量作形参以接受实参数组名传递来的地址时,有两种方法:①用指向变量的指针变量;②用指向一维数组的指针变量
#include
void main()
{
float average(float *p, int n);
void search(float(*p)[4], int index);
float score[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
average(*score, 12);
search(score, 2);
}
//用指向变量的指针变量
float average(float *p, int n)
{
float *i, sum = 0, aver;
for (i = p; i <= p + n - 1; i++)
{
sum += (*i);
}
aver = sum / n;
printf("the average is %5.2f\n", aver);
}
//用指向一维数组的指针变量
void search(float (*p)[4], int index)
{
//p是指向整个二维数组
int i;
printf("the %dth student score is", index);
for (i = 0; i < 4; i++)
{
printf("%5.2f", *(*(p + index - 1) + i));
}
printf("\n");
}
(1)用字符数组存放一个字符串,然后输出字符串
char string[] = “Hello World”;
(2)用字符指针指向一个字符串
可以不定义字符数组,而定义一个字符指针。用字符指针指向字符串中的字符
#include
void main()
{
char *string = "Hello World";
printf("%s\n",string);//Hello World
}
c语言对字符串常量是按字符数组处理的,在内存中开辟一个字符数组用来存放该字符串常量。对字符指针变量string初始化,实际上是把字符串第一个元素的地址(即存放字符串的字符数组的首元素地址)赋给string。
#include
void main()
{
void copy_string(char from[], char to[]);
char a[] = "I am a teacher";
char b[] = "You are a student";
char *p1, *p2;
p1 = a;
p2 = b;
printf("string a =%s\nstring b=%s\n", a, b);
printf("copy string a to string b:\n");
copy_string(p1, p2);
printf("string a=%s\nstring b=%s\n", a, b);
}
void copy_string(char form[], char to[])
{
int i = 0, j = 0;
while ((to[j++] = form[i++]) != '\0');
form[i] = '\0';
}
形参做字符指针变量
#include
void main()
{
void copy_string(char from[], char to[]);
char a[] = "I am a teacher";
char b[] = "You are a student";
char *p1, *p2;
p1 = a;
p2 = b;
printf("string a =%s\nstring b=%s\n", a, b);
printf("copy string a to string b:\n");
copy_string(p1, p2);
printf("string a=%s\nstring b=%s\n", a, b);
}
void copy_string(char *p1, char *p2)
{
while (*p1 != '\0')
{
*p2++ = *p1++;
}
*p2 = '\0';
}
虽然用字符数组和字符指针变量都能实现字符串的存储和运算,但它们二者之间是
有区别的,不应混为一谈,主要有以下几点。
(1)字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第一个字符的地址)。绝不是将字符串放到字符指针变量中
(2)赋值方式。对字符数组只能对各个元素赋值,不能用以下方法对字符数组赋值
//错误
char str[14];
str=“Hello World”;
可以采用下面方法赋值:
char *a;
a=“Hello World”;
(3)对字符指针变量赋初值
char *a =“Hello World”;
等价于
char *a;
a=“Hello World”;
而对数组的初始化:
char str[14]={“Hello World”};
不能等价于
char str[14];
str[]=“Hello World”;
即数组可以在定义时整体赋初值,但不能再赋值语句中整体赋值。
(4)可以 char str[10]; scanf(“%s”,str);
但下面的不行;
注意:
char *a;
scanf(“%s”,a);
(5)
**指针变量a的值可以变化,而数组名虽然代表地址,但它是常量,它的值是不能改变的。**下面是错的
//错误
char str[]={“Hello World”};
str=str+7;
printf(“%s”,str)
;
需要说明,若定义了一个指针变量,并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符
#include
void main()
{
char *str = "Hello World";
int i = 0;
while (str[i] != '\0')
{
printf("%c", str[i++]);
}
}
一个函数在编译时被分配给一个入口地址。这个函数的入口地址就称为函数的指针。可以用一个指针变量指向函数。然后通过该指针变量调用此函数。
每一个函数都占用一段内存单元,他们有一个起始地址。因此,可以用一个指针变量指向一个函数,通过指针变量来访问它指向的函数
#include
void main()
{
int max(int, int);
int (*p)(int, int) = max;
int a, b, c;
scanf("%d %d", &a, &b);
c = (*p)(a, b);
printf("thie max number is %d", c);
}
int max(int n1, int n2)
{
return n1 > n2 ? n1 : n2;
}
说明:
(1)指向函数的指针变量的一般定义形式为:
数据类型 (*指针变量名)(函数参数表列)
(2)函数的调用可以通过函数名调用,也可以通过函数指针调用
(3)“int (*p)(int ,int);”表示定义一个指向函数的指针变量p,它不是固定指向哪一个函数的,而只是表示定义了这样一个类型的变量,它是专门用来存放函数的入口地址。
(4)在给函数指针变量赋值时,只需给函数名而不必给出参数。
(5)用函数指针变量调用函数时,只需将(*p)代替函数名即可(p为指针变量名),
在(*p)之后的括号中根据需要写上实参。
(6)对指向函数的指针变量,像p+n,=++,p–等运算时无意义的。
函数指针变量通常的用途之一是把指针作为参数传递到其他函数。这个问题是C语言应用的一个比较深入的部分。
#include
int max(a, b)
{
return a > b ? a : b;
}
int min(a, b)
{
return a > b ? b : a;
}
int add(a, b)
{
return a + b;
}
int precess(int a, int b, int (*fun)(int, int))
{
return (*fun)(a, b);
}
void main()
{
int a, b;
int (*p)(int, int);
printf("enter a and b\n");
scanf("%d %d", &a, &b);
printf("max=%d\n", precess(a, b, p = max));
printf("min=%d\n", precess(a, b, (p = min)));
printf("add=%d\n", precess(a, b, (p = add)));
}
这种返回指针值的函数,一般定义形式为
类型名 *函数名(参数表列);
例如 : int *a(int x,int y);
注意:在*a两侧没有括号,在a的两侧分别为*运算符和()运算符。而()优先级高于*,因此a先与()结合。
#include
void main()
{
float *search(float(*pointer)[4], int n);
float score[][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
float *pointer;
int m, i;
printf("enter you want search student's number\n");
scanf("%d", &m);
pointer = search(score, m);
printf("the number %d student's score is %.2f %.2f %.2f %.2f", m, *(pointer + 0), *(pointer + 1), *(pointer + 2), *(pointer + 3));
}
float *search(float (*pointer)[4], int n)
{
return *(pointer + n);
}
一维指针数组的定义形式为
类型名 *数组名[数组长度]
例如:int * p[4];
略
10.1 输入3个整数,按有小到大的顺序输出
#include
void main()
{
int n1, n2, n3;
scanf("%d %d %d", &n1, &n2, &n3);
int *p1 = &n1, *p2 = &n2, *p3 = &n3, *p;
if (*p1 > *p2)
{
p = p1;
p1 = p2;
p2 = p;
}
if (*p1 > *p3)
{
p = p1;
p1 = p3;
p3 = p;
}
if (*p2 > *p3)
{
p = p2;
p2 = p3;
p3 = p;
}
printf("%d %d %d",*p1,*p2,*p3);
}
10.2 输入3个字符串,按由小到大的顺序输出
#include
#include
void main()
{
char s1[100];
char s2[100];
char s3[100];
int i, j, k, n = 3;
char *t;
char *arr[] = {s1, s2, s3};
scanf("%s %s %s", s1, s2, s3);
for (i = 0; i < n - 1; i++)
{
k = i;
for (j = i + 1; j < n; j++)
{
if (strcmp(*(arr + k), *(arr + j)) > 0)
{
k = j;
}
}
if (k != i)
{
t = *(arr + k);
*(arr + k) = *(arr + i);
*(arr + i) = t;
}
}
for (i = 0; i < n; i++)
{
printf("%s\n", *(arr + i));
}
}
#include
void scanfNum(int *arr, int n)
{
int i;
for (i = 0; i < n; i++)
{
scanf("%d", arr + i);
}
}
void handle(int *arr, int n)
{
int minIndex = 0, maxIndex = 0;
int i;
int t;
for (i = 1; i < n; i++)
{
minIndex = *(arr + minIndex) > *(arr + i) ? i : minIndex;
maxIndex = *(arr + maxIndex) < *(arr + i) ? i : maxIndex;
}
//最小的数与第一个数对换
t = *(arr + minIndex);
*(arr + minIndex) = *(arr + 0);
*(arr + 0) = t;
//最大的数与最后一个数对换
t = *(arr + maxIndex);
*(arr + maxIndex) = *(arr + n - 1);
*(arr + n - 1) = t;
}
void printArr(int *arr, int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%d ", *(arr + i));
}
}
void main()
{
int arr[10];
scanfNum(arr, 10);
handle(arr, 10);
printArr(arr, 10);
}
#include
void main()
{
int arr[9];
int i, m = 3;
void handle(int *, int, int);
for (i = 0; i < 9; i++)
{
scanf("%d", arr + i);
}
handle(arr, 9, 3);
for (i = 0; i < 9; i++)
{
printf("%d ", *(arr + i));
}
printf("\n");
}
void handle(int *arr, int n, int m)
{
int temp[10];
int i;
//保存后m个数
for (i = 0; i < m; i++)
{
*(temp + i) = *(arr + n - m + i);
}
//向后移m位
for (i = 0; i < n - m; i++)
{
*(arr + n - 1 - i) = *(arr + n - 1 - i - m);
}
//把原m个数放到前面
for (i = 0; i < m; i++)
{
*(arr + i) = *(temp + i);
}
}
1、定义和使用结构体变量,使用结构体数组,结构体指针,用指针处理链表;
2、定共用体类型;
3、使用枚举类型;
4、用typedef声明新类型名。
1、识记
(1)结构体类型变量的定义、引用和初始化
(2)共用体
2、理解
(1)定义结构体类型变量的方法
(2)共用体的概念
3、应用:
(1)结构体变量的引用
(2)结构体数组的简单应用
(3)用指针处理链表
(4)共用体变量的引用
C语言允许用户自己指定这样一种数据结构,它称为结构体。相当于其他高级语言中的“记录”
#include
void main()
{
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};
}
struct是声明结构体类型所必须使用的关键字
声明一个结构体类型的一般形式为:
struct 结构体名
{成员表列}
(1)先声明结构体类型再定义变量名
struct student student1,student2;
(2)在声明类型的同时定义变量
struct student{
…
}student1,student2;
(3)直接定义结构体类型变量
struct{
成员表列
}变量名表列;
说明:在编译时,对类型是不分配空间的,只对变量分配空间
成员也可以是一个结构体变量
(1)不能将一个结构体变量作为一个整体进行输入和输出。
引用结构体变量中成员的方式为
结构体变量名.成员名
(2)如果成员本身又属一个结构体类型,则要用若干个成员运算符,
(3)对结构体变量的成员可以像普通变量一样进行各种运算
(4)可以引用结构体变量成员的地址,也可以引用结构体变量的地址
#include
void main()
{
struct student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
} student1 = {
54, "虞姬", 'F', 26, 398, "乌江"};
printf("序号:%d\n姓名:%s\n性别:%c\n年龄:%d\n成绩:%.1f\n地址:%s\n",
student1.num, student1.name, student1.sex, student1.age, student1.score, student1.addr);
}
1.5.1 定义结构体数组
struct student
{
….
};
struct student stu[3];
1.5.2 结构体数组的初始化
struct student
{
….
} stu[3] = {{…},{…},{…}}
元素个数可以不指定
1.5.3 结构体数组应用举例
1.6.1 指向结构体变量的指针
以下3种形式等价:
(1)结构体变量.成员名
(2)(*p).成员名
(3)p->成员名
其中->称为指向运算符
1.6.2 指向结构体数组的指针
1.6.3 用结构体变量和指向结构体的指针做函数参数
将一个结构体变量的值传递给另一个函数,有3个方法;
(1)用结构体变量的成员作参数
(2)用结构体变量作参数。用结构体变量作实参时,采取的也是“值传递”的方式,将结构体变量所占的内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量。在函数调用期间形参也要占用内存单元.这种传递方式在空间和时间上开销较大。一般较少用这种方法
(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(或数组)的地址传给形参
1.7.1 链表概述
链表没有数组在初始化时需要指定大小,容易造成浪费内存的缺点。根据需要开辟内存单元。
1.7.2简单链表
1.7.3 处理动态链表所需的函数
c语言编译系统的库函数提供了以下有关函数
目的:使集中不同类型的变量存放到同一段内存单元中。
也就是使用覆盖技术,几个变量互相覆盖。这种使几个不同的变量共占同一段内存的结
构,称为“共用体”类型的结构
定义共用体类型变量的一般形式为:
union 共用体名
{
成员表列
}变量表列:
例如
union data
{
int i ;
char ch;
float f;
}a,b,c;
也可以将类型声明与变量定义分开
union data
{
int i;
char ch;
floatf;
};
union data a,b,c
“共用体”与“结构体”的定义形式相似,但含义不同
例子:
声明枚举类型用enum开头,例如:
enum weekday{sun,mon,tue,wed,thu,fri,sat};
声明了一个枚举类型 enum weekday,可以用此类型来定义变量。例如:
enum weekday workday, week-end;
workday和week-end被定义为枚举变量,它们的值只能是sun到sat之一。例如:
week-end=sun;
是正确的。当然,也可以直接定义枚举变量,例如
enum { sun, mon, tue, wed, thu, fri, sat } workday, week-end
说明:
(1)在c编译中,对枚举元素按常量处理,故称枚举常量。他们不是变量,不能对他们赋值
(2)枚举元素作为常量,它们是有值的,C语言编译按定义时的顺序使他们的值为0,1,2…
也可以改变枚举元素的值,在定义时由程序员指定,例如
enum weekday {sun=7, mon=1, tue, wed, thu, fri, sat} workday, week-end;
(3)枚举值可以用来做判断比较。
(4)一个整数不能直接赋给一个枚举变量,它们属于不同的类型。应先进行强制类型转换才能赋值。例如
workday=(enum weekday )2;
它相当于将顺序号为2的枚举元素赋给 workday,相当于
workday=tue
4、用typedef声明新类型名。
#include
void main()
{
typedef struct
{
int year;
int moon;
int day;
} DATE;
int i, count=0;
DATE d = {2020, 12, 31};
for (i = 1; i < d.moon; i++)
{
switch (i)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
count += 31;
break;
case 4:
case 6:
case 9:
case 11:
count += 30;
break;
case 2:
if ((d.year % 4 == 0 && d.year % 100 != 0) || (d.year % 100 == 0 && d.year 400 == 0))
{
count += 29;
}
else
{
count += 28;
}
break;
default:
break;
}
}
count+=d.day;
printf("今年已经过去了%d天",count);
}
#include
struct DATE
{
int year;
int moon;
int day;
};
void main()
{
int days(struct DATE);
struct DATE d1={2020,1,16};
//用结构体变量作实参是不推荐的
printf("%d年已经过去%d天\n",d1.year,days(d1));
}
int days(struct DATE d)
{
int i, count=0;
for (i = 1; i < d.moon; i++)
{
switch (i)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
count += 31;
break;
case 4:
case 6:
case 9:
case 11:
count += 30;
break;
case 2:
if ((d.year % 4 == 0 && d.year % 100 != 0) || (d.year & 100 == 0 && d.year & 400 == 0))
{
count += 29;
}
else
{
count += 28;
}
break;
default:
break;
}
}
count+=d.day;
return count;
}
#include
typedef struct
{
int num;
char name[20];
float score[3];
} STUDENT;
void main()
{
void print(STUDENT *);
int i;
STUDENT *p;
STUDENT stds[5] = {{1, "张三", {9, 9.2, 9.7}},
{2, "李四", {9.6, 9.1, 9.4}},
{3, "王五", {8.3, 9.6, 9.1}},
{4, "赵六", {7.1, 10, 9.9}},
{5, "田七", {3, 5.2, 6}}};
printf("序号 名字 成绩\n");
for (i = 0; i < 5; i++)
{
p = stds + i;
print(p);
}
}
void print(STUDENT *std)
{
printf("%-6d%-6s%-6.1f%-6.1f%-6.1f\n", (*std).num, (*std).name, (*std).score[0], (*std).score[1], (*std).score[2]);
}
#include
typedef struct
{
int num;
char name[20];
float score[3];
} STUDENT;
void main()
{
void input(STUDENT *, int);
void print(STUDENT *, int);
STUDENT *p;
STUDENT stds[5];
input(stds, 5);
print(stds, 5);
}
void input(STUDENT *stds, int num)
{
int i;
for (i = 0; i < num; i++)
{
STUDENT *std = stds + i;
scanf("%d %s %f %f %f", &std->num, &std->name, &std->score[0], &std->score[1], &std->score[2]);
}
}
void print(STUDENT *stds, int num)
{
int i;
STUDENT std;
printf("序号 名字 成绩\n");
for (i = 0; i < num; i++)
{
std = *(stds + i);
printf("%-6d%-6s%-6.1f%-6.1f%-6.1f\n", std.num, std.name, std.score[0], std.score[1], std.score[2]);
}
}
#include
typedef struct
{
int num;
char name[20];
float score[3];
} STUDENT;
void main()
{
void input(STUDENT *, int);
void print(STUDENT *, int);
STUDENT stds[5];
input(stds, 5);
print(stds, 5);
}
void input(STUDENT *stds, int num)
{
int i;
for (i = 0; i < num; i++)
{
STUDENT *std = stds + i;
scanf("%d %s %f %f %f", &std->num, &std->name, &std->score[0], &std->score[1], &std->score[2]);
}
}
void print(STUDENT *stds, int num)
{
double getAllAver(STUDENT *, int);
STUDENT *getBestStudent(STUDENT *, int);
int i;
double aver;
STUDENT *std = getBestStudent(stds, num);
aver = (std->score[0] + std->score[1] + std->score[2]) / 3;
printf("3门课程总平均成绩为:%.2lf\n", getAllAver(stds, num));
printf("序号 名字 成绩1 成绩2 成绩3 平均分数\n");
printf("%-6d%-6s%-6.1f%-6.1f%-6.1f%-6.1f\n", std->num, std->name, std->score[0], std->score[1], std->score[2], aver);
}
double getAllAver(STUDENT *stds, int count)
{
int i;
double sum;
for (i = 0; i < count; i++)
{
STUDENT *std = stds + i;
sum = sum + std->score[0] + std->score[1] + std->score[2];
}
return sum / 10 / 3;
}
STUDENT *getBestStudent(STUDENT *stds, int count)
{
int i, index = 0;
double sum;
STUDENT *std;
for (i = 0; i < count; i++)
{
double sum2;
std = stds + i;
sum2 = sum2 + std->score[0] + std->score[1] + std->score[2];
if (sum2 > sum)
{
sum = sum2;
index = i;
}
}
return stds + index;
}
#include
#include
char *new (int n)
{
char *p;
p = (char *)malloc(n * sizeof(char));
return p;
}
1、C文件的有关基本知识;
2、打开与关闭文件;
3、顺序读写数据文件;
4、随机读写数据文件;
5、文件读写的出错检测。
1、识记
文件和文件指针的概念、文件的定义方法和文件的基本操作方法
2、理解
(1)文件类型指针
(2)文件的打开与关闭
(3)文件的读写
(4)文件的输入输出
3、应用
(1)文件的打开与关闭
(2)文件的读写
C语言把文件看作是一个字符(字节)的序列,即由一个一个字符(字节)的数据顺序组成。根据数据的组织形式,可分为ASCII文件和二进制文件。C语言中对文件的存取是以字符(字节)为单位的。
每个被使用的文件都在内存中开辟一个区,用来存放文件的有关信息。这些信息保存在一个结构体变量中。该结构体类型是由系统定义的,取名为FILE
fopen函数的调用方式通常为:
FILE *fp
fp=fopen(文件名,使用文件方式);
例如:
fp=fopen(“al”,“r”);
用 fclose函数关闭文件。 fclose函数调用的一般形式为
fclose(文件指针);
例如:
fclose(fp);
(1)fputc函数
将一个字符写到磁盘文件上去。其一般调用形式为
fputc(ch,fp)
(2)fgetc函数
ch = fgetc(fp);
使用feof(fp)来测试fp所指向的文件当前状态是否“文件结束”。如果是文件结束,函数feof(fp)的值为1(真),否则为0(假)。
(3)fread函数
(4)fwrite函数
略
#include
#include
void main()
{
void upWord(char *);
void saveToFile(char *, char *);
char *readFromFile(char *);
char str[100];
// scanf("%s", str);
// getchar(); //接收在执行scanf语句时最后输出的回车符
int i;
char ch;
while ((ch = getchar()) != '!')
{
str[i++] = ch;
}
str[i] = '\0';
upWord(str);
saveToFile("13.4.txt", str);
printf("文件写入结束,以下为文件内容\n");
printf("%s", readFromFile("13.4.txt"));
}
void upWord(char *str)
{
int i;
int dist = 'a' - 'A';
int ch;
for (i = 0; (ch = *(str + i)) != '\0'; i++)
{
if (ch >= 'a' && ch <= 'z')
{
ch -= dist;
*(str + i) = ch;
}
}
}
void saveToFile(char fileName[], char textContext[])
{
FILE *fp;
char ch;
int i = 0;
if ((fp = fopen(fileName, "w")) == NULL)
{
printf("cannot open this file\n");
exit(0);
}
for (ch = textContext[0]; ch != '\0'; i++)
{
ch = textContext[i];
fputc(ch, fp);
}
fclose(fp);
}
char *readFromFile(char fileName[])
{
FILE *fp;
int i;
char ch;
static char str[100];
if ((fp = fopen(fileName, "r")) == NULL)
{
printf("cannot open this file\n");
}
for (i = 0; (str[i] = fgetc(fp)) != EOF; i++)
;
return str;
}
#include
#include
#include
void main()
{
char *readFromFile(char *);
void sortCharArr(char *);
void saveToFile(char *, char *);
char *aStr;
char *bStr;
char cStr[200];
int i, j;
char ch;
aStr = readFromFile("a.txt");
bStr = readFromFile("b.txt");
printf("a文件里面的内容为:\n%s\n", aStr);
printf("b文件里面的内容为:\n%s\n", bStr);
//复制字符串
for (i = 0; (ch = *(aStr + i)) != '\0'; i++)
{
cStr[i] = ch;
}
for (j = 0; (ch = *(bStr + j)) != '\0'; j++)
{
cStr[i++] = ch;
}
cStr[i] = '\0';
//排序
sortCharArr(cStr);
printf("cStr里面的内容为:\n%s\n", cStr);
//保存
saveToFile("c.txt", cStr);
printf("成功保存cStr到文件c.txt\n");
printf("c文件内容如下:\n");
printf("%s", readFromFile("c.txt"));
}
void sortCharArr(char *str)
{
int i, j, k;
char t;
int len = strlen(str);
for (i = 0; i < len - 1; i++)
{
k = i;
for (j = i + 1; j < len; j++)
{
if (*(str + k) > *(str + j))
{
k = j;
}
}
if (i != k)
{
t = *(str + k);
*(str + k) = *(str + i);
*(str + i) = t;
}
}
}
void saveToFile(char fileName[], char textContext[])
{
FILE *fp;
char ch;
int i = 0;
if ((fp = fopen(fileName, "w")) == NULL)
{
printf("cannot open this file\n");
exit(0);
}
for (ch = textContext[0]; ch != '\0'; i++)
{
ch = textContext[i];
fputc(ch, fp);
}
fclose(fp);
}
char *readFromFile(char fileName[])
{
FILE *fp;
int i;
char ch;
static int count = 0;
static char strArr[10][100] = {'\0'};
char *str = strArr[count++];
if ((fp = fopen(fileName, "r")) == NULL)
{
printf("cannot open this file\n");
}
for (i = 0; (ch = fgetc(fp)) != EOF; i++)
{
*(str + i) = ch;
}
return str;
}
#include
#include
typedef struct
{
int num;
char name[10];
float score[3];
float average;
} STUDENT;
void main()
{
void inputfromScanf(STUDENT * stds, int count);
void calcuAver(STUDENT * stds, int count);
void output(STUDENT * stds, int count, char *fileName);
void read(char *fileName);
STUDENT stds[5];
inputfromScanf(stds, 5);
calcuAver(stds, 5);
output(stds, 5, "student_score_table.txt");
printf("文件内容如下:\n");
read("student_score_table.txt");
}
void inputfromScanf(STUDENT *stds, int count)
{
int i;
for (i = 0; i < count; i++)
{
STUDENT *std = stds + i;
scanf("%d %s %f %f %f", &std->num, &std->name, &std->score[0], &std->score[1], &std->score[2]);
}
}
void calcuAver(STUDENT *stds, int count)
{
int i;
STUDENT *std;
for (i = 0; i < count; i++)
{
std = stds + i;
std->average = (std->score[0] + std->score[1] + std->score[2]) / 3;
}
}
void output(STUDENT *stds, int count, char *fileName)
{
FILE *fp;
int i;
if ((fp = fopen(fileName, "wb")) == NULL)
{
printf("cannot open file\n");
return;
}
for (i = 0; i < count; i++)
{
fwrite(stds + i, sizeof(STUDENT), 1, fp);
if (ferror(fp))
{
printf("write data to file happen error\n");
return;
}
printf("write data to file %d%%\n", (i + 1) * 100 / 5);
}
fclose(fp);
}
void read(char *fileName)
{
FILE *fp;
STUDENT std;
int i = 0;
if ((fp = fopen(fileName, "r")) == NULL)
{
printf("cannot open file");
return;
}
for (i = 0; !feof(fp); i++)
{
fread(&std, sizeof(STUDENT), 1, fp);
printf("%-6d%-6s%-4.1f%-4.1f%-4.1f%-4.1f\n", std.num, std.name, std.score[0], std.score[1], std.score[2], std.average);
}
fclose(fp);
}
r);
printf(“文件写入结束,以下为文件内容\n”);
printf("%s", readFromFile(“13.4.txt”));
}
void upWord(char *str)
{
int i;
int dist = ‘a’ - ‘A’;
int ch;
for (i = 0; (ch = *(str + i)) != ‘\0’; i++)
{
if (ch >= ‘a’ && ch <= ‘z’)
{
ch -= dist;
*(str + i) = ch;
}
}
}
void saveToFile(char fileName[], char textContext[])
{
FILE *fp;
char ch;
int i = 0;
if ((fp = fopen(fileName, “w”)) == NULL)
{
printf(“cannot open this file\n”);
exit(0);
}
for (ch = textContext[0]; ch != ‘\0’; i++)
{
ch = textContext[i];
fputc(ch, fp);
}
fclose(fp);
}
char *readFromFile(char fileName[])
{
FILE *fp;
int i;
char ch;
static char str[100];
if ((fp = fopen(fileName, “r”)) == NULL)
{
printf(“cannot open this file\n”);
}
for (i = 0; (str[i] = fgetc(fp)) != EOF; i++)
;
return str;
}
[外链图片转存中...(img-NCBf4H5N-1585227264534)]
```c
#include
#include
#include
void main()
{
char *readFromFile(char *);
void sortCharArr(char *);
void saveToFile(char *, char *);
char *aStr;
char *bStr;
char cStr[200];
int i, j;
char ch;
aStr = readFromFile("a.txt");
bStr = readFromFile("b.txt");
printf("a文件里面的内容为:\n%s\n", aStr);
printf("b文件里面的内容为:\n%s\n", bStr);
//复制字符串
for (i = 0; (ch = *(aStr + i)) != '\0'; i++)
{
cStr[i] = ch;
}
for (j = 0; (ch = *(bStr + j)) != '\0'; j++)
{
cStr[i++] = ch;
}
cStr[i] = '\0';
//排序
sortCharArr(cStr);
printf("cStr里面的内容为:\n%s\n", cStr);
//保存
saveToFile("c.txt", cStr);
printf("成功保存cStr到文件c.txt\n");
printf("c文件内容如下:\n");
printf("%s", readFromFile("c.txt"));
}
void sortCharArr(char *str)
{
int i, j, k;
char t;
int len = strlen(str);
for (i = 0; i < len - 1; i++)
{
k = i;
for (j = i + 1; j < len; j++)
{
if (*(str + k) > *(str + j))
{
k = j;
}
}
if (i != k)
{
t = *(str + k);
*(str + k) = *(str + i);
*(str + i) = t;
}
}
}
void saveToFile(char fileName[], char textContext[])
{
FILE *fp;
char ch;
int i = 0;
if ((fp = fopen(fileName, "w")) == NULL)
{
printf("cannot open this file\n");
exit(0);
}
for (ch = textContext[0]; ch != '\0'; i++)
{
ch = textContext[i];
fputc(ch, fp);
}
fclose(fp);
}
char *readFromFile(char fileName[])
{
FILE *fp;
int i;
char ch;
static int count = 0;
static char strArr[10][100] = {'\0'};
char *str = strArr[count++];
if ((fp = fopen(fileName, "r")) == NULL)
{
printf("cannot open this file\n");
}
for (i = 0; (ch = fgetc(fp)) != EOF; i++)
{
*(str + i) = ch;
}
return str;
}
[外链图片转存中…(img-G8H2GDCZ-1585227264534)]
#include
#include
typedef struct
{
int num;
char name[10];
float score[3];
float average;
} STUDENT;
void main()
{
void inputfromScanf(STUDENT * stds, int count);
void calcuAver(STUDENT * stds, int count);
void output(STUDENT * stds, int count, char *fileName);
void read(char *fileName);
STUDENT stds[5];
inputfromScanf(stds, 5);
calcuAver(stds, 5);
output(stds, 5, "student_score_table.txt");
printf("文件内容如下:\n");
read("student_score_table.txt");
}
void inputfromScanf(STUDENT *stds, int count)
{
int i;
for (i = 0; i < count; i++)
{
STUDENT *std = stds + i;
scanf("%d %s %f %f %f", &std->num, &std->name, &std->score[0], &std->score[1], &std->score[2]);
}
}
void calcuAver(STUDENT *stds, int count)
{
int i;
STUDENT *std;
for (i = 0; i < count; i++)
{
std = stds + i;
std->average = (std->score[0] + std->score[1] + std->score[2]) / 3;
}
}
void output(STUDENT *stds, int count, char *fileName)
{
FILE *fp;
int i;
if ((fp = fopen(fileName, "wb")) == NULL)
{
printf("cannot open file\n");
return;
}
for (i = 0; i < count; i++)
{
fwrite(stds + i, sizeof(STUDENT), 1, fp);
if (ferror(fp))
{
printf("write data to file happen error\n");
return;
}
printf("write data to file %d%%\n", (i + 1) * 100 / 5);
}
fclose(fp);
}
void read(char *fileName)
{
FILE *fp;
STUDENT std;
int i = 0;
if ((fp = fopen(fileName, "r")) == NULL)
{
printf("cannot open file");
return;
}
for (i = 0; !feof(fp); i++)
{
fread(&std, sizeof(STUDENT), 1, fp);
printf("%-6d%-6s%-4.1f%-4.1f%-4.1f%-4.1f\n", std.num, std.name, std.score[0], std.score[1], std.score[2], std.average);
}
fclose(fp);
}
[外链图片转存中…(img-uiUBGPZs-1585227264535)]
略: