iNote_C语言程序设计
第一章:C语言概述
1. C语言特点
l 语言简洁、紧凑,使用方便、灵活(32关键字 | 9控制语句 | 书写形式自由 | 主要用小写字母)
l 运算符丰富(34 运算符 | 括号、赋值和强制类型转换等都作为运算符来处理)
l 数据类型丰富,具有现代语言的各种数据结构(整型、浮点型、字符型、数组类型、指针类型、结构体类型、共同体类型等)
l 指针类型,十分灵活和多样化
l 具有结构化的控制语句
l C语言完全是模块化和结构化的语言
l 语言限制不太严格,程序设计自由度大(“限制”&“灵活” 限制严格,就失去灵活性;而强调灵活,就必然放松限制)
l C语言允许直接访问物理地址,能进行位(bit)操作,能实现汇编语言的大部分功能,可以直接对硬件进行操作
l 生成目标代码质量高,程序执行效率高(一般只比汇编程序生成的目标代码效率低10%~20%)
l 编写出的程序可移植性好(比汇编语言好)
2. BASIC和FORTRAN语言都容易些
对操作系统和系统实用程序以及需要对硬件进行操作的场合,用C语言明显优于其他高级语言,有的大型应用软件也用C语言编写。NUIX操作系统与C语言不可分 | 在数据结构课程中,多采用C语言作为背景语言。
3. C++语言 & C语言
C++是为了解决编写大型软件的问题而产生的,学起来比C困难得多 | 不是所有的人都去编写大型软件。在发达国家的大学中,C语言仍然是大学生的一种基本选择 | 掌握了C语言,在学C++不会太困难。
4. 知识点总结
1. /* */是C语言中的注释方式,亦可以使用//单行注释。
2. 函数是C程序中的基本单位,有利于实现程序的模块化。
第2章 程序设计的灵魂——算法
1. 什么是算法
算法是 对数据的操作 | 广义地说,为了解决而采取的方法和步骤 。
2. 算法的特性
有穷性 | 准确性 | 0或N个输入 | 1或N个输出 | 有效性
3. 流程图的构成
1)表示相应操作的框;2)带箭头的流程线;3)框外必要的文字说明。
4. 基本结构的特点
1)只有一个入口;2)只有一个出口;3)结构内的每一部分都有机会被执行到;4)结构内不存在“死循环”。
5. 结构化程序设计
结构化程序设计强调程序设计风格和程序结构的规范化,提倡清晰的结构。
结构化程序设计的基本思路:把一个复杂的求解过程分阶段进行,每个阶段处理的问题都控制在人们容易理解和处理的范围内。(结构化程序设计的方法用来解决人脑思维能力的局限性和被处理问题的复杂之间的矛盾)
实现方法:1)自顶向下;2)逐步细化;3)模块化设计;4)结构化编码。其中,1)和2)的过程是讲问题求解由抽象逐步具体化。
第3章 数据类型 运算符与表达式
1. 数据类型:
1)基本型(整型|字符型|浮点型|枚举型);2)构造类型(数组类型|结构体类型|共同体类型);3)指针类型;4)空类型。
2. 常量(直接常量|字符常量)
#define Name C_string 简单替换,一改全改。
3. 变量
1)以一个名字对应代表一个地址;2)变量名对大小写敏感;3)长度最好不超过8个字符;4)先定义,后使用。
4. 整形数据
1)正数的补码是它的原码,负数的补码是它的“反码+1”;2)int的范围是-32768~32767,unsigned int的范围是0~65535,long的范围是-2147473648~2147483647;3)signed可以省略;int溢出时,“周而复始”。
5. 浮点型数据
1)十进制小数形式 | 指数形式(即科学计数法);2)浮点型数据是按照指数形式存储的;3)在TC中,float占4字节,有效数字6~7位,double占8字节,有效数字15~16位,long double占16字节,有效数字18~19位;4)应避免大数与小数直接相加减,否则会“丢失”小数;5)float型变量只接收7位有效数字,其余的忽略不计,double类比之。
6.字符型数据
1)编译系统用1个字节来存储1个字符;2)字符型数据与整形数据是相通的,两者可以相互赋值;3)C语言中没有字符串变量,字符串的存储必须借助数组。
7. 各种数据类型间的混合运算
1)+-*/运算中2个数中有一个数为实数或者双精度数,结果就是double;2)%左右必须都是整数;3)2个整数相除,结果向零取整;4)强制类型转换的优先级仅次于括号;5)在结果输出之前,所有的运算应当结束。
8. 赋值表达式
1)把浮点数据赋值给整型时,舍弃浮点数的小数部分;2)把double赋值给float时,截取前7位有效数字,存放到float变量中,但应注意数值范围不能溢出;3)把unsigned数据赋值给signed时,可能出错;4)不同类型的整形数据之间的赋值归根结底就是:把存储单元中的存储形式直接传送。
9. 逗号运算符和逗号表达式
1)逗号表达式的值是最后一个单元的值;2)逗号的作用有2——连接逗号表达式和连接函数的形式参数。
第4章 C语言顺序程序设计
1. C语句的5种类型
控制语句 | 函数调用语句 | 表达式语句 | 空语句 | 复合语句
2. 赋值语句 赋值表达式左侧的值就是表达式的值(表达式有值,语句没有值)
3. 字符数据的输入输出
1)putchar(c):向终端输出一个字符,c是字符变量或整型变量;2)getchar():从终端得到一个字符,注意没有&取址符。
4. 格式输入与输出
1)printf(格式控制,输出表列)
a. 格式符%m.n*,m表示数据的最小宽度,n分2种情况——对实数,表示输出n位小数| 对字符串,表示截取的字符的个数 | 如果m与n有冲突,确保n全部输出;
b. %f 以小数形式输出单、双精度数,默认输出6位小数,可以通过n更改;
c. %g,G在%f和%e之间选择最少的那一个输出格式;
d. 默认为右对齐,用负号可以更改 | 小数点占据1列 | e占1列;
e. 由于实数在内存中的存储误差,%f输出可能与原值不同(float f=123.456;printf(”%f”,f);
2)scanf(格式控制,地址列表)
a. scanf的格式控制中多了*,表示本输入项在读入后不赋给相应的变量;
b. 可以指定输入数据所占的列数,系统自动按它截取所需数据(取最先输入的);
c. %c格式输入符时,空格字符和“转义字符”都作为有效字符输入;
d. %d遇到3种情况输入结束:空格、回车或跳格 | 按指定的宽度结束 | 非法输入;
第5章 选择结构程序设计
1. 关系表达式和逻辑表达式
1)关系表达式的值是可运算的“0”或“1”;2)并不是所有的逻辑运算都被执行,只是在必须执行下一个逻辑运算才能求出表达式的解时,才执行该运算符,如a&&b&&c …3)逻辑非(!)的优先级仅次于括号()。
2. 条件运算符:条件运算符的结合方向是“自右向左”,如a>b?a:c>d?c:d…
3. switch语句
1)执行完1个case后面的语句后,流程控制转移到下1个case继续执行;2)switch必须与break联用,否则会出现冗余。
第6章 循环控制
1. goto语句及其构成的循环
1)相当于锚标记,先定义后使用;2;goto语句可读性差,无规律,只有在多层循环的内层跳到外循环时才会使用。
2. while循环和do…while循环
1)两者都是当条件判断为真实,才能持续循环,结果有可能相同,有可能不同;2)while内的变量不能字处理(自加或自减),只能进行条件判断;3)while循环能完成的for都可以;4)do…while循环在while语句后要加分号。
第7章 数组
1. 一维数组的定义和引用
1)定义数组时必须指定数组的长度,且中括号只能放置常量;2)一旦对数组进行初始化,未赋值的元素默认为0或’/0’。
2. 二维数组的定义与引用
1)二维数组被看一种特殊的一维数组,它的元素又是一个一维数组;2)定义时如果对全部元素都赋初值,则定义数组时对第一维的长度可以不指定,但第二维的长度不能省。
3. 字符数组
1)如果初值个数小于数组长度,则其余的元素自动定位空字符;2)字符数组的输入输出:printf(“%s”,c) | scanf(“%s”,str);scanf函数输入时,系统把空格字符作为输入的字符串之间的分隔符。
4. 字符串处理函数(string. h)
1)puts(str1) 字符串中允许包含转义字符,且输出完成后换行;2)gets(str2) 的输入结束标志是回车键;3)strcat(str1,str2) 把str2连接到str1的后面,返回新的str1的地址;4)strcpy(str1,str2) & strncpy(str1,str2,n) 把str2复制到str1中,str2可以是字符串常量;5)不能把str2直接赋值给str1,只能使用strcpy函数;6)strcmp(str1,str2) 相等为0,大于为正,小于为负,且字符串的比较只能使用strcmp函数;7)strlen(str),返回str的实际长度,不包含’\0’;8)strlwr(str) & strupr(str) 改大小写。
第8章 函数
1. 函数概述
1)1个C程序由1或N个程序模块组成,每一个程序模块作为一个源程序文件;2)1源程序文件由1或N个函数及其他有关内容(如命令行、数据定义等)组成;3)程序编译时,以源文件(而非函数)为单位;4)所有函数都是平行的,即分别定义,相互独立,可以相互调用但不可嵌套定义;5)函数可以理解为一种“复杂的运算”。
2. 定义函数
1)如果定义函数时不指定函数类型,系统隐含指定函数类型为int型;2)在程序开发过程中,会定义一些空函数,后期扩充。
3. 函数参数与函数的值
1)在定义函数时,函数名后面括号的变量是形参,在主调函数中调用函数时,函数名后面括号中的参数(可以是常量),是实参;2)形参未调用时,形参不分配内存,只有被调用时才分配,调用结束后形参的内存单元释放;3)形参和实参的类型必须相同或复制兼容(把实参自动转化为形参的类型,否则报错);4)C语言中,实参单向传值给形参;5)函数中可以有N个return,执行到reutrn就返回;6)函数值类型和return语句中表达式的值不一致时,以函数类型为准。
4. 函数的调用的方式
1)函数语句;2)函数表达式;3)函数参数。
5. 函数声明 & 函数原型
1)函数调用的条件:已定义 | 已声明或包括在文件头部或定义在被调用之前;2)函数声明中可以只写形参类型,不写形参名(注意顺序);3)函数的定义是指对函数功能的确立,包括指定函数名、函数值类型、形参及其类型、函数体等,是一个完整的、独立的函数单位,而函数的声明则是把函数的名字、类型以及形参类型、个数和顺序通知编译系统,以便按此规定对照检查;4)main以外的其他函数之间的互调也要声明。
6. 函数的递归调用
1)递归问题可以分为“回推”和“递推”2个阶段;2)解决递推问题的关键在于数学建模,写出数学上的函数。
7. 数组作为函数参数
1)数组名作为实参和形参时,传递的是数组首元素的地址;2)数组元素可以作为实参;3)形参数组可以不指定大小,只写空的方括号即可;4)数组作为形参时,双向传值;5)多维数组名作为函数参数时,第1维的长度可以省略或与实参不同,其余的则不可。
8. 局部变量
1)函数内部定义的变量是内部变量,即局部变量;2)不同函数中可以使用相同名字的变量,它们代表着不同的对象,互不干扰;3)复合语句中定义变量,这些变量只在本复合语句中有效,此复合语句称为“分程序”或“程序块”;4)形参也是局部变量。
9. 全局变量
1)函数之外定义的变量是外部变量,即全局变量;2)全局变量增加了函数间数据联系的渠道,一般变量名的第1个字母大写;3)建议不适用全局变量:伴随程序执行的全程,生存周期长 | 降低了函数的通用性 | 降低了函数的可读性 | 全局变量遇到局部变量就会被屏蔽。
------
10. 变量的存储类别
1)2大类4小类:静态存储类,动态存储类||自动的(auto),静态的(static),寄存器的(register)和外部的(extern);
2)auto类型:凡没有声明为static的局部变量(函数内的变量)都是自动变量,其中auto可以省略;3)static变量(静态局部变量):属于静态存储类别,在静态存储区内分配存储单元,且只赋一次值,以后每次调用函数时不在重新赋初值,而只是使用上次函数调用结束后的值;4)定义局部变量时不赋初值时,静态局部变量自动赋初值0或者空字符,而对自动变量而言,得到的是一个不确定的值;5)静态局部变量在函数调用结束后依然存在,但是其它函数仍然不能访问它;6)静态局部变量的优缺点:可以保留函数上一次调用的值,且定义之后不用每次调用都重新赋初值|耗费内存,生存周期长,降低程序可读性;
7)register变量:只有局部自动变量和形式参数可以作为寄存器变量,而且CPU的寄存器有限,不能多放;
8)用extern声明外部变量:类似于函数原型的声明,只声明,不定义,表示该变量是一个已经定义了的外部变量;9)用extern在同一文件内声明外部变量:类型名可以省略,e.g.extern A,B;10)用extern在多个文件中声明外部变量:亦然;11)用static声明外部变量:使得该变量的作用域局限于本文件而不能被其他文件调用。
11. 声明 & 定义
1)对于函数,声明的是函数的原型,而定义则是函数自身,是一个单独的模块;2)对于变量,一般把建立存储空间的声明称为定义,不建立存储空间的声明成为声明。
12. 内部函数和外部函数
1)只能被本文件的其他函数调用的函数,即内部函数;2)在函数类型前加static可是生函数变为内部函数,又称为静态函数;3)能被本文件之外的其它函数调用的函数,即外部函数;4)外部函数定义时可以省去extern,外部调用时,必须用extern声明函数原型。
第9章 预处理命令
1. 宏定义
1)宏是用一个指定的标识符来代表一个字符串(#define 标识符 字符串);2)宏只不过是简单的置换,不做正确性检查;3)宏定义不加分号,否则分号会被一同置换;4)用“#undef 标识符”可终止宏定义的作用域;5)程序中用双引号括起来的字符串,即使与宏名相同,也不进行置换。
2. 带参数的宏定义
1)形式为“#define 宏名(参数表) 字符串”,将程序句中的相应是实参(可以是变量、常量或表达式)代替形参;3)宏名与带参数的括号之间不能有空格,否则空格后面的字符都作为替代字符串的一部分。
3. 带参数的宏 & 函数
1)函数调用,先求出实参,再代入形参,而宏知识进行简单的字符替换;2)函数调用是在程序运行处理时,为形参分配临时的内存单元,而宏展开则在编译前;3)函数只能得到一个返回值,而宏可以设法得到N个结果。
4. “文件包含”处理
1)形式:#include “文件名”或#include <文件名>;2)预编译处理时,要对#include命令进行“文件处理”,把文件名所指示的文件内容复制到当前文件内;3)1个#include只能包含1个文件;4)调用库函数,使用尖括号,调用自定义的文件,使用双引号,以节省查找时间;5)若文件不在当前目录下,应给出文件的路径。
5. 条件编译(的形式)
1)“#ifdef 标识符/程序段1/#else/程序段2/#endif”,作用是若指定的标识符已经被#define定义过,编译程序段1,否则编译程序段2;2)“#ifndef 标识符/程序段1/#else/程序段2/#endif”,作用是若指定的标识符没有被#define定义过,编译程序段1,否则编译程序段2;3)“#if 表达式/程序段1/else/程序段2/#endif”,作用是当指定的表达式为真(非零)时,编译程序段1,否则编译程序段2。
6. 条件编译的优点
非条件编译会导致目标程序长,运行时间长。采用条件编译,可以减少被编译的语句,从而减少目标程序的长度,减少运行时间。
第10章 指针
1. 地址与指针
1)内存区的每1字节都有编号,即地址,变量的地址即变量的指针;2)程序中一般是通过变量名来对内存单元进行存取操作的,程序进过编译后,已经将变量名转换为变量的地址;3)存放另一变量地址的变量,即指针变量。
2. 变量的指针 & 指针变量
1)定义指针的形式:“基类型 *指针变量名”;2)指针只能指向同一种变量的地址;3)取地址符(&),指针运算符(*),优先级相同,自右向左。
3. 指针作为函数参数
1)指针变量作为形参时,指针变量的传值是“值传递”,但所指变量的数值发生变化;2)只定义不赋初值的指针,“*temp = *p1”,结果不可预见,因为temp的指向是不确定的,有可能指向系统占用的内存单元;3)指针变量作为参数,在函数执行过程中使指针变量所指向的变量值发生变化,函数调用结束后,这些变量的变化依然保留下来,即实现了“通过调用函数使变量的值发生改变”的目的;4)不要企图通过改变指针形参的值使指针实参的值发生改变;5)如需要改变n个变量,要使用n个指针参数。
4. 数组与指针
1)指向数组元素的指针,同指向普通变量的指针相同;2)数组名(不包括形参数组名)代表数组中首元素的地址(p = a);3)如果p已指向数组的某元素,则p+1指向的是下1个元素;4)(p = a),a+i也代表地址,与p+i等效;5)(p = a),p[i],*(p+i),*(a+i),a[i]等效;6. 变址运算符([]);7)数组不能自加,它是一个地址常量,指针可以;8)指针也可以进行关系运算,PK的是地址;9)在C中,指针越界,系统不提示。
5. 用数组名作函数参数
1)C编译将形参数组名作为指针变量来处理,因此也不提示越界;2)实参数组名代表一个固定的地址,或者说是指针常量,但型参数组并不是一个固定的地址,而是作为一个指针变量,在函数调用开始时,它的值等于实参数组首元素的地址,在函数执行期间,可以再次被赋值;3)使用数组名做形参,相对于指针,更容易识别和理解;4)利用指针的移动取不同的值一定要借助与数组,因为数组便于组织元素;5)作为指针变量的实参,必须先指向一个已定义的单元。
1)(a[m][n])a+1 和*(a+1)所代表的地址相同;2)&a[i]与a[i]的值形同;3)*a亦代表首地址;4)指向多维数组元素的指针:定义形式为“函数类型 (*p)[n];”,e.g.int (*)[4];5)指向多维数组的指针作参数:e.g. void search(float (*p)[4],int n);。
7. 字符串的表示以及字符指针做参数
1)访问字符串的2种方式:字符数组|字符指针(char *string = “love”);2)C语言对字符串常量是按字符数组处理的,在内存中开辟一个字符数组用来存放该字符串常量,并把首地址付给字符指针;3)字符指针输出字符串(把指针指向字符数组,亦然):printf(“s%”,string);4)数组形式的字符串不能直接输出,必须借助循环或者函数(所有非循环类的输出,遇到’\0’都会结束;5) 字符指针作为函数参数;6)字符指针做形参,“双传值”;7)实参和形参中,字符数组和字符指针可以互换和任意组合。
8. 字符指针 & 字符数组
1)存放的内容不同;2)赋值方式不同,数组必须定义的同时初始化,之后不能改变,而指针可以;3)定义1个字符数组时,即分配地址,可直接输出,而定义字符指针为初始化,指向不定;4)字符指针式变量,字符数组是常量;5)字符指针可以指向1个格式输出字符串,妙用(char *format = “a=%d,b=%f\n”;printf(format,a,b);)。
9. 指向函数的指针
1)用函数指针变量调用函数;2)函数在编译时被分配1个入口地址,即函数的指针;3)指向函数的指针变量的一半定义形式:数据类型 (*指针变量名)(函数参数类表);4)指向函数的指针变量不能移动;5)可以只给函数类型,不给参数名;6)调用时只需将原来的函数名替换成*(p)即可。
10. 指向函数的指针做函数参数
1)定义的形式:void sub( int (*x1)(int),int (*x2)(int,float));2)作为实参的函数,应在主调函数中用函数原型做声明。
11. 返回指针值的函数:定义的形式:类型名 *函数名(参数列表)。
12. 指针数组和指向指针的指针
1)指针数组定义的形式:类型名 *数组名[数组长度];2)利用指针数组,可以存储多个字符串(char * string[] = {“Thank”,”you”,”!”});3)指向指针的指针定义的形式:类型名 **变量名;4)指针数组作为main函数的形参:void main(int argc, char *argv[]),在操作命令中使用,提更main函数的参数,其中命令名是main所在的执行文件名,它也是一个参数。
13. void指针类型
1)ANSI C标准规定用动态存储分配函数时,可返回void指针;2)指向1个抽象的类型的数据,在把它的值赋给另一个指针变量时要强制类型转换。
第11章 结构体与共同体
1. 结构体
1)结构体定义的形式:“struct 结构体名{成员列表};”;2)结构体在定义时可以引用其他结构体作为自己的成员;3)成员名可以与程序名中的变量名相同,两者不代表同意个对象;4)结构体变量的引用有两种:成员(分量)运算符 | 结构体指针。
2. 结构体数组和结构体指针
1)跟结构体变量的定义相仿,在变量名后面加中括号说明数组长度即可;2)结构体变量的指针是指该变量所占内存段的起始地址,定义的形式:struct 结构体名称 *pointer(= &stru | stur[3]);3)指向运算符(->),与指针联用,用以访问结构体的元素;4)指向运算符的优先级仅次于()和[],大于自加和自减;5)结构体指针不能指向结构体内的某一个元素。
3. 结构体变量 & 结构体指针
1)结构体成员作参数,与普通变量一样,值传递;2)结构体变量做实参,也是值传递,把结构体变量所占的内存单元的内容全部顺序传递给形参,开销较大;3)用结构体变量或者数组的指针做实参,将结构体变量或数组的地址传给形参,运行效率高。
4.链表
1)链表,一种数据结构,根据需要开辟内存单元;2)链表的基本概念:结点| head |表尾;3)结点的模型:struct stu{int num; float score; struct student *next;};4)指针类型的成员既可以指向其他类型的结构体数据,也可指向自己所在的结构体类型数据。
5. 动态链表所需的函数(#include <malloc.h>)
1)malloc函数:原型为void *malloc(unsigned n),作用是分配一个长度为size的连续空间,返回一个指向分配域起始地址的指针(void类型),若未成功,返回NULL;2)calloc函数:原型为void *calloc(unsigned n,unsigned size),作用在内存的动态存储区中分配n个长度为size的连续空间,返回一个指向分配域起始地址的指针,若未成功,返回NULL。3)free函数:原型为void free(void *p),释放p指向的内存区,其中p是最近一次调用calloc或malloc时返回的值。
6.动态链表的操作
1)文件的头部:#include <stdio.h> #include <malloc.h> #define NULL 0
#define LEN sizeof(struct student)
struct student{ long num; float score; struct student *next; }; int n;
2)创建动态链表
struct student *creat(void) {
struct student *head; struct student *p1,*p2; n = 0;
p1 = p2 = (struct student *)malloc(LEN);
scanf("%d,%f",&p1->num,&p1->score); head = NULL;
while(p1->num != 0) {
n++; if(n == 1) head = p1; else p2->next = p1; p2 = p1;
p1 = (struct student *)malloc(LEN);//
scanf("%d,%f",&p1->num,&p1->score); }
p2->next = NULL; return (head); }
3)输出动态链表的结点
void print(struct student *head){ struct student *p;
printf("\nNow,These %d records are:\n",n); p = head;
if(head != NULL)
/*do{ printf("%ld %5.1f\n",p->num,p->score);p = p->next;}while(p != NULL);*/
while(p != NULL) {printf("%ld %5.1f\n",p->num,p->score);p = p->next;} }
3)删除动态链表的结点
struct student *del(struct student *head,long num){
struct student *p1,*p2; if(head == NULL){
printf("\nThis List is Null!\n"); return head;}
p1 = head; while(num != p1->num && p1->next != NULL)//
{ p2 = p1;//
p1 = p1->next ; }
if(num == p1->num){
if(p1 == head) head = p1->next; else p2->next = p1->next;
printf("delete:%ld\n",num); n = n-1; }
else printf("%ld not been found!\n",num); return head;
}
4)插入新结点到动态链表
struct student *insert(struct student *head,struct student *stud)
{ struct student *p0,*p1,*p2;
p1 = head;//·
p0 = stud;//
if(head == NULL)//
{ head = p0;p0->next = NULL; }
else {//
while((p0->num > p1->num) && (p1->next != NULL)) {
p2 = p1; p1 = p1->next; }
if(p0->num <= p1->num ){//
if(head == p1) head = p0; else p2->next = p0;
p0->next = p1; }//
else {p1->next = p0;p0->next = NULL; }
}
n = n+1; return head;
}
7. 共用体
1)概述:几个变量共占一段内存的结构,极为“共用体”类型的结构;2)定义的形式:union un_name{成员表列} 变量列表;3)共用体变量所占的内存长度等于最长的成员的长度;4)共用体变量的访问:使用成员访问符(.);5)共用体类型的特点:共用1个内存段存放N个不同类型的成员,但1次只能存放其中1种,且共用体起作用的是最后一次存放的成员;6)不能直接使用变量名赋予成员初值或者访问和更改成员的值;7)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针;8)共用体类型出现在结构体类型定义中,也可以定义共同体数组,结构体和数组也可以做共同体的成员。
#include <stdio.h>
struct{ int num; char name[10];
char sex; char job;
union{int banji; char position[10]; }category;
} person[2];
void main(){
int i; for(i = 0; i < 2; i++) {
scanf("%d %s %c %c",&person[i].num,&person[i].name,&person[i].sex,&person[i].job);
if(person[i].job == 's')scanf("%d%",&person[i].category.banji);
else if(person[i].job == 't')scanf("%s",person[i].category.position);
else printf("input error!");
}
printf("\n"); printf("No. Name sex job class/position\n");
for(i = 0; i < 2; i++) {
if(person[i].job == 's') printf("%-6d%-10s%-3c%-3c%-6d\n",person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.banji);
else printf("%-6d%-10s%-3c%-3c%-6s\n",person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.position);
}
}
8. 枚举类型
1)枚举,即将变量的值一一列表出来,变量的值只限于列举出来的值的范围;2)定义的形式:enum 枚举类型名{枚举元素列表};3)枚举常量是常量,编译时按照定义的书序分别赋值0,1,2,……;4)枚举值可以根据赋初值的顺序进行比较,但不能跟数值进行比较;5)1个整数不能直接赋值给枚举变量,需进行强制类型转换(enum e_name);6)枚举类型的变量亦可以自加减。
9. 用typedef定义类型
1)定义新类型的方法:先按定义变量的方法写出定义体(如:int i;)-->将变量名换成新类型名(如:将i换成COUNT)-->在最前面加typedef(如:typedef int COUNT)-->用心类型定义变量;2)定义新的数组类型:先按写出定义数组变量的形式(int n[100])-->将变量名n换成自己指定的类型名(int NMU[100])-->在前面加上typedef,得到新数组类型 -->用新数组类型定义变量(NUM a);3)typedef只能声明新类型,不能定义变量;4)typedef和#define类似,只进行简单的字符替换。
第12章 位运算
1. 位运算概述:运算符:&,|,~,<<,>>;2)运算量只能是整形或字符型,不能为实行数据。
2. 运算符
1)“按位与”运算符(&)的特殊用途:清零 | 保留指定位的值,其他置零 ;2)“按位或”运算符(|)的用途:使指定位的值置’1’;3)“异或”运算符(/\)的用途:作用位置1,被作用的部位翻转;4)“取反”运算符(~):优先级相对于算术、关系、逻辑和其他位运算符都高;5)左移运算符(<<):在不溢出的情况下,每移动1位,乘以2;6)右移运算符(>>):在不溢出的情况下,每移动1位,除以2。
3. 位段
第13章 文件
1. C文件概述
1)C语言把文件看作是一个字符(字节)的序列,即由一个个字符(字节)的数据顺序组成;2)根据数据的组织形式,文件可分为ASCII文件和二进制文件;
2. 文件类型指针
1)使用的文件都在内存中开辟一个区,用以存放文件的有关信息,这些信息被存放在一个结构体变量中,该结构体是由系统定义的,取名LIFE;2)文件型指针变量的定义形式:FILE *p。
3. 文件的打开
1)文件的打开(fopen函数):FILE *fp;fp = fopen(file_name,usemode);
2)文件使用方式:r - 只读 | w - 只写 |a - 追加 | rb - 只读(2进制)|wb - 只写(2进件)|ab - 追加(2进制)|r+ - 读写|w+ 读写(新建)| a+ 读写|rb+,wb+,ab+ -- 类比之,2进制文件;
3)w方式,若文件存在,删除原内容再写数据,若文件不存在,根据file_name自建文件;
4)a方式,若file_name不存在则报错,否则打开时位置指针移至文件末尾;
5)文件操作模块:
if((fp = fopen(“file_name”,”r”)) == NULL){printf(“cannot open this file\n”); exit(0); }
4. 文件的读写
1)fgetc和fputc函数
fputc(ch,fp);
ch = fgetc(fp);while (ch != EOF){putchar(ch);ch = fgetc(fp);}//用以检查文本文件,EOF的值是-1
while( !feof(fp) ){ c = fgetc(fp); … } //feof(fp)用以测试fp所指向的文件当前状态是否“文件结束”,如果是,返回1,否则返回0,此方法亦适用于文本和二进制文件
2)fread和fwrite函数(一般用于二进制文件的读写)
fread(buffer, size, count, fp); fwrite(buffer, size, count, fp);
buffer指针,对于fread它是读入数据的存放的地址,对于fwrite它是输出数据的地址(都是初始地址);size,读写的字节数;count,读写多少个size数据项;fp,文件指针。
for( i = 0; i < 40; i++) fwrite(&stud[i],sizeof(struct student), 1,fp);
若执行成功,则返回count的值。
3)fprintf和 fscanf函数(消耗大,不常用)
fprintf( fp, format_string, outputList );//把outputlist中的数据格式化地输出到文件
fscanf( fp, format_string, inputList ); //把文件中的数据格式化地读入到intputlist中
4)fgets和fputs函数
fgets(str,n,fp); n是得到字符的个数,由于字符串以’\0’结束,实际上只能得到n-1个,它们被放入str数组中(如果遇到EOF或换行符即结束),最终返回str的首地址。
fputs(str,fp) 向文件输出指定的字符串,字符串的末尾’ \0’不输出,若成功返回0,若失败,返回EOF。
5. 文件的定位
rewind(fp); 重新定义指针的位置至文件头。
fseek(fp,count,site) 移动指针,count表示相对移动量,数字的末尾加L,site可选0,1,2(0代表文件开始,1代表当前位置,2代表文件末尾)(一般用于二进制文件)。
ftell(fp); 返回文件指针的当前位置。
6. 文件状态
ferror(fp); 返回0代表为出错,返回非零代表出错。
clearerr(pf); 使文件错误标志和文件结束标志置0。
常用的C程序模块
1. 排序
(1)排序法 for(i = 0; i < N - 1; i++) {
crs = i;
for(j = i; j < N; j++)
if(ary[j] > ary[j+1]) crs = j + 1;
temp = ary[i]; ary[i] = ary[crs]; ary[crs] = temp;
}
(2)冒泡法 for(i = 0; i < N-1; i++)
for( j = 0; j < N-i; j++)
if(ary[j] > ary[j+1]) {
temp = ary[j]; ary[j] = ary[j+1]; ary[j+1] = temp;
}
2. 读写操作
(1)fgetc和fputc函数
void main(){ //从in文件中出数据,在写入out文件中
FILE *in,*out; char ch,infile[10],outfile[10];
printf("Enter the inflie name:\n"); scanf("%s",infile);
printf("Enter the outflie name:\n"); scanf("%s",outfile);
if((in = fopen(infile,"r")) == NULL) { printf("can not open infile!\n"); exit(0); }
if((out = fopen(outfile,"w")) == NULL) {printf("can not open outfile!\n"); exit(0); }
while(!feof(in)) //feof用以判断文件是否真的结束,如结束,返回1,否则返回0;
fputc(fgetc(in),out); //如果,out.txt中如果原来有内容,执行程序后会被覆盖;
fclose(in); fclose(out);
}
(2)fread和fwrite函数
void load(){ int i;
if((fp = fopen("stu_list","rb")) == NULL) { printf("cannot open infile\n"); return; }
for(i= 0; i < SIZE; i++)//如果读取成功,返回读取数据段数的值,即为1;
if(fread(&stud[i],sizeof(struct student),1,fp) != 1) {
if(feof(fp)) { fclose(fp);return; }
printf("file read error!\n");
}
fclose(fp);
}
void save(){ FILE *fp; int i;
if((fp = fopen("stu_list","wb")) == NULL) { printf("cannot open file\n");return; }
for(i = 0; i < SIZE; i++) {
if( fwrite(&stud[i], sizeof(struct student), 1 ,fp) != 1 ) {
printf("file write error\n");fclose(fp);
} } }
3. “遇3而终”
#define N 13
struct person{ int number; int nextp;} link[N+1];
void main(){
int i,count,h;
for(i = 0; i <= N; i++) {
if(i == N) link[i].nextp = 1;else link[i].nextp = i + 1;
link[i].number = i; }
printf("\n"); count = 0; h = N;
printf("sequence that persons leave the circle:\n");
while(count < N - 1) { i = 0;
while(i != 3) {
h = link[h].nextp; if(link[h].number) i++;
}
printf("%4d",link[h].number); link[h].number = 0; count++;
}
printf("\nThe last one is: ");
for(i = 0; i <= N; i++)
if(link[i].number) printf("%3d",link[i].number);
printf("\n");
}
4. 结构体排序
void sort(struct student *p){
struct student * attain(struct student *head,int n);
struct student *head; int n, i, j, max; int temp; long templ; head = p; n = 0;
while(head != NULL) {
n++; head = head->next ;
}
for(i = 0;i < n-1; i++) { max = i;
for(j = i;j < n-1; j++)
if(attain(p,max)->num < attain(p,j+1)->num ) max = j+1;
templ = attain(p,max)->num ; attain(p,max)->num = attain(p,i)->num ;
attain(p,i)->num = templ;
temp = attain(p,max)->score ; attain(p,max)->score = attain(p,i)->score ;
attain(p,i)->score = temp;
}
}
struct student * attain(struct student *head,int n){ int i;
for(i = 0; i < n; i++)
head = head->next ;
return head;
}