数据
1. 1e-3:aeb类型,即a*(10^b);
2. int rand(void)函数:
位于stdlib,h;
返回一个0~RAN_MAX的值伪随机数,若随机数种子相同,则返回的随机数序列相同;
RAN_MAX的值为int类型的最大值;
默认随机数种子为1,可用void srand(int)在rand()之前设置随机数种子,一般用time(NULL) 当前时间的毫秒 数作为参数。
可用取余操作%来限制随机数的范围;
3. %取余的操作数必须为整型(即整数,正负皆可);取余操作的结果与第一个操作数的正负性相同;
4. 字符常量: '/a';a可为八、十六进制;
5.递增操作a++,当变量a使用完毕不再需要时即执行+1而不会等到所有语句都执行完,如while(T--),判断完成后即完成-1;a-->0,即使a不满足条件,在判断之后还是会执行a--!!!!
输入输出
1. %格式控制符,后接d等,若没有则忽略;%%表示输出字符%;
2. %*c : *空读一个数据,%*c为空读一个字符,读取但不赋值;
3. getchar()函数: 返回值为所输字符的ASCII码,直到用户输入回车才结束;
4.整数部分若实际数值比规定位数多,则按实际数值输出;若少,则空格补位,空格位置视是否有符号;浮点数补零。
5.getchar()函数:行缓冲输入方式。将输入的结果放在输入缓冲区队列,直至输入EOF或者换行符为结束,getchar()从输入缓冲区内读一个字符,故两个连续的getchar要在同一行输入,否则第二个getchar()得到的值是换行符;
6. 连续的scanf当心将换行符赋给%c : 可用getchar()吃掉换行符;%c前留空格可无视所有空白字符:换行、制表、空格;
7.scanf()可以指定位宽,但不能指定输入浮点数的精度,返回值为成功读取的类型的数量;不能包含换行符。
short对应%hd。
8.输出double和float都是用%f,但double输入格式为%lf。因为printf时,float会被转换成double。
9.gets函数会一直接收输入(包括空格)直到换行,所以如果数据中有空格,最好用gets来获取。另外,如果gets函数前还有其他输入函数,要用getchar去吃掉缓冲区内的换行符,否则会直接略过gets函数。且,不能定义指针p再gets(p),因为p可能指向任何非法地址。
条件语句
1.优先级:算数运算符优先级高于逻辑运算符,==和!=优先级在逻辑运算符中最低;
(一元运算符) 逻辑非->算术运算符->逻辑运算符->逻辑与->逻辑或
2.结合性:逻辑运算符、逻辑与、逻辑或的结合性都为从左到右;
一元运算符(逻辑非)都为从右到左;
3.短路特性:逻辑与、逻辑或,若由左操作数已经知道运算结果,则不再计算右操作数。
4.唯一三元运算符 ? : max=a>b?a:b;
5.switch:case,break,default
溢出
1.一般不用相减来判断大小,因为可能第一个操作数小于第二个操作数,而结果溢出为正;
2.浮点数运算既可以上溢也可以下溢;
3.要使用数据类型大小时,最好用sizeof(),可提高可移植性;
舍入(截断):针对不同数据类型之间的转换
int->float:不会溢出但可能被舍入;
精度损失
float:有效数字6~7位,精度位数包含整数部分和小数部分
double:有效数字16位
32位系统下,long->float:损失第7位以后的准确性(不含第7位)
十进制小数与二进制小数非一一对应,所有二进制小数都可以找到一个精确的十进制小数,反之则不行,故,当十进制小数转换为二进制小数不能精确表示时,就取近似值;当该近似值再转换为十进制小数时,已经与原小数不同;
两个浮点数,一很大一很小,进行运算时可能发生舍入运算,即无视小的浮点数,结果仍未大的浮点数;
测试
白盒测试/结构测试
黑盒测试/功能测试
导论
程序=算法+数据结构
软件=程序+文档
循环
exit(0)在stdlib.h中,强制终止程序的运行返回到操作系统;
break和continue;continue:无视continue之后的语句,for直接跳转到增,while跳到条件判断;
goto:跳出多重循环使用 goto error; error: 多种情况中的相同错误类型
务必注意switch语句中有无break!!!!
错误类型:
编译错误:语法错误
链接错误:缺少包含的文件
运行时错误:逻辑错误,除零、非法内存访问
函数
1.若函数类型缺省,则默认为整型;
2.assert()宏,定义在<assert.h>,测试断言,为便于理解可视为函数 void assert(int expression),若括号内的假设内容为真,则继续执行;否则,中断程序并报告错误所在的行。等价于 if() exit(1);但后者在debug版本和release版本都会被执行,而assert宏只在debug版本中执行,而在正式的发布版本中不执行,故前者更好,在release中不会影响程序执行的效率。所以断言不能取代条件语句,只是一个标签,用于debug。一个断言一个条件。
3.先决条件务必进行判断,提高robustness。
编程风格
1.花括号换行;
2.函数定义之间空行;
3.定义变量时,初始化的习惯;对于一些需要注释的变量的定义,一个变量一行便于写注释;
4.二元运算符前后各加一个空格;一元运算符,[],.,->,不加空格;,和;后加空格;
但在for和if的括号内有时为了追求紧凑型,二元运算符前后会不加空格;
关键字如for,while等后加空格;
5.形参列表太长可进行缩进,如:
if ((veryLongVar1 >= veryLongVar2)
&&(veryLongVar3 >= veryLongVar4))
{
DoSomething();
}
for (very_longer_initialization;
very_longer_condition;
very_longer_update)
{
DoSomething();
}
6.标识符的命名
共性规则:
有意义的单词;避免数字编号;全局变量和局部变量不重名;不以大小写区分不同标识符;
Linux/Unix风格:小写单词加下划线
Windows风格:大小写单词
Windows应用程序中的命名规则:匈牙利标记法
[限定范围的前缀]+[数据类型前缀]+[有意义的英文单词]
静态变量 s_,static, ch,char
动态变量 g_,global, i ,int
默认情况为局部变量 f ,float
p ,point
->简化:
限定范围和数据类型无视,无特殊意义的循环变量直接定义成i,j,k等单字母变量;
变量名小写字母开头,第二个单词开始首字母大写,形容词+名词形式;newTime;
函数名大写字母开头,之后每个单词首字母大写,动词+名词形式;GetMax()
宏和const常量标识符全大写,用下划线分割单词;
注释格式:修改代码的同时也要注意修改注释或加注释,修改时间、修改人;
重要文件的首部:文件名+功能说明+[作者]+[版本声明]+[日期]
自定义函数的接口;功能,入口参数,出口参数,返回值;
递归
普通递归:函数返回之后还要再做一次运算。
尾递归tail recursion:无需再一级一级返回,最后一个函数的结果即可得出要求的结果。
变量的作用域
1.局部变量(在动态存储区中分配内存
块内定义的局部变量,作用域只在块内;如果块是for语句,则for(;;;)括号内不属于块内;
2.全局变量(在静态存储区中分配内存
从定义的位置到程序结束;
全局变量在定义时,若未初始化,会被编译器自动初始化为0
3.同名时
局部变量隐藏全局变量。
作用域小的局部变量隐藏作用域大的局部变量
4.auto自动局部变量和static静态局部变量
生命周期不同,本质为内存分配区域不一样
static静态局部变量,静态存储区分配内存,只被初始化一次,作用域不变,生命周期为整个程序;
auto自动变量的生命周期和作用域一致;
全局的static和auto,作用域不同;
数组
1.memset函数,在string.h头文件中。memset(a,0,sizeof(a)),将数组置零。
2.memcpy(b,a,sizeof(a));将数组a的内容赋值给b,要求数组a和数组b大小一样。
3.二维数组定义初始化时,第一个下标可省,第二个下标不可省。初始化时可用花括号指定出缺省的行数。
4.二维数组与指针:
a[2][3],a为二维数组首地址,也为第0行地址
a+i为第i行地址、第i行首元素的地址
*(a+i)为第i行首元素的地址
*(a+i)+j第i行第j列元素的地址。
*(*(a+i)+j)i行j列元素的值,等价于a[i][j]
main()函数:
完整形式: int main(int argc, char * argv())
argc : 命令行参数的数量(包括程序名本身)
argv :字符指针数组,每个元素指向一个参数;故,argv[0]指向程序名。
文件:数据的集合;
文件的分类:
按文件的逻辑结构:无结构与有结构,见收藏。
文件的打开:
FILE *fopen( const char *filename, const char *mode);
// 返回指向此文件的指针,若打开失败(文件损坏或不存在),则返回NULL;
如:
FILE *fp;
fp = fopen("test,txt", "r" ) ; // 文件名可包含路径,也可以不,不包含则表示其为当前目录下的文件。
// "D:\\project\\test.txt"
if(fp) // 必须检查是否正确打开。
模式:
r | 以只读方式打开文件,该文件必须存在。 |
r+ | 以读/写方式打开文件,该文件必须存在。 |
rt+ | 以读/写方式打开一个文本文件,允许读和写。 |
rb+ | 以读/写方式打开一个二进制文件,只允许读/写数据。 |
w | 打开只写文件,若文件存在则长度清为0,即该文件内容消失,若不存在则创建该文件。 |
w+ | 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
wt+ | 以读/写方式打开或建立一个文本文件,允许读写。 |
wb | 以只写方式打开或新建一个二进制文件,只允许写数据。 |
wb+ | 以读/写方式打开或建立一个二进制文件,允许读和写。 |
a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留(EOF符保留)。 |
a+ | 以附加方式打开可读/写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(原来的EOF符 不保留)。 |
at+ | 以读/写方式打开一个文本文件,允许读或在文本末追加数据。 |
ab+ | 以读/写方式打开一个二进制文件,允许读或在文件末追加数据。 |
文件的关闭:
int fclose ( FILE *fp ); // 成功返回0,失败返回非零值;
按格式读写文件:
int fscanf ( FILE * stream, const format , [argument...] ); // 文件指针;格式化字符串;输入列表
// fscanf(stdin,...)等价于scanf();
按格式写文件:
int fprintf ( FILE * stream, const *format , [argument] );
// fprintf(stdout,...)等价于printf()
将文件指针置回首部:
fseek(FILE * stream,)
按字符读写文件:
int putc( int c , FILE * fp );
int fputc(int c, FILE *fp ); //向fp中写入一个字符
int getc( FILR *fp ) ;
int fgetc(FILR *fp );`// 从fp中读出一个字符并将位置指针指向下一个字符;若读成功,则返回该字符,否则 返回EOF通常为-1;即返回EOF可能读取错误也可以能读到文件尾部。
判断是否到达文件尾:
int feof(FILE *fp); // 到达文件末尾则返回非零值,不到则返回0;while(!feof(FILE *fp));
返回文件指针的位置:
long ftell ( FILE * fp) ;
判断是否读取出错:
int ferror(FILR * fp ) ; // 出错则返回非0值,否则返回0;
按行读写文件:
int fputs (char * s, FILR *fp ) ; //失败返回0;不同于puts。不会自动添加换行符。
char * fgets( char *s , int n, FILR * fp) ; //n为缓冲区大小,即最多读取n-1个字符;都会在字符串末尾添加'\0',但如果文件中的此行以换行符结束,则会将换行符也读入到字符串末尾再添加'\0';读取成功返回字符串首地址,失败或到末尾则返回EOF;gets不保留'\n',用\0取代;fgets保留且也添加\0
用fgets( buf, sizeof(buf), stdin)取代gets(buf)
按数据块读写文件:
数据块是一个抽象概念,可以是一个数组,也可以是数组的一个元素;可以是一个结构体;
读:
size_t fread ( void *buffer , size_t size , size_t count , FILE * stream);
// buffer:从文件指针所指向的文件中读取数据块并存储到buffer指向的内存;即数据块首地址。
size : 每个数据块的大小,单位为字节;
count : 读入数据块的个数
返回实际读入的数据块个数,正确时大小等于count;到达文件末尾或出现错误则不等于count;
写:
size_t fwrite ( const void * buffer , size_ t size, size_t count, FILE * stream ) ;
// 将buffer所指向的内存中的数据块写入fp所指的文件,buffer时数据块的首地址;
size为每个数据块的大小;count为数据块的数量;返回实际写入的数据块的个数,成功则等于count;
文件的随机读写:
函数:
void rewind( FILE * fp ) ; // 使文件位置指针重新指向文件的开始位置。
long ftell ( FILE * fp );// 返回当前指针所指位置的偏移量
int fseek ( FILE *fp , long offset , int fromwhere ) ;
//改变文件位置指针,实现随机读写。
注意offset必须为long类型,若为其他类型须强制转换,常量则后缀加L。
fromwhere有三个值SEEK_SET或0,表示文件开始的位置。
SEEK_CUR或1,表示文件的当前位置。
SEEK_END或2,表示文件的末尾位置。
动态内存分配:
分配:
void * malloc(unsigned int size); //分配size大小的内存空间
void * calloc( unsigned int num, unsigned int size ) ; // 分配num个size大小的内存空间;与malloc不同,会将 分配的地址初始化为0。
void * realloc( void *p, unsigned int size); // 改变原来分配的存储空间的大小;将p所指向的存储空间的大小 改为size个字节,返回值为新分配的存储空间的首地址。
void *使用时需使用强制类型转换(Type*)
释放:
void free(void * p ); // 释放由malloc和calloc申请的内存块,p为指向这块内存的指针;free时系统将此 块内存标记为未占用,可被重新分配。