导图社区 C语言
C程序设计第四版谭浩强著,知识框架图。语言功能很强,且不依赖具体机器,用它写的程序对任何型号的计算机都适用(或只须作很少的修改),它与具体机器距离较远。
编辑于2021-03-02 19:49:51C语言
第一章程序设计和C语言
计算机程序
一组计算机能识别和执行的指令
计算机语言
机器语言
计算机工作基于二进制,从根本上说,计算机只能识别和接受由0和1组成的指令
机器指令(目标程序)
计算机能直接识别和接受的二进制代码
机器指令的集合就是该计算机的机器语言
符号语言(符号汇编语言)/汇编语言
用一些英文字母和数字表示一个指令
低级语言
高级语言(源程序)
语言功能很强,且不依赖具体机器,用它写的程序对任何型号的计算机都适用(或只须作很少的修改),它与具体机器距离较远
发展阶段
1.非结构化的语言
BASIC/FORTRAN/ALGOL
2.结构化语言
QBASIC/FORTRAN77/C语言
3.面向对象的语言
C++/C#/Visual Basic/Java
C语言的发展及其特点
发展
BCPL语言-B语言-C语言
特点
1.语言简洁、紧凑、使用方便、灵活
2.运算符丰富
3.数据类型丰富
4.具有结构化的控制语句
5.语言限制不太严格,程序设计自由度大
6.C语言允许直接访问物理地址
7.用语言编写的程序可移植性好
8.生成目标代码质量高,程序执行效率高
最简单的C语言程序
程序中如要用到标准函数库中的输入输出函数,应该在程序开头:#include<stdio.h>
注释方法
以//开始的单行注释
以/*开始,以*/结束的块式注释
注意:在字符串中的//和/*都不作为注释的开始,而是作为字符串的一部分
C语言程序的结构
一个程序由一个或多个源程序文件组成
1.预处理指令
#include<stdio.h>
#define
2.全局声明
全局变量
在函数外面声明的变量
局部变量
在函数中声明的变量(只在函数范围内有效)
3.函数定义
函数是c程序的主要组成部分
函数构成
函数首部(函数的第一行)
int max(int x,int y);
函数名(max)
函数类型(int)
函数属性
函数参数(形式参数)名(x,y)
参数类型(int)
函数体
声明部分
执行部分
程序总是从main函数开始执行的
程序中对计算机的操作是由函数中的C语句完成的
在每个数据声明和语句的最后必须有一个分号
C语言本身不提供输入输出语句
程序应当包含注释
运行C程序
1.上机输入和编辑源程序
文件用.c作为后缀,生成源程序文件
2.对源程序进行编译(预处理+编译)
编译程序自动把源程序转换为二进制形式的目标程序(后缀为.obj)
对源程序进行检查,判定它有无语法方面的错误
3.进行连接处理
把所有的编译后得到的目标模块连接装配起来,再与函数库相连接成一个整体,生成一个可供计算机执行的目标程序-----可执行程序(后缀.exe)
4.运行可执行程序
第二章算法
程序结构
数据结构
算法
算法+数据结构=程序
算法
为解决一个问题而采取的方法和步骤
分类
数值运算算法
求数值解
非数值运算算法
特点
一般性,通用性,灵活性
特性
有穷性
一个算法应包含有限的操作步骤,而不能是无限的
确定性
算法的含义应当是唯一的,而不应当产生歧义性
有零个或多个输入
有一个或多个输出
有效性
算法表示
用自然语言表示算法
用流程图表示算法
弊端
难以阅读,且难以修改,算法的可靠性和可维护性难以保证
基本结构
顺序结构
选择结构
循环结构
当型(while型)循环结构
直到型(until型)循环结构
顺序结构和选择结构
循环结构
共同特点
1.只有一个入口
2.只有一个出口
3.结构内的每一部分都有机会被执行到
4.结构内不存在“死循环”
用N-S流程图表示算法
1.顺序结构
2.选择结构
3.循环结构
用伪代码表示算法
用计算机语言表示算法
第三章顺序程序设计
数据的表现形式及其运算
表现形式
常量
在程序运行过程中,其值不能被改变的量
分类
整型常量
实型常量
十进制小数形式
指数形式
12.34e3(代表12.34x10Ù3)
e或E之前必须有数字,且e或E后面必须为整数
字符常量
普通字符
用单撇号括起来的一个字符,如:‘a’,‘Z’,'!'
单撇号只是界限符,字符常量只能是一个字符,不包括单撇号,‘12’‘ab’错误
转义字符
子主题
字符常量存储并不是存储字符,而是以其代码存储的
字符串常量
用双撇号把若干个字符括起来,字符串常量是双撇号中的全部字符
符号常量
用#define指令,指定用一个符号名称代表一个常量,例#define PI 3.1416//注意行末没有分号
在对程序编译前,预处理器先对PI进行处理,把所有PI全部置换为3.1416
1.含义清楚
2.在需要改变程序中多处用到的同一变量时,能做到“一改全改”
不占内存,在预编译后这个符号就不存在,不能对符号常量赋新值
变量
变量代表一个有名字的,具有特定属性的一个存储单元,它用来存放数据,也就是存放变量的值
变量必须先定义,后使用,在定义的时指定该变量的名字和类型
常变量
const int a=3;//表示a被定义为一个整型变量,指定其值为3,而且在变量存在期间其值不能改变
常变量与常量的异同:常变量具有变量的基本属性:有类型,占存储单元,只是不允许改变其值,常变量是有名字的不变量,而常量是没有名字的不变量
标识符
在计算机高级语言中,用来对变量、符号常量名、函数、数组、类型等命名的有效字符序列统称为标识符
规定
标识符只能由字母、数字和下划线3种字符组成,且第一个字符必须为字母或下划线
数据类型
基本类型
整形类型
基本整型(int)
短整型(short int)
长整型(long int)
*双长整型(long long int)
字符型(char)
*布尔型(bool)
浮点类型
单精度浮点型(float)
双精度浮点型(double)
复数浮点型
存储空间和值的范围
枚举类型(enum)
算术类型
空类型(void)
派生类型
指针类型(*)
数组类型([])
结构体类型(struct)
组合类型
共用体类型(union)
函数类型
字符数据
字符和字符代码
字符集127个字符
字母:大写英文字母A~Z,小写英文字母a~z
数字:0~9
专门符号
空格符
不能显示的字符
空(null)字符(以’\0‘表示)、警告(以’\a‘表示)、退格(以’\b‘表示)、回车(以’\r‘表示)
字符变量
类型符char定义字符变量
char c=‘?’;//系统把整数63(ASCII)赋给变量c
char c=255;//255已经超过char变量的数值允许范围,在运行时输出-1
char=signed char
浮点型数据
用来表示小数点的实数
由于小数点位置可以浮动,所以实数的指数形式称为浮点数(计算机中实数都是指数形式存放)
规范化的指数形式
小数部分中小数点前的数字为0、小数点后第一位数字不为0的表示形式
在程序以指数形式输出一个实数时,必然以规范化指数形式输出
float型(单精度浮点型)
存储时,系统将实型数据分成小数部分+指数部分
小数部分占的位数越多,数的有效数字越多,精度越高。
指数部分占的位数越多,则能表示的数值范围越大
float型数据能得到6位有效数字,数值范围为-3.4x10^-38~3.4x10^38
double型(双精度浮点型)15位
long double(长双精度)19位
确定常量类型
原因
在程序中出现的常量是要存放在计算机内存单元中的。这就必须确定分配给它多少字节,按什么方式存储
C编译器把浮点型常量都按照双精度处理
把一个双精度常量转换为float型,一般不会影响程序运行结果的正确性,但会影响程序运行结果的精确性
可以在常量的末尾加专门字符,强制指定常量类型
类型与变量
每一个变量都属于一个确定的类型,类型是变量的一个重要属性
变量是占用存储单元的,是具体存在的实体,在其占用的存储单元中可以存放数据
类型是变量的共性,是抽象的,不占用存储单元,不能用来存放数据
运算符和表达式
基本的运算符
两个实数相除的结果是双精度实数,两个整数相除的结果为整数,向零取整原则
自增、自减运算符
++i,--i
在使用i之前,先使i的值加(减)1
i++,i--
在使用i之后,使i的值加(减)1
只能用于变量
不能用于常量和表达式
5++、(a+b)++都不合法
算术表达式和运算符的优先级和结合性
c算术表达式
用算术运算符和括号将运算对象连接起来的,符合C语句规则的式子
优先级
初等运算符
单目运算符(!逻辑非)(自右往左)
算术运算符(乘除高于加减)
关系运算符
逻辑运算符(与高于或)
条件运算符(? :)(自右向左)
赋值运算符(自右向左)
逗号运算符
优先级由上到下递减,379页附录D
不同类型数据间的混合运算
+、-、*、/运算的两个数中有一个数为float或double型,结果是double型
如果int型与float或double型数据进行运算,结果为double型
字符(char)型数据与整型数据进行运算,就是把字符的ASCII代码与整型数据进行运算
系统将所有float型数据都先转换为double型,然后计算
强制类型转换运算符
一般形式:(类型名)(表达式)
(double)a
(int)(x+y);//将x+y的值转换成int型
(float)(5%3)
类型转换
自动类型转换
3+6.5
强制类型转换
(int)x%3
注:%运算符要求其两侧均为整型量
重点
C语句
C语句的作用和分类
函数结构
函数首部
函数体
声明部分
执行部分
函数作用
向计算机系统发出操作指令,要求执行相应的操作
分类
控制语句
1.if()...else...(条件语句)
2.for()...(循环语句)
3.while()...(循环语句)
4.do...while()(循环语句)
5.continue(结束本次循环语句)
6.break(中止执行switch或循环语句)
7.switch(多分支选择语句)
8.return(从函数返回语句)
9.goto(转向语句)
函数调用语句
如:printf("this is a c statement.");
表达式语句
a=3;
空语句
;
加分号
复合语句
用{}把一些语句和声明括起来成为复合语句
赋值语句
赋值运算符
=
复合的赋值运算符
在赋值运算符=之前加上其他运算符,可以构成复合的运算符
a+=3
等价于a=a+3
x*=y+8
等价于x=x*(y+8)
x%=3
等价于x=x%3
赋值表达式
一般形式
变量 赋值运算符 表达式
注意
变量可以为左值,算术表达式(a+b)不能为左值,常量不能为左值
赋值过程中的类型转换
1.将浮点型数据(包括单,双精度)赋给整型变量
先对浮点数取整,即舍弃小数部分,然后赋予整型变量
2.将整型数据赋给单双精度变量时,数值不变
3.将一个double型数据赋给float变量时,先将双精度转换为单精度,即只取6~7位有效数字。注意不能超过float型变量的数值范围
4.float型数据赋给double变量时,数值不变
5.字符型数据赋给整型变量时,将字符的ASCII代码赋给整型变量
6.将一个占字节多的整型数据赋给一个占字节少的整型变量或字符变量时,只将其低字节原封不动送到被赋值的变量(截断现象)
赋值表达式和赋值语句
一个赋值表达式加一个分号组成赋值语句
变量赋初值
正确:int a=3,b=3,c=3;
错误:int a=b=c=3;
数据的输入输出
C语言函数库中有一批标准输入输出函数
putchar(输出字符)
getchar(输入字符)
printf(格式输出)
scanf(格式输入)
puts(输出字符串)
gets(输入字符串)
printf函数输出数据
作用
用来向终端(或系统隐含指定的输出设备)输出若干个任意类型的数据
一般格式
printf(格式控制,输出列表)
例:printf("%d,%c\n",i,c);
格式控制
格式声明
将输出的数据转换为指定的格式然后输出
普通字符
普通字符即需要在输出时原样输出的字符
输出列表
程序需要输出的一些数据,可以是常量、变量或表达式
格式字符
d格式符(%d)
(%d)
用来输出一个有符号的十进制整数
(%ld)长整型
(%lld)双长整型
(%5d)
可以在格式声明中指定输出数据的域宽
指定数据占5列,输出的数据显示在此5列区域的右对齐
c格式符(%c)
用来输出一个字符
可以指定域宽(右对齐)
一个整数,如果在0~127范围内,也可以用“%c”输出对应ASCII转换成相应的字符
例:print("%c",a);//a=121,输出字符y
如果整数比较大,则把它的最后一个字节的信息以字符形式输出(截断)
例:print("%c",a);//a=337,输出字符y
s格式符(%s)
用来输出一个字符串
printf("%s","china");
f格式符(%f)
用来输出实数
1.基本型,用%f
实数中的整数部分全部输出,小数部分输出6位
2.指定数据宽度和小数位数,用%m.nf(右对齐)
输出的数据占m列,其中包括n位小数
注意:用%f输出时要注意数据本身能提供的有效数字
float型数据的存储单元只能保证6位有效数字
double型数据能保证15位有效数字
3.输出的数据左对齐,用%-m.nf
e格式符(%e、%E)
指定以指数形式输出实数
如果不指定输出数据所占的宽度和数字部分的小数位数,会自动给出数字部分的小数位数为6位,指数部分占5列(e占一列,符号占一列,指数占3列),按标准化指数形式输出
可用“%m.ne”形式的格式声明
i格式符
十进制输出
o格式符
以八进制整数形式输出
x格式符
以十六进形式输出
u格式符
十进制整数形式输出无符号型数据
g格式符
输出浮点数
系统自动选f格式或e格式输出,选择长度较短的格式输出
想输出字符“%”,应该在“格式控制字符串”中用连续两个“%”
printf("%f%%\n",1.0/3);
scanf函数输入数据
scanf函数的一般形式
scanf(格式控制,地址表列)
地址表列
由若干个地址组成的表列,可以是变量的地址,或字符串的首地址
scanf函数中的格式声明
格式字符
使用scanf函数时应注意问题
scanf函数中的“格式控制”后面应当是变量地址,而不是变量名
如果在“格式控制字符串”中除了格式声明以外还有其他字符,则在输入数据时在相应的位置上应输入与这些字符相同的字符
在用“%c”格式声明输入字符时,空格字符和“转义字符”中的字符都作为有效输入
在输入数值数据时,如输入空格、回车、tab键或遇非法字符(不属于数值的字符),认为该数据结束
字符数据的输入输出
用putchar函数输出一个字符
从计算机向显示器输出一个字符
一般格式:putchar(c)
char a='B'; putchar(a);
int a=66; putchar(a);
将一个字符赋给字符变量和将字符的ASCII代码赋给字符变量作用是完全相同的(0~127)
putchar(getchar()); printf("%c",getchar());
用getchar函数输入一个字符
从计算机终端(一般是键盘)输入一个字符
一般格式:getchar()
第四章 选择结构程序设计
选择结构和条件判断
两种选择语句
if语句
用来实现两个分支选择结构
一般形式
if(表达式) 语句1//(没有else子句部分)
if(表达式) 语句1 else 语句2
if(表达式1) else if(表达式2) else if(表达式3) ...... else//嵌套多层if
switch语句
用来实现多分支选择结构
关系运算符和关系表达式
关系运算符
<(小于)
<=(小于等于)
>(大于)
>=(大于等于)
优先级相同(高)
==(等于)
!=(不等于)
优先级相同(低)
关系表达式
用关系运算符将两个数值或数值表达式连接起来的式子
表达式的值是一个逻辑值,即“真”或“假”
a=3,b=2,c=1,则f=a>b>c,则f的值为0:a>b的值为1,1>c的值为0
逻辑运算符和逻辑表达式
逻辑运算符及其优先次序
子主题
优先次序
逻辑表达式
c语言编译系统在表示逻辑运算结果时,以数值1代表“真”,以0代表”假“
在判断一个量是否为真时将一个非0的数值认作为“真”
有些逻辑表达式并不是所以逻辑运算符都被执行
a&&b&&c
若a为0,不用判断后面
a||b||c
若a=1,不用判断后面
逻辑型变量
类型符号:_Bool
头文件中包含#include<stdbool.h>
逻辑型变量bool
ture代表1
false代表0
条件运算符和条件表达式
条件运算符
条件运算符由两个符号(?和:)组成,必须一起使用。要求有3个操作对象,称为3目运算符
条件表达式
一般形式
表达式1?表达式2:表达式3
若表达式1为真,则执行表达式2
若表达式1为假,则执行表达式3
选择结构的嵌套
else总是与它上面的最近的未配对的if配对
用switch语句实现多分支选择结构
一般形式
作用
根据表达式的值,使流程跳转到不同的语句
switch后面括号内的表达式,其值的类型应为整数类型(包括字符型)
一般情况下,在执行一个case子句后,应当用break语句跳出switch结构,即终止switch语句的执行
多个case标号,也可以共用一组执行语句
case'A': case'B': case'C':printf(">60\n");break;
第五章循环结构程序设计
用while语句实现循环
一般形式:while(表达式)语句
只要当循环条件表达式为真(即给定的条件成立),就执行循环体语句
while循环的特点:先判断条件表达式,后执行循环体语句
用do...while语句实现循环
执行过程:先执行循环体,然后再检查条件是否成立,若成立,再执行循环体
一般形式:
do 语句 while(表达式)
特点:先无条件地执行循环体,然后判断循环条件是否成立
至少要执行一次循环体
当while后面的表达式的第一次的值为“真”时两种循环结果相同, 否则结果不相同
用for语句实现循环
一般形式:for(表达式1;表达式2;表达式3) 语句:for (循环变量赋初值;循环条件;循环变量增值)
表达式1的作用
设置初始条件,只执行一次。也可以为零个、一个或多个变量的初值
表达式2的作用
循环条件表达式,用来判定是否继续循环。在每次执行循环体前先执行此表达式,决定是否继续执行循环
表达式3的作用
作为循环的调整,例如使循环变量增值,它在执行完循环体后才进行的。
循环嵌套
一个循环体内又包含另一个完整的循环结构
改变循环执行的状态
用break语句提前终止循环
break语句的一般形式:break
作用是使流程跳到循环体之外,接着执行循环体下面的语句
break语句只能用于循环语句和switch语句之中,而不能单独使用
用continue语句提前结束本次循环
希望提前结束本次循环,而接着执行下次循环
一般形式:continue;
区别
continue语句只结束本次循环,而不是终止整个循环的执行
break语句则是结束整个循环过程
第六章 利用数组处理批量数据
定义和引用一维数组
定义数组
一般形式:类型符 数组名[常量表达式];
int a[10];
表示a数组有10个元素
下标从0开始,到9
C语言不允许对数组的大小作动态定义
在被调用的函数(不包括主函数)中定义数组,其长度可以是变量或非常量表达式
如果指定数组为静态存储方式,则不能用“可变长数组”
引用一维数组元素
引用数组元素的表达式:数组名[下标]
注意只能引用数组,不能一次调用整个数组全部元素的值
一维数组的初始化
在定义数组的同时,给各数组元素赋值,这称为数值的初始化
1.在定义数组时对全部数组元素赋予初值
int a[10]={0,1,2,3,4,5,6,7,8,9}
2.可以只给数组中一部分元素赋值,未赋值的全部为0
int a[10]={0,1,2,3,4};
3.如果想让一个数组全为0
int a[10]={0};
4.在对全部数组元素赋值时,由于数据的个数已经确定,因此可以不指定数组长度
5.如果数组长度与提供初值的个数相同,则方括号中的数组长度不能省略
定义和引用二维数组
定义二维数组
一般形式 类型说明符 数组名[常量表达式][常量表达式]
例:float a[3][4],b[5][10];
二维数组可被看作是一种特殊的一维数组:它的元素又是一维数组
二维数组中元素排列的顺序是按行存放的,即在存放中先顺序存放第一行的元素,接着再存放第二行的元素
引用二维数组
一般形式 数组名[下标][下标]
数组元素可以出现在表达式中,也可以被赋值
b[1][2]=a[2][3]/2
行序号和列序号均从0起算
二维数组的初始化
1.分行给二维数组赋初值
例:int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
2.将所有数据写在一个花括号内,按数组元素在内存中的排列顺序对各元素赋初值
例:int a[3][4]={1,2,3,4,5,6,7,8,9,0,1,2};
3.对部分元素赋初值
例:int a[3][4]={{1},{2},{4}};//只对各行第一列(即序号为0的列)的元素赋初值,其余元素值自动为0。
4.如果对全部元素都赋初值,则定义数组对第一维的长度可以不指定,但第二维的长度不能省略
字符数组
定义字符数组
char c[10]; c[0]='i';c[2]='a';....
字符数组的初始化
用初始化列表,把各个字符依次赋值给数组中各元素
例:char c[10]={'i',' ','a'....};
如果在定义字符数组时不进行初始化,则数组中各元素的值是不可预料的。
引用字符数组中的元素
同上
字符串和字符串结束标志
“字符串结束标志”以字符‘\0’作为结束标志
遇到字符‘\0’时,表示字符串结束,把它前面的字符组成一个字符串
'\0'是一个空字符
用来作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志
用字符串常量来使字符数组初始化
例:char c[]={"i am happy"};
char c[]="i am happy";
数组c的长度为11(包括\0)
字符数组的输入输出
逐个字符输入输出。:用格式符%c输入或输出一个字符
将整个字符串一次输入或输出:用“%s”格式符,意思是对字符串的输入输出
可以用scanf函数输入一个字符串
使用字符串处理函数
puts函数--输出字符串的函数
一般形式:puts(字符数组)
将一个字符串(以‘\0’结束的字符序列)输出到终端
gets函数--输入字符串函数
一般形式:gets(字符数组)
从终端输入一个字符数组,并且得到一个函数值
该函数值是字符数组的起始地址
strcat函数--字符串连接函数
一般形式:strcat(字符数组1,字符数组2)
把两个字符数组中的字符串连接起来,把字符串2接到字符串1的后面,结果放在字符数组1中,调用后得到一个函数值--字符数组1的地址。
字符数组1必须足够大,以便容纳连接后的新字符串
strcpy和strncpy函数--字符串复制函数
一般形式:strcpy(字符数组1,字符数组2)
将字符串2复制到字符串1中去
字符数组1必须足够大,以便容纳被复制的字符串2
字符数组2可以是一个字符串常量。:strcpy(str1,"china");
不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组,只能用strcpy函数将一个字符串复制到另一个字符数组中去,赋值语句只能赋值一个字母
可以用strcpy函数将字符串2中前面n个字符复制到字符数组1中去,strncpy(str1,str2,2);
strcmp函数---字符串比较函数
一般形式为:strcmp(字符串1,字符串2)
比较字符串1和字符串2
比较规则
将两个字符串自左到右逐个字符相比(按ASCII码值大小比较),直到出现不同的字符或遇到‘\n’为止
1.如全部字符相同,则认为两个字符串相等
2.若出现不相同的字符,则以第一对不相同的字符的比较结果为准
比较的结果
1.如果字符串1=字符串2,则函数值为0
2.如果字符串1>字符串2,则函数值为一个正整数
3.如果字符串1<字符串2,则函数值为一个负整数
strlen函数----测字符串长度的函数(字母个数)
一般形式:strlen(字符数组)
函数值为字符串中的实际长度(不包括‘\0’在内)
strlwr---转换为小写的函数
一般形式:strlwr(字符串)
将字符串中大写字母换成小写字母
strupr函数---转换为大写的函数
一般形式:strupr(字符串)
将字符串中小写字母换成大写字母
在使用字符串处理函数时,应当在程序文件的开头用#include<string.h>
主题
第10章 对文件的输入输出
C文件的有关基本知识
文件
存储在外部介质上数据的集合
程序文件
包含源程序文件(后缀.c)、目标文件(后缀.obj)、可执行文件(后缀为.exe)等。
数据文件
文件的内容不是程序,而是供程序运行时读写的数据,如在程序运行过程中输出到磁盘(或其他外部设备)的数据,或在程序运行过程中供读入的数据。
磁盘文件
数据输出到磁盘上保存起来,以后需要时再从磁盘中输入到计算机内存
文件名
文件标识
1.文件路径
2.文件名主干
3.文件名后缀
文件缓冲区
值系统自动地在内存区为程序中每一个正在使用的文件开辟一个文件缓冲区
文件的分类
数据文件
ASCII文件(文本文件)
二进制文件(映像文件)
文件类型指针
该结构体类型是由系统声明的,取名为FILE.
通过文件指针变量能够找到与它关联的文件
指向文件的指针变量并不是指向外部介质上的数据文件的开头,而是指向内存中的文件信息区的开头
打开与关闭文件
打开
文件建立相应的信息区(用来存放有关文件的信息)和文件缓冲区(用来暂时存放输入输出的数据)
关闭
撤销文件信息区和文件缓冲区,使文件指针变量不再指向该文件
用fopen函数打开数据文件
调用方式:fopen(文件名,使用文件方式);
用fclose函数关闭数据文件
调用方式:fclose(文件指针);
顺序读写数据文件
怎样向文件读写字符
怎样向文件读写一个字符串
fgets函数原型
char*fgets(char*str,int n,FILE*fp);//作用是从文件读入一个字符串。调用时可以写成fgets(str,n,fp);
fputs函数原型
int fputs(char*str,FILE*fp);//作用是将str所指的字符串输出到fp所指的文件中
用格式化的方式读写文件
fprintf函数
调用方式:fprintf(文件指针,格式字符串,输出表列);
fscanf函数
调用方式:fscanf(文件指针,格式字符串,输入表列);
用二进制方式向文件读写一组数据
fread函数从文件中读入一个数据块
调用形式:fread(buffer,size,count,fp);
buffer:是一个地址
对fread来说,它是用来存放从文件读入的数据的存储区的地址
对fwrite来说,是要把此地址开始的存储区中的数据向文件输出
size:要读写的字节数
count:要读写多少个数据项
fp:FILE类型指针
fwrite函数向文件中写一个数据块
调用形式:fwrite(buffer,size,count,fp);
随机读写数据文件
文件位置标记及其定位
文件位置标记
为了对读写进行控制,系统为每个文件设置了一个文件读写位置标记(简称文件位置标记或文件标记)
文件位置标记的定位
1.用rewind函数使文件位置标记指向文件开头
rewind函数的作用是使文件位置标记重新返回文件的开头,此函数没有返回值。
2.用fseek函数改变文件位置标记
调用形式:fseek函数的调用形式:fseek(文件类型指针,位移量,起始点)
起始点可以用0、1、2代替。0代表文件开始位置,1代表当前位置,2代表文件末尾位置
位移量指以起始点为基点,向前移动的字节数。位移量应用long型数据(在数字的末尾加一个字母L)
3.用ftell函数测定文件位置标记的当前位置
ftell函数的作用是得到流式文件中文件位置标记的当前位置
随机读写
文件读写的出错检测
ferror函数
调用形式:ferror(fp);
如果ferror返回值为0(假),表示未出错;如果返回值一个非0值,表示出错
clearerr函数
作用:使文件错误标志和文件结束标志置为0
假设在调用一个输入输出函数时出现错误,ferror函数值为一个非零值,应该立即调用clearerr(fp),使ferror(fp)的值变成0,以便再进行下一次检测。
第9章 用户自己建立数据类型
定义和使用结构体变量
自己建立结构体类型
C语言允许用户自己建立由不同类型数据组成的组合型的数据结构,称为结构体
结构体类型的一般形式
struct 结构体名 {成员表列};
对各个成员都应进行类型声明:类型名 成员名;
成员可以属于另一个结构体类型
定义结构体类型变量
1.先声明结构体类型,再定义该类型的变量
2.在声明类型的同时定义变量
struct 结构体名 { 成员表列 }变量名表列;
3.不指定类型名而直接定义结构体类型变量
struct {成员表列} 变量名表列;
结构体变量的初始化和引用
1.在定义结构体变量时可以对它的成员初始化
注意:是对结构体变量初始化,而不是对结构类型初始化
2.可以引用结构体变量中成员的值
引用方式:结构体变量名.成员名
“.”是成员运算符()在所以运算符中优先级最高
注意:不能企图输出结构体变量名来达到输出结构体变量所有成员的值
3.如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低一级的成员。
4.对结构体变量的成员可以像普通变量一样进行各种运算
5.同类的结构体变量可以相互赋值
6.可以引用结构体变量成员的地址,也可以引用结构体变量的地址
使用结构体数组
定义:一个结构体变量中可以存放一组有关联的数据,这就是结构体数组
结构体数组与数值型数组的区别:每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员项
定义结构体数组
一般形式:
1.struct 结构体名 {成员表列} 数组名[数组长度]={}初值表列};
2.先声明一个结构体类型,然后再用此类型定义结构体数据:
2.struct 结构体名 {成员表列}; struct 结构体名 数组名[数组长度]={初值表列};
对结构体数组初始化的形式是在定义数组的后面加上:={初值表列}
结构体指针
所谓结构体变量的指针就是指向结构体变量的指针,一个结构体变量的起始地址就是这结构体变量的指针
指向结构体变量的指针
指向结构体对象的指针变量既可指向结构体变量,也可指向结构体数组中的元素。
指针变量的基类型必须与结构体变量的类型相同
为了使用方便和直观,C语言允许把(*p).num用p->num来代替
如果指针变量p指向一个结构体变量stu,以下3种用法等价
1.stu.成员名(如stu.num)
2.(*p).成员名(如(*p).num)
3.p->成员名(如p->num)
指向结构体数组的指针
可以用指针变量指向结构体数组元素
如果p的初值为stu,即指向stu的第一个元素,p加一后,p就指向下一个元素。
程序定义了p是一个指向struct Student类型对象的指针对象,它用来指向一个struct Student类型的对象,不应用来指向stu数组元素中的某一成员
用结构体变量和结构体变量的指针作函数的参数
将一个结构体变量的值传递给另一个函数的方法
1.用结构体变量的成员做参数
2.用结构体变量作实参
3.用指向结构体变量(或数值元素)的指针作实参,将结构体变量(或数组元素)的地址传给形参
用指针处理链表
什么是链表
链表是一种动态地进行存储分配的一种结构
链表有一个“头指针”变量以head表示,它存放一个地址,该地址指向一个元素
如果不提供“头指针”(head),则整个链表都无法访问
链表中每个元素称为“结点”,它包括
用户需要用的实际数据
下一个结点的地址
最后一个元素不再指向其他元素,称为"表尾"它的地址部分存放一个"NULL"(表示“空地址”),链表到此结束
静态链表
所有结点都是在程序中定义的,不是临时开辟的,也不能用完后释放,这种链表称为“静态链表”
动态链表
所谓建立动态链表是指在执行过程中从无到有地建立起一个链表,即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系
输出链表
共用体类型
什么是共用体类型
使几个不同的变量共享同一段内存的结构,称为“共用体”类型的结构
一般形式
union 共用体名 {成员表列 }变量表列;
共用体变量所占的内存长度等于最长的成员的长度
引用共用体变量的方式
不能引用共用体变量,而只能引用共用体变量中的成员
printf("%d",a.i);或printf("%c",a.ch);
共用体类型数据的特点
同一内存段可以用来存放几种不同类型的成员,但在每一个瞬间只能存放其中一个成员,而不是同时存放几个
可以对共用体变量初始化,但初始化表中只能有一个常量
共用体变量中起作用的成员是最后一次被赋值的成员,在对共用体变量的一个成员赋值后,原来有变量存储单元中的值就取代
共用体变量的地址和它的各成员的地址都是同一地址
不能对共用体变量名赋值,也不能企图引用变量名来得到一个值
共用体类型可以出现在结构体类型定义中,也可以定义共用体数组
使用枚举类型
如果一个变量只有几种可能的值,则可以定义为枚举类型
声明枚举类型用enum开头
例:enum Weekday{sun,mon,tue,wed,thu,fri,sat};
定义:enum Weekday workday,weekend;
workday,weekend定义为枚举变量
sun,mon,称为枚举元素或枚举常量
声明枚举类型的一般形式
enum[枚举名]{枚举元素列表};
说明
c编译器对枚举类型的枚举元素按常量处理,故称为枚举常量。不能对它们赋值
每个枚举元素都代表一个整数,c语言编译按定义时的顺序默认它们的值为0,1,2,3,4...
枚举常量可以引用和输出,也可以人为地指定枚举元素的数值,在定义枚举类型时显式地指定
枚举元素可以用来作判断比较
用typedef声明新类型名
简单的用一个新的类型名代替原有的类型名
例如:typedef int Integer;//指定用Integer为类型名,作用与int相同
命名一个简单的类型名代替复杂的类型表示方法
第八章指针
1.指针概念
存储单元的地址
直接访问
直接按变量名进行访问
间接访问
将变量i的地址存放在另一个变量中,然后通过该变量来找到变量i的地址,从而访问i变量
指针
一个变量的地址称为该变量的指针(地址)
指针变量
如果有一个变量专门用来存放另一个变量的地址(存放地址的变量)
2.指针变量
定义指针变量
类型名 *指针变量名
char/int/float)/ *pointer-1,*pointer-2;
"*"表示该变量的类型为指针型变量
此处类型名是指指针指向的单元中的数据类型--基类型
不同类型的数据在内存中所占的字节数和存放方式是不同的
变量的指针的含义
以存储单元编号表示的地址(如编号为2000的字节)
它指向的存储单元的数据类型(如int,char,float)
指针类型表示
int*——指向int的指针或简称int指针
指针变量中只能存放地址(指针),不要将一个整数赋给一个指针变量
*pointer_1=100;//不合法
引用指针变量
1.给指针变量赋值(p=&a;)
2.引用指针变量指向的变量(p=&a;*p=1;//把1赋给a)
3.引用指针变量的值(printf("%o",p);//八进制形式输出p的值即&a,a的地址))
运算符
& 取地址运算符
* 指针运算符(间接访问运算符)
指针变量作为函数参数
作用:将一个变量的地址传送到另一个函数中
3.指针引用数组
数组元素的指针
p=&a[0];//p的值是a[0]的地址
p=a;//p的值是数组a首元素(即a[0])的地址
等价
指针的运算
只有指针指向数组元素能运算
运算
加一个整数,p+1
实际地址是:p+1xd,d是一个数组元素所占字节数
减一个整数,p-1
自加运算,p++
自减运算,p--
两个指针相减,p1-p2(只有p1和p2都指向同数组元素有意义)没有两个指针相加
指针引用数组元素
下标法
a[i]
指针法
*(a+i)或*(p+i)
数组名做函数参数
array是实参数组名
该数组首元素的地址
arr为形参数组名(vc++占4个字节)
用来接收从实参传递过来的数组首元素地址的
以实变量和数组名作为函数参数的比较
改变数组中的元素的值(p241)
1.形参与实参都用数组名
2.实参用数组名,形参用指针变量
3.实参形参都用指针变量
4.实参为指针变量,形参为数组名
指针引用多维数组
多维数组元素的地址
a[i]和*(a+i)等价
二维数组a的有关指针
指向多维数组元素的指针变量
指向数组元素的指针变量
指向由m个元素组成的一维数组的指针变量
int a[4];
a有4个元素,每个元素都为整型
int (*p)[4];
表示(*p)有4个元素,每个元素都为整数。
p只能指向一个包含4个元素的一堆数组,不能指向一维数组中的某一元素
p的值就是该一维数组的起始地址
用指向数组的指针作函数参数
用指向变量的指针变量
用指向一维数组的指针变量
4.指字符串针引用
字符串的引用方式
用字符数组存放一个字符串
通过数组名和下标引用字符串中的一个字符
通过数组名和格式声明“%s”输出该字符串
用字符指针变量指向一个字符串常量
通过字符指针变量引用字符串常量
字符指针作函数参数
字符数组名作参数
字符指针变量作参数
用字符指针变量作实参
用字符指针变量作形参和实参
使用字符指针变量和字符数组比较
相同点
都能实现字符串的存储和运算
不同点
1.存放形式
字符数组由若干个元素组成,每个元素中放一个字符
字符指针变量中存放的是地址(字符串第一个字符的地址)
2.赋值方式
可以对字符指针变量赋值
不能对数组名赋值
3.初始化的含义
数组可以在定义时对各元素赋初值,但不能用赋值语句对字符数组中全部元素整体赋值
4.存储单元的内容
编译时为字符数组分配若干存储单元,以存放各元素的值
对字符指针变量,只分配一个存储单元(vc++为指针变量分配4个字节)
5.值是否可变
指针变量的值是可以改变的
数组名代表一个固定的值(数组首元素的地址),不能改变
6.元素的值是否改变
字符数组中各元素的值是可以改变的(可以对它们再赋值)
字符指针变量指向的字符串常量中的内容是不可以被取代的(不能对他们再赋值)
7.引用数组元素
对字符数组可以用下标法(a[5])和地址法(*(a+5))引用数组元素
指针变量没有指向数组,则无法用下标法和地址法引用数组
8.指针变量代替内容
用指针变量指向一个格式字符串,可以用它代替printf函数(可变格式输出函数)中的格式字符串
使用字符数组时,只能采用在定义数组时初始化或逐个对元素赋值的方法,而不能用赋值语句对数组整体赋值
5.指向函数的指针
函数指针
如果在程序中定义了一个函数,在编译时,编译系统为函数代码分配一段内存空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针
函数指针变量调用函数
通过函数名调用函数
通过指针变量访问它所指向的函数
定义和使用指向函数的指针变量
形式
类型名(*指针变量名)(函数参数表列);
int(*p)(int,int);
说明和要求
1.定义指向函数的指针变量,并不意味着这个指针变量可以指向任何函数,它只能指向在定义时指定的类型的函数。
2.如果要用指针调用函数,必须先使指针变量指向该函数(p=max;//把max函数的入口地址赋给指针变量p)
3.在给函数指针变量赋值时,只须给出函数名而不必给出参数
p=max;//将函数入口地址赋给p
p=max(a,b);//将调用max函数所得到的函数值赋给p
4.用函数指针变量调用函数时,只须将(*p)代替函数名即可,在(*p)之后的括号中根据需要写上实参//注意函数返回值
c=(*p)(a,b);//表示“调用由p指向的函数,实参为a,b。得到的函数值赋给c”
5.对指向函数的指针变量不能进行算术运算
6.通过指针变量调用函数比较灵活,可以根据不同情况先后调用不同的函数
用指向函数的指针作函数参数
指向函数的指针变量的一个重要用途是把函数的地址作为参数传递到其他函数
指向函数的指针可以作为函数参数,把函数的入口地址传递给形参,这样就能够在被调用的函数中使用实参函数。
6.返回指针值的函数
int*a(int x,int y);
()优先级高于*,因此a先与()结合,显然这是函数形式
定义返回指针值的函数的一般形式
类型名 *函数名(参数列表);
7.指针数组和多重指针
什么是指针数组
一个数组,若其元素均为指针类型数据,称为指针数组
int *p[4];
[]比*优先级高,形成p[4]数组形式
*表示此数组是指针类型的,每个数组元素都可指向一个整型变量
定义一维指针数组的一般类型
类型名 * 数组名[数组长度];
用途
指向若干字符串,使字符串处理更加方便灵活
指向指针数据的指针
指向指针数据的指针变量
char**p;
*运算符的结合性是从右往左
*p表示p是指针变量//前面的char*表示p指向的是char*型的数据
指针数组作main函数的形参
8.动态内存分配与指向它的指针变量
内存动态分配
非静态的局部变量是分配在内存中的动态存储区,这个存储区是一个称为栈(stack)的区域
数据临时存放在一个特别的自由存储区,称为堆(heap)区
建立内存的动态分配
1.使用malloc函数
其函数原型为:void *malloc(unsigned int size);
其作用是在内存的动态存储区分配一个长度为size的连续空间,形参size的类型定为无符号整型
此函数的值(返回值)是所分配区域的第一个字节的地址
malloc(100);//开辟100字节的临时分配域,函数值为其第一个字节的地址
如果此函数未能成功地执行,则返回空指针(NULL)
2.使用calloc函数
其函数原型为:void *calloc(unsigned n,unsigned size);
其作用是在内存的动态存储区中分配n个长度为size的连续空间,这个空间一般比较大,足以保存一个数组
函数返回指向所分配域的起始位置的指针
p=calloc(50,4);//开辟50x4个字节的临时分配域,把起始地址赋给指针变量p
如果此函数未能成功地执行,则返回空指针(NULL)
3.使用free函数
其函数原型为:void free(void *p);
其作用是释放指针变量p所指向的动态空间,使这部分空间能重新被其他变量使用
p应是最近一次调用calloc或者malloc函数时得到的函数返回值
free(p);//释放指针变量p所指向的已分配的动态空间
free函数无返回值
4.使用realloc函数
其函数原型为:void *realloc(void *p, unsigned int size);
如果已经通过malloc函数或calloc函数获得了动态空间,想改变其大小,可以用realloc函数重新分配
用realloc函数将p所指向的动态空间的大小改变为size。p的值不变。
realloc(p,50);//将p所指向的已分配的动态空间改为50字节
无类型指针
不指向哪一种具体的类型数据,只表示用来指向一个抽象的类型的数据,即仅提供一个纯地址,而不能指向任何具体的对象
用这些函数时应当用“#include<stdlib.h>”指令把stdlib.h头文件包含在程序文件中
void指针类型
C99允许使用基类型为void的指针类型
第七章 函数实现模块化程序设计
定义函数
定义函数的方法
定义无参函数
函数名后面的括号是空地
一般形式为
定义有参函数
一般形式为
定义空函数
一般形式
作用:为将来准备扩充功能作准备
调用函数
一般形式:函数名(实参表列)
函数调用方式
函数调用语句
把函数调用单独作为一个语句。不要求函数带回值,只要求函数完成一定的操作:例:star();
函数表达式
函数调用出现在另一个表达式中,要求函数带回一个确定的值,以参加表达式的运算:c=2*max(a,b);
函数参数
函数调用作为另一个函数调用时的实参。:m=max(a,max(b,c));
如果调用无参函数,则“实参表列”可以没有,但括号不能省略 如果实参表列包含多个实参,则各参数间用逗号隔开
函数调用时的数据传递
形式参数和实际参数
在定义函数时函数名后面括号中的变量名称为“形式参数(形参)”或“”虚拟参数
在主调函数中调用一个函数时,函数名后面括号中的参数称为实际参数(实参)
实参和形参间的数据传递
在调用函数过程中,系统会把实参的值传递给被调用函数的形参。或者说,形参从实参得到一个值。该值在函数调用期间有效,可以参加该函数中的运算
在调用函数过程中发生的实参与形参间的数据传递,常称为“虚实结合”
函数调用的过程
1.在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元
2.将实参对应的值传递给形参
3.在执行max函数期间,由于形参已经有值,就可以利用形参进行有关的运算
4.通过return语句将函数值带回到主调函数
如果函数不需要返回值,则不需要return语句。这时函数的类型应定义为void类型
5.调用结束,形参单元被释放。注意:实参单元仍保留并维持原值,没有改变
注:实参向形参的数据传递是“值传递”,单向传递,只能由实参传递给形参,而不能由形参传给实参
函数的返回值
希望通过函数调用使主调函数能得到一个确定的值,这就是函数值
1.函数的返回值是通过函数中的return语句获得的
return语句将被调用函数中的一个确定值带回到主调函数中去
如果需要从被调用函数带回一个函数值,被调用函数中必须包含return语句
如果不需要从被调用函数带回函数值可以不要return语句
2.函数值的类型
在定义函数时要指定函数的类型
3.在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致
如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。即函数类型决定返回值的类型
对被调用函数的声明和函数原型
被调用函数的条件
1.首先被调用的函数必须是已经定义的函数(库函数或用户自己定义的函数)
2.如果使用库函数,应该在本头文件开头用#include指令将调用有关库函数时所需用到的信息“包含”到本文件中来
3.如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面(在同一文件中),应该在主调函数中对被调用的函数作声明
声明的作用:把函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法
函数的首行称为函数原型
函数声明的一般形式
1.函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2,...参数类型n 参数名n);
2.函数类型 函数名(参数类型1,参数类型2,...,参数类型n);
函数定义和函数声明
函数的定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型以及函数体等,它是一个完整的、独立的函数单位
函数的声明的作用则是把函数的名字、函数类型以及形参的类型、个数和顺序通知编译系统,以便在调用该函数时系统按此进行对照检查,它不包括函数体
函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用
数组作为函数参数
数组元素作函数实参
数组元素可以用作函数实参,不能用作形参
因为形参是在函数被调用时临时分配存储单元的,不可能为一个数组元素单独分配存储单元
在用数组元素作函数实参时,把实参的值传给形参,是‘值传递’方式。数据传递的方法是从实参传到形参,单向传递
数组名作函数参数
用数组元素作实参时,向形参变量传递的是数组元素的值,而用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素的地址
用数组名作函数实参时,不是把数组元素的值传递给形参,而是把实参数组的首元素的地址传递给形参数组,这样两个数组就共占同一段内存单元
形参数组中各元素的值如发生变化会使实参数组元素的值同时发生变化,与变量作函数参数的情况不同
多维数组名作函数参数
可以用多维数组名作为函数的实参和形参,在被调用函数中对形参数组定义时可以指定每一维的大小,也可以省略第一维的大小说明。不能把第二维以及其他高维的大小说明省略
局部变量和全局变量
局部变量(函数内定义)
1.在函数的开头定义
2.在函数内的复合语句内定义
3.在函数的外部定义
说明
1.主函数中定义的变量也只在主函数中有效,并不因为在主函数中定义而在整个文件或程序中有效。主函数也不能使用其他函数中定义的变量
2.不同函数中可以使用同名的变量,它们代表不同的对象,互不干扰
3.形式参数也是局部变量
4.在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效。
全局变量/外部变量(函数外定义)
全局变量可以为本文件中其他函数所共用,它的有效范围为从定义变量的位置开始到本源文件结束
作用:增加了函数间数据联系的渠道
将全局变量名的第一个字母用大写表示
建议在不必要时不要使用全局变量
1.全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元
2.降低了程序的可靠性和通用性
3.降低程序的清晰性
如果在同一源文件中,全局变量与局部变量同名时,在局部变量的作用范围内,局部变量有效,全局变量被屏蔽,即不起作用。
变量的存储方式和生存期
动态存储方式与静态存储方式
静态存储方式
在程序运行期间由系统分配固定的存储空间的方式
动态存储方式
在程序运行期间根据需要进行动态的分配存储空间的方式
数据在内存中的存储方式
内存中的供用户使用的存储空间
1.程序区
2.静态存储区
全局变量
在程序开头执行时给全局变量分配存储区,程序执行完毕就释放
3.动态存储区
1.函数形式参数。在调用函数时给形参分配存储空间
2.函数中定义的没有用关键字static声明的变量,即自动变量
3.函数调用时的现场保护和返回地址等
局部变量的存储类别
1.自动变量(auto变量)/动态存储区
在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间
关键字“auto”可以省略,不写auto则隐含指定为“自动存储类别”
2.静态局部变量(static局部变量)/静态存储区
函数中的局部变量的值在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次再调用该函数时,该变量已有值
说明
静态局部变量属于静态存储类别,在静态存储区内分配存储单元
对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已经有初值
如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符‘\0’(对字符变量)
虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的
3.寄存器变量(register变量)/cpu中的寄存器
将局部变量的值放在cpu中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。由于对寄存器的存取速度远高于对内存的存取速度,提高执行效率
全局变量的存储类别/静态存储区
在一个文件内扩展外部变量的作用域
如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件结束
在定义点之前的函数需要引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”,表示把该外部变量的作用域扩展到此位置
将外部变量的作用域扩展到其他文件
在任一个文件中定义外部变量,而在另一文件中用extern作“外部变量声明”,在编译和连接时,系统会由此知道外部变量有“外部链接”,可以从别处找到已定义的外部变量,并将在另一文件中定义的外部变量的作用域扩展到本文件
将外部变量的作用域限制在本文件中
static声明
对局部变量用static声明,把它分配在静态存储区,该变量在整个程序执行期间不释放,其所分配的空间始终存在
对全局变量用static声明,则该变量的作用域只限于本文件模块
加上static声明、只能用于本文件的外部变量称为静态外部变量
变量的声明和定义
把建立存储空间的声明称为定义
不需要建立存储空间的声明称为声明
在函数中出现的对变量的声明(除了extern声明的以外)都是定义 在函数中对其他函数的声明不是函数的定义
内部函数和外部函数
根据函数能否被其他源文件调用,分为内部函数和外部函数
内部函数/静态函数
一个文件只能被本文件中其他函数所调用
一般形式:static 类型名 函数名(形参表)
外部函数
在定义函数时,在函数首部的最左端加关键字extern,则此函数是外部函数
函数首部可以为:extern int fun (int a,int b)
如果在定义函数时省略extern,则默认为外部函数