1.程序设计和C语言
程序:就是一组计算机能识别和执行的指令。
低级语言
完全依赖具体机器特性,面向机器的语言,由于”贴近“计算机。 机器语言:能直接识别和接受的二进制代码称为机器机器指令。机器指令的集合称为该计算机的机器语言。 符号语言:计算机不能直接识别和执行符号语言的指令,需要用汇编程序把符号语言的指令转换为机器指令。又称汇编语言。
高级语言
与具体机器距离较远,故被称为计算机高级语言。 用编译程序把用高级语言写的程序(源程序)转换为机器指令的程序(目标程序),高级语言的一个语句往往对应多条机器指令
高级语言发展阶段
- 非结构化的语言。如早期BASIC,FORTRAN。
- 结构化语言
- 面向对象的语言
C语言特点
- 语言简洁、紧凑、使用方便、灵活。只有37个关键字,9种控制语句。 C语言不直接提供输入和输出语句、有关文件操作的语句和动态内存管理的语句等由编译系统提供的库函数来实现。
- 运算符丰富
- 数据类型丰富。
- 具体结构化的控制语句(if-else)、while、do-while
- 语法限制不太严格,程序设计自由度大。
- 允许直接访问物理内存,能进行位操作,能实现汇编语言的大部分功能,可以直接对硬件进行操作。
- 可移植性好。
- 生成目标代码质量高,程序执行效率高
C语言程序结构
- 一个程序由一个或多个源程序文件组成
预处理指令,全局声明,函数定义 - 函数是C程序的重要组成部分
- 一个函数包括两个部分
函数首部:函数名,函数类型,函数属性,参数,参数类型 函数体:声明部分,执行部分 - 程序总是从main函数开始执行,而不论main在程序中的位置如何
- 程序对计算机的操作由函数中的C语句完成的。
- 每个数据声明和语句的最后必须有一个分号
- C语言本身不提供输入输出语句
- 程序应当包含注释
运行C的步骤与方法
-
输入和编辑源程序 -
对源程序进行编译。先用预处理器对程序中的预处理指令进行编译预处理。由预处理得到的信息与程序其他部分一起,组成一个完整的、可以用来进行正式编译的源程序,然后由编译程序对该源程序进行编译。 当没有语法错误时,编译程序把源程序转换为二进制形式的目标程序。 编译时,自动包括预编译和正式编译,用户不必分别发出二次指令。 -
进行连接处理。一个程序可能包含若干个源程序文件,必须把所有的编译后得到的目标文件连接装配起来,再与库函数相连接成一个整体,生成可供计算机执行的目标程序,称为:可执行程序。 -
运行可执行程序
程序设计的任务
- 问题分析
- 设计算法
- 编写程序
- 对源程序进行编辑、编译和连接
- 运行程序,分析结果
- 编写程序文档
2.算法
一个程序主要包括以下两方面的信息:
- 对数据的描述。(数据结构)
- 对操作的描述。(算法)
沃思提出公式:
算
法
+
数
据
结
构
=
程
序
算法+数据结构=程序
算法+数据结构=程序 计算机算法分成两大类别:数值运算算法与非数值运算算法。
算法的特征
- 有穷性:有限个操作步骤
- 确定性:每一个步骤应当是确定的。
- 有零个或多个输入:
- 有一个或多个输出
- 有效性:每个步骤都应当能有效地执行,并得到确定的结果。
算法的表示方法
- 自然语言
- 流程图。ANSI规定一些常用的流程图符号。
三种基本结构与改进的流程图
BS(a bowl of noodle)算法的弊端:流程图毫无规律,如同乱麻。
基本结构
- 顺序结构
- 选择结构
- 循环结构
当型(while):如果条件成立则执行。 直到型(until):执行至条件成立。
共同特点: 只有一个出口,只有一个入口。结构内每一部分都有机会被执行。结构内不存在死循环。
N-S流程图
- 循环结构
2.选择结构 - 循环结构
伪代码
介于自然语言和计算机语言之间的文字和符号来描述算法。
计算机语言
必须严格遵循所用的语言的语法规则
结构化设计方法
- 自顶向下
- 逐步细化
- 模块化设计:低耦合,高内聚
- 结构化编码
3.顺序结构设计
数据存储形式
常量
在程序运行过程中,其值不能被改变的量称为常量。
- 整形常量
- 实型常量
十进制小数 指数形式(e或 E前必须有数字,且e或E以后必须为整数) - 字符常量
普通字符 转义字符 - 字符串常量:双撇号的括号中全部字符,不包括双撇号。
- 符号常量:用#define,指定用一个符号名称代表变量。优点:含义清楚,程序多处使用时只用修改一处。
符号常量不等于变量,不占用内存,只是临时符号,预编译后符号就不存在
变量
变量代表一个有名字、具有特定属性的一个存储单元。用来存放数据,存放变量的值。先定义再使用
常变量
C99允许使用。具有变量的基本属性,但不允许修改值, 常量是没有名字的不变量,常变量是有名字的不变量。
标识符
计算机高级语言中,用来对变量、符号常量名、函数、数组、类型等命名的有效字符序列。只能由字母、数字、下划线3种字符组成,且第一个字符必须为字母或下划线。
数据类型
数据存放在存储单元中。类型就是对数据分配存储单元的安排,包括存储单元的长度和存储类型。 基本类型和枚举类型统称算术类型。算术类型和指针类型统称纯量类型。 数组和和结构体统称组合类型。
整形
- 基本整形int。(2字节或4字节)
数值范围-32768~32767或
?
2
31
,
2
31
?
1
-2^{31},2^{31}-1
?231,231?1 - 短整型short int (2字节)
- 长整形long int(4字节)
- 双长整形long long int(8字节 C99支持)
in addition:不严格要求空间大小,但满足以下条件
s
i
z
e
o
f
(
s
h
o
r
t
)
≤
s
i
z
e
o
f
(
i
n
t
)
≤
s
i
z
e
o
f
(
l
o
n
g
)
≤
s
i
z
e
o
f
(
l
o
n
g
l
o
n
g
)
sizeof(short)\leq sizeof(int)\leq sizeof(long)\leq sizeof(long long)
sizeof(short)≤sizeof(int)≤sizeof(long)≤sizeof(longlong)
(符号) 数字取值范围 只有整形支持signed和unsigned修饰符,实型不支持 无符号用%u输出 默认有符号
字符型
- 字符与字符代码
ascii.1字节 wchar_t.在(C99 stddef.h)中,宽字符(2字节) - 字符变量
字符变量实际上是一个字节的整形变量。符号(signed)由编译器决定. 如果将一个负整数赋给符号字符变量是合法的,但不代表一个字符,而作为已字节整形变量存储负整数。
浮点型
由于小数点位置可以浮动,所以实数的指数形式称为浮点数
- float型(4字节)
部分编译系统以24位表示小数部分,以8位表示(指数部分,包括指数的符号) - double型(8字节)
- long double (Turbo 16字节 VC++ 8字节)
有限的单元不可能完全精确存储实数,如float不能表示
1
0
?
40
10^{-40}
10?40 有的C编译器把所有实数作为double来处理,当以float变量存储时会警告。
常量类型确定
整形常量需注意有效范围。在一个整数末尾加L或l表长整型。 浮点型常量 以小数或指数形式出现的实数,是浮点型常量。 C程序中实型常量都是double常量 可以在常量末尾加专用字符,强制指定常量类型。
float a=3.14f; //float型
long double a=3.14L //long double处理
类型是变量的共性、抽象,不占用存储单元、不能用来存放数据
运算符
算术运算符
- 整数相除结果为负数时多数编译系统向零取整数
- %要求操作数为整数
- 自增自减只用于变量,不用于常量
- 注意运算符结合优先级
混合运算
- 运算中有一个是float或double,结果为double
- int与float或double型计算,结果为double
- 字符与整形计算,结果为整形,字符与double计算,结果为double
运算符
C语句
语句分类:
- 控制语句:9种
- if else
- for
- while
- do while
- continue
- break
- switch
- return
- goto
- 函数调用
- 表达式语句:一个表达式+分号
- 空语句:作为流程的转向点或循环语句的循环体
- 复合语句{}把语句和声明括起来称为复合语句
赋值语句
赋值表达式: 变量 赋值运算符 表达式 左值都可以作为右值 类型转换:
f
l
o
a
t
→
i
n
t
对
浮
点
数
取
整
后
赋
值
float\rightarrow int 对浮点数取整后赋值
float→int对浮点数取整后赋值
i
n
t
→
f
l
o
a
t
、
d
o
u
b
l
e
数
值
不
变
,
转
换
成
实
型
int\rightarrow float、double 数值不变,转换成实型
int→float、double数值不变,转换成实型
d
o
u
b
l
e
→
f
l
o
a
t
将
双
精
度
转
换
为
单
精
度
,
只
取
6
到
7
位
有
效
数
字
,
且
不
能
超
过
f
l
o
a
t
范
围
,
否
则
报
错
double\rightarrow float 将双精度转换为单精度,只取6到7位有效数字,且不能超过float范围,否则报错
double→float将双精度转换为单精度,只取6到7位有效数字,且不能超过float范围,否则报错
c
h
a
r
→
i
n
t
则
a
s
c
i
i
值
赋
给
变
量
char\rightarrow int 则ascii值赋给变量
char→int则ascii值赋给变量 将多字节整形数据赋给占字节少的整形变量或字符变量,将低字节原封不动赋给变量 注意:赋值表达式没有分号,赋值语句结尾有分号。赋值表达式可包含一个或多个赋值表达式,但不能包含赋值语句。 一般变量初始化不是在编译阶段完成的(除静态存储变量和外部变量初始化),而是在程序运行时执行时赋值。
数据IO
概念:
- 输入输出以计算机主机为主体而言
- C本身不提供输入输出语句:各种C编译系统提供的系统函数库是各软件公司编制的,包括C建议的全部标准函数,还根据用户需要补充一些常用函数,已对其进行编译,成为目标文件。在连接阶段与源文件编译后的目标文件相连接,生成可执行文件
- 使用系统库函数,要在程序文件的开头用预处理指令#include把头文件放在本程序中。在程序进行预编译时,系统将头文件的内容调出来放在此位置,取代本行#include指令。
说明: <>(标准方式),从存放C编译系统的子目录去找包含的文件 “”编译系统先在源程序文件的子目录中寻找包含的文件,若找不到,则按标准方式找。
printf函数
一般格式 printf(格式控制,输出列表) 格式控制:(转换控制字符串)简称格式控制字符串。包含格式声明(由‘%’和格式字符组成),普通字符(原样输出)。 输出列表:可以是常量、变量、表达式
格式字符
- d格式符输出一个有符号的十进制整数。在格式声明中指定输出数据的域宽。输出的数据显示在域宽内右侧,更有ld、lld输出long、long long。
- c格式符输出一个字符。如果整数比较大,则把最后一个字节的信息以字符形式输出。
int a=378; printf("%c",a);//输出z - s格式符,输出字符串
- f格式符,输出实数(单、双、长双),小数形式。
- 基本型:不指定数据长度,由系统根据数据的实际情况决定所占列宽。
- 指定数据宽度和小数位数。用%m.nf
如%7.2f表数据占7位,小数部分四舍五入保留两位,加上小数点总共7位。如果小数部分指定位0,不输出小数以及小数点。用%f输出时要注意数据本身能提供的有效数字。 -输出的数据向左对齐%-m.nf 当数据长度不超过m时,数据向左靠,右端补空格。
- e(E)格式符,%e以指数形式输出实数。如果不指定数据所占宽度和数据部分的小数部分,许多编译器会自动给出数字部分的小数位数为6位,指数部分占5位。数值按标准化指数形式输出
用%m.ne输出。若用大写则用大写表示 如printf("%10.2e",123.456); 输出_1.23e+002,_代表空格
- i格式符
作用与d格式符相同 - o格式符
以将内存中的(0,1包括符号位)八进制输出 -x格式符 十六进制输出,可用lx输出长整型,也可以指定域宽 - u格式符
输出无符号数据,以十进制证书输出 - g格式符
用来输出浮点数,系统自动选f或e中较短的格式
说明: 6. 输出对象类型应与格式说明匹配,否则出错 7. 只有X,E,G支持大小写 8. %%输出%
scanf函数
一般形式 scanf(格式控制,地址列表) 地址列表:变量的的地址,字符串的首地址
格式声明
与printf类似 注意:
- 变量地址不能写成变量名
- 格式控制字符串如果还有其他字符,则必须在对应位置输入相应字符
- 用%c时空格和转义字符中的字符都为有效字符输入
- 在输入数值数据时,如输入回车,空格、Tab或非法字符则认为该数据结束
字符输入输出
- putchar(c)
输出字符c,c可以是字符常量、变量,整形常量、变量。在ASCII范围内。 - getchar()
从计算机中断获得一个字符。不仅能获得一个显示的字符,而且可以获得在屏幕上无法显示的字符、如控制字符。
4.选择结构
关系运算符和关系表达式
说明:关系运算符优先级低于算术运算符,高于赋值运算符。
关系表达式:
用关系运算符将两个数值或数值表达式连接起来的式子。 关系表达式的是一个逻辑值,“1”表真,“0”表假。
逻辑运算表达式:
用逻辑运算符将关系表达式或其他逻辑量连接起来的式子就是逻辑表达式
- && 与
- ||或
- !非
优先级: 注意:在判断一个量是否为“真”时,非0代表真,0代表假。逻辑运算结果只有0,1.而逻辑表达式中逻辑运算的运算对象可以是0或任何非0数值,实际上,逻辑运算符两次的运算对象不但可以是整数,也可以是字符型、浮点型、枚举型、指针型。最终以0和非0判断。 在逻辑表达式求解可能发生“短路”。
逻辑型变量
C99新增_Bool,在头文件stdbool.h中
条件运算符和条件表达式
表达式1?表达式2:表达式3 如果表达式1为真,则执行表达式2,否则为表达式3. 优先级高于赋值运算,比关系运算符和算术运算符低。 如: max=(a>b)?a:b;等价max=(a>b)?a:b; a>b?a:b+1等价a>b?a:(b+1) (a>b?max=a:max=b)
≠
\neq
?=(a>b?(max=a):(max=b))
if语句
一般形式: if (表达式) 语句1 [else 语句2] 常用形式
- if(表达式) 语句
- if (表达式) 语句1
else 语句2 - if(表达式1) 语句1
else if(表达式2) 语句2 else if… else …
嵌套
if()
if()
else
else
if()
else
else必须与最近的if配对,不能单独使用
switch语句
一般形式: switch(表达式) { case 常量1:语句1 case 常量2:语句2 case 常量3:语句3 case 常量n:语句n default: 语句n+1 } 注意:
- 表达式值类型为整数类型(或字符型)
- 语句体内包括多个以关键字case开头的语句行和最多以一个以default开头的行。case后为常量或常量表达式。和defalut都起标号作用。
- 如果default标号,且没有与switch表达式相匹配的case常量,则不执行任何语句。
- case标号出现次序不影响执行结果,可先出现Default
- 每个case常量必须不同
- case标号只起标记坐拥,如果找到标记入口,则会一直执行下去,不再判断。
- case子句可包含一个以上花括号且不必用{}
- 多个case标号可共用一组执行语句
5.循环结构
while
一般形式如下: while(表达式) 语句 判断表达式为真则执行
do—while
一般形式如下: do 语句 while(表达式); 先无条件执行循环体,在判断条件是否成立
for
一般形式如下: for(表达式1;表达式2;表达式3) 语句 设置初值 循环条件 循环调整 注意:
- 表达式1可省略,但分号不可省略
- 表达式2省略代表无尽循环
- 表达式3省略,应在循环体内补充循环调整,保证循环结束
- 三个表达式都可省略
- 表达式1可以对非循环变量的表达式
- 表达式1、3可以是简单表达式也可以是逗号表达式(自左到右求解,表达式的值为最右边表达式的值)
- C99允许在表达式1定义变量并赋值
改变循环状态
break 退出当前循环 continue 跳过本次循环,进行下一次(循环体之后的部分不做,如果循环变量未改变,可能引起死循环)
6.数组
- 数组是一组有序数据的集合
- 用一个数组名和下标确定数组中的元素
- 每一个元素都属于同一个数据类型
一维数组
定义一维数组一般形式
类型符 数组名[常量表达式]
- 命名规则与变量名相同,遵循标识符命名规则
- 需要指定数组长度
- 常量表达式可以包含常量和符号常量,不能包含变量。C语言不允许对数组大小作动态定义(C99貌似可以),如果在被调用的(非主)函数定义数组,其长度可以是变量或非常量表达式。如果指定数组为静态存储方式,则不能用可变长数组。
引用形式
数组名[下标]
初始化
- 定义时全部赋初值
- 只给一部分赋初值,其余赋值为0(int:0,char:\0,*:NULL)
- 给一个int数组赋值0只用给1个赋0
- 对全部元素赋初值可不指定数组长度。
二维数组
定义一维数组一般形式
类型符 数组名[常量表达式][常量表达式] 注意: 内存中各个元素是连续存放,是线性的不是二维的。
引用形式
数组名[下标][下标]
初始化
- 定义时全部赋初值,用{}代表一行的数据,也可以不用,按排列顺序赋初值
- 只给一部分赋初值,用{}代表一行,其余赋值为0(int:0,char:\0,*:NULL)
- 对全部元素赋初值可不指定数组一维长度,但要指定二维长度。
字符数组
与一位数组相似的地方不再赘述 在定义字符数组不进行初始化,则数组中各元素的值是不可预测的。 C语言中,字符串以字符数组来处理。字符串结束标记‘\0’之前代表有效字符。 补充初始化方法
char str=[]="abcd"; \\长度为5,默认添加\0
printf在遇到\0则会停止输出
字符数组IO
- 逐个输入输出
- 将整个字符串一次输入或输出
- 输出不包括\0
- 用scanf直接输入字符串末尾自动补\0,此时参数只用数组名,不需要加&
使用字符串处理函数
一般形式 puts(字符数组) 输出字符串,可以包含转义字符,并且\0转换成\n,输出完字符串后换行。 gets(字符数组) 从中断输入字符串到字符数组,并得到字符数组起始地址的返回值 puts和gets只能输入一个字符 strcat(字符数组1,字符数组2) 把字符串2接到字符串1后面,返回值为字符数组1的起始地址 字符数组1的空间必须足够大,连接时将字符数组1的\0取消只在新串最后保留\0 strcpy(字符数组1,字符数组2) 将字符数组2的内容复制到字符数组1当中 字符数组1的长度大于等于字符数组2。 字符数组1必须是数组名形式,字符串2可以是字符数组名,也可以是字符串常量。 未赋值前str1内容无法预知,在复制后,超过str2的内容保留不变(也未知)。 字符数组不能直接赋值 strncpy(字符数组1,字符数组2,n) 字符串2前n个字符复制到字符串1,取代前n个,但不应超过字符串1原有长度(实际上超过了)
strcmp(字符数组1,字符数组2) 从左至右逐个字符比较,直到出现不同字符或\0为止 如果全部字符相同,则字符串相等。 如果不同,则以第一对不同字符为准 s1==s2 return 0 s1>s2 return s1[i]-s2[i] (>0) s1<s2 return s1[i]-s2[i] (<0) strlen(字符数组) 返回值为字符串的实际长度,不包括\0 strlwr(字符数组)和strupr(字符数组) 将大写转成大写,反之。 在使用字符串处理函数时,在程序文件开头#include<string.h>
7函数
如果把所有程序代码卸载一个main函数中,,会使得主函数变得庞杂、头绪不清、使阅读和维护程序变得困难。 通过模块化程序设计的思路,将功能拆解成函数。在设计一个较大程序时,往往把他分为若干个程序模块,每一个模块包括一个或多个函数,每个函数实现一个特定的功能。一个C程序可由一个主函数和若干个其他函数构成。 一个或多个程序模块组成源程序。 一个源程序文件由一个或多个函数以及其他有关文件组成。 在main函数中调用,之后返回到main函数,在main函数中结束整个程序运行。 函数不能嵌套定义 函数从用户角度来看:
- 库函数,由系统提供的,用户不必自己定义,可直接使用。
- 用户自己定义的函数。解决用户专门需要的函数
从函数形式看: 无参函数 有参函数
函数定义
需定义 1、函数名 2、返回值类型 3、指令参数名参数类型4、指定应当完成什么操作,函数体
定义函数方法
- 无参函数
类型名 函数名 () { 函数体 } - 有参函数
类型名 函数名(形参表) { 函数体 } - 空函数
类型名 函数名(形参表) { 函数体 }
函数声明: 当调用函数时,若函数在调用位置之后定义,则需要添加函数声明。函数的首行称为函数原型。函数的定义是指对函数功能的确立,是完整的函数单位。函数声明只是把函数原型所需参数通知编译系统,以便在调用时进行对照检查,不包括函数体。
调用函数
函数名(实参表)
- 函数调用语句
单独调用作为语句 - 函数表达式
函数调用出现是语句的一部分,如赋值语句 - 函数参数
函数返回值可以作为参数,再调用。
实参与形参
在定义函数时函数名后面括号中的变量名称为形参,调用时括号中的参数为实参。 在调用时,系统会把实参的值传递给调用函数的形参,“虚实结合”。未调用时,形参并不占内存中的存储单元,在调用时,形参被分配内存单元。在调用结束后,实参仍然保留并维持原值,没有改变。 注意: 实参可以是常量、变量或表达式,但要有确定的值,在调用时将实参的值赋给形参。 实参与形参的类型应相同或符合,如果不符合则会进行转换。 实参向形参传值是单向传递
返回值
函数的返回值通过函数中的return语句获得。 如果返回值与函数类型不一致,则以函数类型为准
递归
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。 例如
void hanoi(int n,char one,char two,char three)
{
if(n==1)
move(one,three);
else
{
hanoi(n-1,one,three,two)
move(one,three);
hanoi(n-1,two,one,three);
}
}
数组作为参数
数组元素作参数
数组可以用作实参、不能用作形参。在数组元素作为函数参数时,把实参的值传给形参,是值传递的方式。
数组名作参数
用数组元素作实参时,向形参变量传递的是数组元素的值,而用数组名作函数实参时,向形参传递的数组首元素的地址。 函数形参在定义时,声明数组大小不起任何作用。在调用时,只将实参数组的首元素地址传给形参数组名。在定义时,可跟一个空的方括号。
多维数组
可以指定一维的大小,也可以省略一位的大小说明。二维数组,在内存中,数组是按行存放。不能指定第1维而省略第2维。
局部变量
- 函数的开头定义
- 函数内复合语句内定义
- 在函数的外部定义
全局变量
在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量。外部变量是全局变量(也称全程变量) 说明: 全局变量的作用是增加了函数见数据联系的渠道。 全局变量在全部执行过程中都占用存储单元,而不是在需要时才开辟。 函数的通用性降低。模块的功能要单一。 会降低程序的清晰性。 如果在同一文件中,全局变量与部分变量同盟,在局部变量的作用范围内,局部变量有效,全局变量被"屏蔽"
变量存储方式和生存期
每一个变量和函数都有两个属性:数据类型和数据的存储类别 存储空间分区:
- 程序区
- 静态存储区
- 动态存储区
静态存储方式
全局变量全部存放在静态存储区。
动态存储区
- 函数形参。在调用时给形参分配空间
- 函数中定义的没有static声明的变量。
- 函数调用的现场保护和返回地址
局部变量存储类别
- 自动变量auto
不专门声明为static存储类别,都是动态地分配存储空间,数据存储在动态存储区。函数的形参和函数中定义的局部变量。 - 静态局部变量static
有时希望函数中的局部变量的值在函数调用结束后不消失而继续保留原值,即占用存储单元不释放。 在静态存储区分配存储单元 对静态局部变量在编译时赋初值而只是保留上次函数调用结束时的值。 如果在定义局部变量时不赋初值,对静态变量来说,自动赋初值为0或\0 静态局部函数调用结束后仍然存在,但其他函数不能引用。 - 寄存器变量register
一般情形下,变量的值是存放在内存中。有一些频繁使用的即便存放到寄存器中。
全局变量的存储类别
全局变量都是存放在静态存储区中的。因此它们的生存期是固定的,存在于程序的整个运行过程。 一般来说,外部变量实在函数的外部定义的全局变量,作用域从变量的定义出开始,到本程序文件的末尾。
- 在一个文件内扩展外部变量的作用域
extern对该变量作外部变量声明。 将外部变量定义放在引用它的所有函数之前,这样可以避免在多加一个extern声明。 在声明外部变量时,类型名可以写也可以省略。
extern int A,B,C;
extern A,B,C;
- 外部变量的作用域扩展到其他文件
如果一个程序包含两个文件,在两个文件都要用同一个值,如果分别定义则会出现重复定义错误。为解决此问题:在任一个文件中定义外部变量,另一个文件用extern作外部声明 用这样方法扩展全局变量的作用域应该慎重,对于一个文件中改变该值,从而影响函数的执行结果 在遇到extern时,先在本文件找到外部变量的定义,如果找到,就在在本文件中扩展作用域;如果找不到,就在连接时从其他文件找到其他文件找外部变量的定义,如果从其他找到,就将作用域扩展到本文件,如果找不到,就按出错处理。 - 将外部变量的作用域限制在本文件。如果在程序设计中希望某些外部变量只限于本文件引用,而不能被其他文件引用。
在全局变量加上static声明。只能用于本文件的外部变量称为静态外部变量。 声明局部变量的存储类型和声明全局变量的存储类型的含义不同,对局部变量来说,声明存储类型的作用是指定存储的区域以及由此产生的生存期问题。而全局变量在编译时分配内存,存放在静态存储区 - 对于局部变量static声明,分配在静态存储区。
对于全局变量用static声明,则该变量的作用域只局限于本文件模块。 auto,register,static都是在定义时加上关键字的,而不能单独使用 如果一个变量在某个文件或函数范围内是有效的,则称该范围时该变量的作用域,在此作用域可见。如果某一时刻变量存在,则这一刻称为生存期
变量的定义与声明
- 需要存储空间,称为定义性声明,简称定义。
- 不需要存储空间,称为引用性声明,简称引用。如extern
把建立存储空间的声明称定义,把不需要建立存储空间的声明称为声明。
内部函数和外部函数
只能在本文仅中其他函数所调用称为内部函数(静态函数)。 static 类型名 函数名(形参表); 如果定义函数时,在首部的最左端加关键字extern,则函数时外部函数。可悲其他文件调用。C语言规定,函数默认是外部函数。 在调用此函数的其他文件中,需要对此函数作声明。 在对此函数声明时,要加关键字extern(允许省略)
8.指针
没有提纲。。 详细请看
9.自定义数据类型
结构体
结构体类型的一般形式为 struct 结构体名 {成员列表}; 成员列表形式 类型名 成员名; 计算机对内存的管理以"字"为单位(某些计算机以4个字节为一个字),如果结构体的内存不是"字"的整数倍,下一个数据会从下一个字开始。 定义变量方式
- 先声明结构体类型,再定义变量
- 在声明结构体的同时定义变量
struct 结构体名 {成员列表}变量名列表; - 不指定类型名而直接定义结构体类型变量
struct {成员列表}变量名列表; 对变量分配空间,对结构体本身不分配空间。 结构体的成员名可以与程序中的变量名相同。
初始化和引用
- 在定义结构体变量时可以对其成员初始化。
C99允许对某一成员初始化。struct stu a={.name=“123”;}其他未指定初始化的数值型成员倍系统初始化为0,字符成员被初始化为\0,指针被初始化NULL - 结构体变量名.成员名,对成员进行引用。如果成员也是结构体,则要一级一级引用。对结构体变量的成员可以像普通变量一样进行各种运算。
- 同类型的结构体可以相互赋值,可以引用成员地址,也可以引用结构体变量的地址(主要用作参数)
结构体数组、指针
一般形式: 1. struct 结构体名{成员列表} 数组名[数组长度]; 2. 先声明结构体类型,后定义数组。 3. 指针定义形式与基本数据类型相同。(*p).num访问成员,括号不能省略。==. == 的优先级高于*.可用->代表(*p). 程序定义p是一个指向结构体的变量,如果用来指向某一成员赋值给它就会报错,但用强势类型转换可以实现特定功能,因为指针自增一个结构体长度
struct Stu{
int id;
int name;
}stu[10];
Stu *p=(Stu*)stu[0].id;
p++; //此时p++后,p指向stu[1].id;
链表
包含两个部分
- 用户需要用到数据。
- 下一个结点的地址。
静态链表:所有结点都是在程序中定义的,不是临时开辟的,也不能用完后释放。 动态链表:一个个开辟结点和输入各结点数据。并建立前后相链接的关系。
共用体
定义共用体的一般形式为union 共用体名字{成员列表}变量列表; 共用体变量所占长度等于最长的成员的长度。 只用定义了共用体变量才能引用它,但注意,不能引用共用体变量,而只能引用共用体变量的成员。 特点
- 同一内存段可以存放几种不同类型的成员,但在每一瞬间只能存放其中一个成员。而不是同时存放几个。可以对共用体初始化,但只能有一个常量。起作用的是最后一个赋值的值。
- 共用体变量的地址和它各成员地址都是同一个。
- 不能对共用体变量名赋值,不能引用变量名获得值。(C99允许同类型赋值,可以作函数参数)
union D{
int i;
char c;
float f;
}a;
int main()
{
a.i=97;
printf("%d\n",a); //97
printf("%c\n",a);//a
printf("%f",a);//0.000000
return 0;
}
枚举类型
enum [类型名]{枚举元素列表}; 枚举元素按常量处理,称枚举常量。(不可赋值)。默认值为0…递增。也能人为指定 如enum exp{a=5,b=1,c,d,e}; b之后递增。 由于枚举型变量的值是整数,因此C99把枚举类型作为整形数据中的一种。 枚举元素可以用来比较。
typedef用法
- 定义别名
typedef 原名 新名 - 复杂类型别名
用法 命名结构体 命名新的类型代替数组 typedef int arr[10]; arr a;//a为10个元素的数组 命名指针 typdef int* p; p a; 命名指向函数的指针 typedef int (*Point)(); Point p1; 以上方法实际上为特定类型指定了同义字 与#define对比 #define是在预编译将某字符串进行替换。 typedef实在编译时进行处理,不是简单的字符串替换。
10. 文件
两种文件: 程序文件。(源文件、目标文件、可执行文件)内容是程序代码 数据文件。内容不是程序,程序运行时读写的数据。 以下讨论数据文件 为了简化用户对输入输入设备的草所,使用户不必区区分各种输入输出设备之间的区别,操作系统把各种设备都同一作为文件来处理。 文件一般指存储在外部介质上数据的集合。 输入输出时数据传送的过程,常将数据输入输出称为流,称数据流。 C语言把文件看作是一个字符(字节)的序列,即由一个一个字符(字节)的数据顺序组成。一个输入输出流就是一个个字符流或字节(流)。 对文件的存取是以字符(字节)为单位。输入输出数据流的开始和结束仅受程序控制而不受物理符号控制。称为流式文件
一个文件有唯一的文件表示,以便用户识别和引用。1.文件路径2.文件名主干3.文件后缀
文件分类
数据文件可分为ASCII文件和二进制文件(映像文件)。如果要求在外村上以ACII代码形式存放,需要在存储前尽心转换。ASCII文件又称为文本文件,每个字节放一个字符的ASCII代码。 数据在磁盘上的存储。字符一律以ASCII存储,数值型既可以用ASCII也可用二进制。 运用ASCII码形式输出字节与字符一一对应,一个字节代表一个字符,因而便于对字符进行逐个处理,也便于输出字符,但存储空间较多,花费转换时间。 用二进制输出数值,可以节省外存空间和转换实践,此时每个字节并不一定代表一个字符。
文件类型指针
每个被使用的文件都在内存中开辟一个相应的文件信息去,用来存放文件的有关信息(文件名,文件状态、当前位置等等)。信息保存在一个结构体变量中。由系统声明。 定义 FILE *fp 通过文件指针变量能够找到与它关联的文件。 指向文件的指针变量并不是指向外部介质上数据文件的开头,而是指向内存中的文件信息区的开头。
打开文件
fopen(文件名,使用文件方式) 返回值为指向文件的指针变量。 如果不能打开,fopen带回错误信息。可能原因: r打开的文件不存在、磁盘故障、磁盘已满无法新建文件。return NULL(stdio.h中被定义为0)
文件使用方式 | 含义 | 如果文件不存在 |
---|
r(只读) | 为了输入数据,打开已存在文本文件 | 出错 | w(只写) | 为了输出数据,打开文本文件 | 建立新文件 | a(追加) | 文本末尾添加数据 | 出错 | rb(只读) | 为了输入数据,打开二进制文件 | 出错 | wb(只写) | 为了输出数据,打开二进机制文件 | 建立新文件 | ab(追加) | 二进制文件末尾添加数据 | 出错 | r+(读写) | 为了读写,打开已存在文本文件 | 出错 | w+(读写) | 为了读写,打开文本文件 | 建立新文件 | a+(读写) | 为了读写 | 出错 | rb+(读写) | 为了读写,打开二进制文件 | 出错 | wb+(读写) | 为了读写,打开二进机制文件 | 建立新文件 | ab+(读写 | 为了读写打开二进制文件 | 出错 |
注意: r不能打开一个不存在文件,否则出错。 w打开文件只能相文件写数据,不能用来向计算机输入。文件不存在则新建、文件存在则将该文件删除,然后新建文件。 a不能打开不存在的文件。打开文件时,文件读写位置标记移到文件末尾 w+方式新建文件,先向文件写数据,然后可以读该文件的数据。 a+原文件不被删除,文件读写位置标记移到文件末尾,可以添加也可以读。 输入ASCII字符时,遇到回车换行,系统把它转换为一个换行符,在输出时把换行转换称回车和换行两个符号。在用二进制文件时,不进行转换,内存中的数据形式与输出到外部文件的数据形式完全一致,一 一对应。 标准输入流stdiin 标准输出流stdout 标准出错输出流stderr fclose(文件指针) 如果不关闭文件将会丢失数据。有些数组在缓冲区还没被写入磁盘。 成功return 0.不成功return EOF(-1)
顺序读写
函数名 | 调用形式 | 功能 | 返回值 |
---|
fgetc | fgetc(fp) | 从fp指向的文件读入一个字符 | 成功返回字符,失败返回EOF | fputc | fputc(chi,fp) | 把ch写入fp指向的文件 | 成功返回输出字符;失败返回EOF | feof | feof(fp) | 检查文件是否结束 | 是返回1否则为0 |
宏名分别为putc和getc
函数名 | 调用形式 | 功能 | 返回值 |
---|
fgets | fgetc(str,n,fp) | 从fp指向的文件读入长度为n-1的字符串,存放到str中(末尾加\0) | 成功返回str地址,失败返回NULL | fputs | fputc(str,fp) | 把str所指字符串写入fp指向的文件 | 成功返回0;失败返回非0 |
如果fgets在遇到\n或EOF,读入结束,但也将\n也写入。如果一开始遇到文件尾或读数据出错返回NULL。 fputs不把str的\0输出带文件中,如果成功返回0,不成功返回EOF
用格式化的方式读写文件
fprintf(文件指针,格式字符串,输出表列) fscanff(文件指针,格式字符串,输出表列) 需要对内存中二进制转换称字符,要花费较多时间
二进制方式向文件读写一组数据
fread(buffer,size,count,fp) fwrite(buffer,size,count,fp) buffer:地址,存放从文件中读入读出的的数据。 size:字节数,字的整数倍 count:要读多少个数据项,每个长度为size fp:FILE指针 fread和fwrite一般用于二进制文件的输入输出。因为他们按数据块的长度处理输入输出,不出现字符转换。如果stdin作为fp则空格也将存储到数据中,出现错误。
随机读写
文件位置指标: 指示要读写的下一个字符的位置。 顺序文件,则美读写一个数据之后,文件位置标记顺序向后移一个位置。 对流式文件可以顺序读写亦可以进行随机读写。读写完上一个字符(字节)后,并不一定要读写后续的字符(字节)。可以对鞋文件中任意位置上所需要的(字符)
文件位置标记的定位
rewind指向文件开头,无返回值。 rewind(fp); fseek(文件类型指针,位移量,起始点) 位移量以七十点为基准,向前移动的字节数。应是long型数据 ftell返回相对开头位置的位移量,出错返回-1L
出错检测
ferror(fp) 返回值为0未出错,非零出错。
clearerr 将文件错误标志和文件结束标志置0.假设出现错误,ferror为非零值,调用clearerr(fp)。 只要出现文件读写错误标志,就一直保留。直到调用rewind或clearerr,或其他输入输出函数
- 关键字-菜鸟教程
- 运算符-菜鸟教程
如有谬误欢迎指正!
|