基础
1. C语言默认的函数返回值是int, 而c++中没有这个规定,必须显示写函数返回值,即使是void
2. 1. c语言中的整数类型有char, short, int, long等几种, 下面是C语言对每种数据类型长度的规定:
(a). short和long类型的长度不相同
(b). int类型通常同具体机器的物理字长相同
(c). short通常是16bits, int通常是16bits or 32bits每种编译器可以根据硬件的不同自由确定, 但是short和int必须最少是16bits, 而long类型必须最少是32bits, 并且short必须比int和long类型要短。
3. C++中的数据类型
1、字符型数据char,该类型始终是一个字节长,即8位。
2、整形int、短整型short和长整形long。通常int为一个字长,short为半个字长,long为一个或2个字长(在32位机器中为一个字长)。
3、浮点型float、双精度double、和长双精度long double,分别表示单精度浮点数 双精度浮点数和扩展精度的浮点数值。典型情况下,float 为一个字,double是两个字,long double为三个或四个字。
4. float与double都以%f输出 %0.f表示不要小数部分
5. 学习C语言,在d:/dev_projects/testc中建立C工程 C盘下turboc下codes
6. int c = getchar(); putchar(c); 由于判断是否EOF,所以c要大一些,用int
7. UNIX下运行cc hello.c 生成hello.out , 直接运行hello.out就行
8. 函数的默认返回类型为int,如果返回int,则可省略int
9. 在函数外面定义的是外部变量,函数里面要使用首先要extern声明一下
10.void copy(void); ANSI C语言中,如果声明空参数表,则必须使用void
11.关于extern : file1中定义的变量 在file2中使用要加extern声明
一般地,把变量和函数的extern声明放在头文件中
12.定义:表示创建中分配存储单元; 声明指说明变量的性质,并不分配存储单元
13.变量名
a) 下划线_被看成是字母,一般用于命名长度较长的变量名,提高可读性
b) 局部变量短一些,外部变量名长一些
14. short通常16位,int通常16或32位,long通常32位
short和int至少16位,long至少32位,int <= long, short <= int
有关这些类型长度定义的符号学号以及其他与机器和编译器有关的属性可以在标准头文件<limits.h>和<float.h>中找到
long = 23L; 如果没加L且值太大超过int容量也被当long值处理
一个字符常量是一个整数 用’0’代替48就增加了可读性,不用关心具体值
通过转义字符序列表示为字符和字符串常量
转义字符序列看起来像两个字符,却是一个字符:’\ooo’:一到三个0…7数字, ‘\xhh’:一到多个0…9, a…f, A…F
#defineBELL ‘\007’ /* ASCII响铃符 */
‘\0’表示值为0的字符,也就是空字符NULL或null
常量表达式在编译时求值
字符串常量也叫字符串字面值 “hello”, 双引号不是其中一部分,只是限定字符串
‘x’是一个整数,其值是字母x在机器字符集中对应的数值;”x”是一个包含字母和’\0’的字符数组
15. leap year: if ((year % 4 == 0 && year % 100 !=0) || year % 400 == 0)
16. 非自动变量只进行一次初始化操作,在编译阶段。 默认情况下,外部变量和static变量被初始化为0.
自动变量在每次进入函数或程序块时要显式初始化一次,初始化表达式可以是任何 表达式。
任何变量的声明都可以用const进行限定 const数组的元素值都不能改
%不能用于double和float
将字符转换为整数要注意,C没规定char类型的变量是无符号还是带符号变量,所以当把一个负char变量的值转为int类型时,结果有可能是负也有可能是正
带不带符号是与机器相关的,为保证移植性,在char中存放非字符数据最好指定signed或unsigned
二元运算如果没有unsigned,则按如下转换:
è long double
è double
è float
char, short-> int
è long
注意:表达式中float类型不会自动转换为double类型
如果表达式中含有iunsigned时,转换规则要复杂:因为与机器相关
如果int16位,long32则,-1L > 1U ,此时,int的1U提升为singedlong, 但-1L> 1UL, 此时singed long的-1L提升为unsignedlong,变成大整数
无论是否进行符号扩展,字符型变量都将被转换为整型变量
float -> int 小数部分截掉
double ->float 小数部分进行四舍五入还是截取取决于实现
关于函数原型:函数原型类似函数定义时的函数头。为了能使函数在定义之前就能被调用,C++规定可以先说明函数原型,然后就可以调用函数。函数定义可放在程序后面。系统标准函数并没有在包含文件中定义,而只是提供了函数原型。在调用函数时,系统会正确地调用库函数。
注意:函数原型与函数定义必须一致,否则会引起编译错误。如果函数是单独编译的,则这种错误就无法检测出来
在没有函数原型的情况下,参数传递中,char与short类型都被转为int, float转为double,所以,这种情况下,最好把参数声明为double或int
有一个实现伪随机数发生器的函数rand以及一个初始化种子数的函数srand,前一个函数用了强制类型转换 return (usigned int)***
int rand(void );
void srand(unsigned int); // 设置种子数
17. 运算符优先级:
-> . 大于! ++ * (强制转换) sizeof ~
18. 一个程序可以保存在一个或者多个源文件中,各个文件可以单独编译,并可以与库中已编译过的函数一起加载。这一过程的具体实现因编译器不同而异
19. cc main.c file1.c file2.c
如果main.c有错,则 cc main.cfile1.o file2.o
20. 对于空参数,新程序不提倡func(),而写成func(void);
21. 外部变量和函数的作用域从声明它的地方开始,到其所在的文件的结束
如果要在外部变量的定义之前使用该变量,或者外部变量的定义与使用不在一个源文件中,则必须在相应的变量声明中强制使用extern ,不须要include包含进来
只能定义一次,其他文件中要使用要extern声明。定义时必须数据指明长度,而extern中不用指明长度
22.关于extern 详述已存在QQ日志中。共三条作用
a) 最重要的作用:隐藏
未加static前缀的全局变量和函数都具有全局可见性,另一个文件中只要extern 声明一下这个变量就可以用,函数可以不用extern就可以用的
加上static以后,全局变量和函数就只能限于当前文件中可见了,对于函数来讲,static的作用仅限于隐藏,对于变量,还有持久性和默认0
b) 保持变量内容的持久, 存储在静态数据区的变量会在程序刚开始运行时就完成初始化(使用常量表达式初始化),也是唯一的一次初始化。共有两种变量存储在静态存储区:全局变量和static变量,只不过和全局变量比起来,static可以控制变量的可见范围,定义在函数内的static变量与同文件中的同名全局变量来讲,是局部隐藏,同样是持久性
c) 默认初始化为0
比如初始化一个稀疏矩阵,我们可以一个一个地把所有元素都置0,然后把不是0的几个元素赋值。如果定义成静态的,就省去了一开始置0的操作。再比如要把一个字符数组当字符串来用,但又觉得每次在字符数组末尾加‘\0’太麻烦。如果把字符串定义成静态的,就省去了这个麻烦,因为那里本来就是‘\0’
23. int sum_array(int a[static 3], int n) 将static放在数字3之前表明数组a的长度至少可以保证是3
只不过是一个"提示",C编译器可以据此生成更快的指令来访问数组。(如果编译器知道数组总是具有某个最小值,那么它可以在函数调用时预先从内存中取出这些元素值,而不是在遇到函数内部实际需要用到这些元素的语句时才取出相应的值。)如果数组参数是多维的,static仅可用于第一维(例如,指定二维数组的行数。)
24. #include “”在当前位置查找,#include <>根据相应规则查找,跟具体实现有关
25. C预处理
#define作用域是当前文件
宏定义中也可以使用前面出现的宏定义
字符串中的字符不进行替换
#define占一行,续行使用\
为了省去函数调用所需的运行时开销,常常将函数定义为宏 取消它:#undef getchar
形参不能使用带引号的字符串替换,参数名以#作前缀则把实参转为该参数的带引号的字符串
##是用于连接两个参数的
#if!defined(HDR) 或#ifndef
...
#endif
#if中不能使用sizeof(),因为预处理器不对类型名进行分析
26. 几个头文件
NULL定义在#include <stddef.h>中
malloc定义在<stdlib.h> 它参满足对于不同类型对象的不同大小的对齐要求 返回void *保证能返回不同类型指针,强制转换一下就可以
EOF<stdio.h> 一般为-1
27.打印命令行参数
for (i = 1; i < argc; ++i) {
printf("%s%s", argv[i], (i <argc-1) ? " " : "\n");
}
或
while (--argc> 0) {
printf(“%s%s”, *++argv, (argc > 1) ? “ ”: “\n”);
}
printf的格式化参数也可以是表达式: printf((argc > 1) ? “%s” : “%s”, *++argv);
28.算维数的宏: #define dim(arr) (sizeof(arr) /sizeof(arr[0]))
29.关于union联合体:
union u_tag {
int ival;
float fval;
chart *sval;
} u;
u必须足够大,以保存这三种类型中最大的一种
这些类型中的任何一种类型的对象都可赋值给u,读取的类型必须是最近一次存入的类型,程序员负责跟踪当前保存在联合体中的类型,如果读取类型与存入类型不一致,结果取决于具体实现。联合体只能用第一个成员类型的值进行初始化。上述u能能用int值进行初始化
30.输入输出
文件流由一些行组成,每行尾是一个换行符
getch()、getche()和getchar()以及gets函数
(1) getch()和getche()函数 : 前者不回显,后者回显 利用回显和不回显的特点, 这两个函数经常用于交互输入的过程中完成暂停等功能
main函数最后一行:getch(); /*等待输入任一键*/与system(“pause”);一样
C语言中getch以及上面其他两个都在<stdio.h>,C++中getch在#include<conio.h>中
再啰嗦一下getch的废话:可以用它来实现“按任意键继续”的效果,即程序中遇到getch();这行语句,它就会把程序暂停下来,等你按任意键,它接收了这个字符键后再继续执行后面的代码
(2)getchar等待输入直到按回车才结束, 回车前的所有输入字符都会逐个显示在屏幕上。但只有第一个字符作为函数的返回值。
(3)gets(str)从stdin流中读取一行到str中,直至接受到换行符或EOF时停止,换行符被删除,附上’\0’作为字符串结束符
puts(str)将str输出到Stdout上,并在末尾加上换行符
下文的文件访问中,会提到与它们类似的函数fgets与fputs
(4)int putchar(int): 返回输出的字符,如果发生错误,则返回EOF 。 同样可以使用>将输出重定向到某个文件中
(5)<stdio.h>中的getchar和putchar以及<ctype>中的tolower函数,一般都是宏,避免调用开销
printf()
l 负号:左对齐
l h作short打印, l作long打印
l %d或%i
%o 无符号八进制数(没有前导0)
%x或%X 无符号十六进制(没有前导0x或0X)
%u
%c
%s char *, 遇到’\0’或已打印了由精度指定的字符数为止
%f double, 默认6个小数
%e或%E double,m.ddddde+xx d的个数由精度指定,默认6
%g或%G double,如果指数小于-4,大于精度,则以%e或%E输出,尾部的0和小数点不打印,否则以%f
%p void *
%% 打印一个百分号
小数点前叫宽度,小数点之后叫精度
宽度或精度可用*表示,它的值通过转换下一参数(必须为int)来计算,例如:
printf(“%.*s”, max, s); max是int的数
%-15.10s 是十五宽度,最多打印10个字符,且左对齐
printf(s); 如果s中有%则出错
printf(“%s”, s);// ok
int sprintf(char*string, char *format, arg1, arg2, ...); 把输出结果放到string中
31. 关于变长参数表./testc/funcs/minprintf.c
int printf(char*fmt, ...);
int scanf(char*format, ...);
关于scanf的说明:
1) 其他参数都是指针——存放地址
2) 扫描完格式串,或者遇到无法匹配的情况时终止
3) 返回成功匹配的个数,如果返回0说明与第一个格式不匹配。如果到达文件尾,则返回EOF
4) 下一次调用scanf将从上一次转换的最后一个字符的下一字符开始继续搜索
int sscanf(char*string, char *format, arg1, arg2, ...);
说明:它按照format中的格式扫描string,并把结果存在arg1, arg2, ...中,这些参数必须是指针
scanf基本转换说明:
a) d: 十进
b) i: 十进制,八进制(以0开头),十六进制(0x开头)
c) o: 八进制(可以不以0开头)
d) x:十六(可以不以0x开头)
e) u:无符号十进制
f) c:将接下来的多个字符比如%8c存入到指定位置,该转换规通常不跳过空白字符。如果需要读入下一个非空白字符,使用%1s
g) s: 指向一个足以存放该字符串+’\0’的char *, 字符串的末尾被添加一个’\0’
h) e, f, g: 浮点数
i) %: 字符%,不进行任何赋值操作
scanf("%d/%d/%d", &m, &d,&y); 读入mm/dd/yy没错 转义符是\而不是/
scanf忽略格式串中的空格和制表符,在读入时,将跳过空白符(空格,制表符,换行符)
32. 文件访问
FILE *fp; // FILE在<stdio.h>中定义
FILE *fopen(char*name, char *mode); // mode: r w a追加
如果打开一个不存在的文件用于写或追加,该文件将被创建(但是name中是一个相对路径,且含有一个没有创建的文件夹时,它会出错,不会自动创建文件夹),当以写方式打开一个已存在的文件时,该文件原来的内容将被覆盖。读一个不存在的文件将会出错,或读一个没有读权限的文件也会出错。如果发生错,则返回NULL.
打开文件后,通过getc和putc对文件进行读写最简单
int getc(FILE *fp); 返回fp指向的下一个字符,如果到达文件尾或出现错误,则返回EOF
int putc(int c, FILE *fp); 写入到fp中,并返回写入的字符。如果发生错,则返回EOF。
上面这两个也是宏,而不是函数
关闭文件int fclose(FILE *fp);
启动一个C程序,操作系统打开三个文件,并将这三个指针交给程序,它们是stdin, stdout, stderr。它们在<stdio.h>中声明,在大多环境中,stdin指向键盘,后两个指向显示器。可以重定向到文件使用<或>.
getchar putchar可定义如下:
#define getchar() getc(stdin)
#define putchar(c) putc((c), stdout)
示例:test_fopen.c p142_filecopy.c
补充说明:exit(1);会终止调用程序的执行,任何启用该程序的进程都可以获取exit的参数值。因此,可以通过另一个将该程序作为子进程程序来测试该程序的执行是否成功。非0说明异常。exit为每个忆找开的输出文件调用 fclose函数,以将缓冲区中的所有输出写到相应的文件中.在main中,return 等同于exit。使用Exit的好处还有一个,就是它可从其他函数中调用。feof与ferror类似int feof(FILE *fp),如果到达文件末尾,则返回一个非0值
对文件的格式化输入和输出
int fscanf(FILE*fp, char *format, ...);
int fprintf(FILE*fp, char *format, ...);
行输入与行输出 原代码./funcs/fgets.c fputs.c getline.c
char *fgets(cahr*line, int max, FILE *fp);
与getline类似
从fp指向的文件中读入下一行,包括换行符,并以’\0’作为字符串结束,即最后两个字符是’\n’与’\0’。最多读max-1个字符
返回值:通常返回line,如果遇到EOF且读入失败(根本就一个字符都没读到),则返回 NULL。
int fputs(char*line, FILE *fp);
写入到fp中,line不需要包含换行符
返回值:发生错误则返回EOF,否则返回一个非负值
gets与puts是对stdin和stdout进行操作,gets在读取字符串的时候将删除换行符,而puts在写入字符串时,将在最后添加一个换行符
33. <string.h>
strcat(s, t)
strncat(s, t, n)
strcmp(s, t)
strncmp(s,t,n)// 只与前n个字符进行比较
strcpy(s,t)
strncpy(s,t,n)
strlen(s)
strchr(s,c) // 在字符串s中查找c,若找到,返回第一次出现的位置指针否则返回NULL
strrchr(s,c) // 查找c,若找到,返回最后一次出现的位置指针
34. <ctype.h>
isalpha
isupper
islower
isdigit
isalnum
isspace 空格,横向制表符,纵向制表符,换行,换页,回车
toupper
tolower
35. int ungetc(int c, FILE *fp)
将c写回到fp中,成功返回c,失败返回EOF。 每个文件只能接收一个写回字符。它可以与任何一个输入函数一起使用,如scanf,getc,getchar
36. 存储管理
void*malloc(size_t n);
void*calloc(size_t n, size_t size); 返回一个指针 ,该指针指向的空闲空间足以容纳由n个指定长度的对象组成的数组。否则返回NULL。此数组初始化为0
free(p)
典型的错误:
for (p = head; p!= NULL; p = p->next) {
free(p);
}
改为
for (p = head; p!= NULL; p = q) {
q = p->next;
free(p);
}
37. <math.h>
sin cos atan2(y,x) : y/x的反正切,其x与y用弧度表示
exp: 指数函数ex
log(x) : 以e为底,自然对数, x > 0
log10
pow
sqrt
fabs
38. 随机数生成
rand成生介于 0与RAND_MAX间的伪随机整数序列 // RAND_MAX 在<stdlib.h>
#define frand()((double) rand() / (RAND_MAX + 1.0))
39.附录
a) 标志符可以是任意长度
b) 与具体实现相关的限制:limits.h float.h
c) 日期时间函数time.h
d) stddef.h中指针相减ptrdiff_t类型
e) auto与register声明自动类型的对象,仅用在函数中,声明的同时也是定义,分配了空间。后者说明会被频繁的访问,但是只有很少的变量被真正存放在寄存器中,并且只有特定类型才可以,与具体实现有关。register变量不能用&取地址操作符,即使它不是一个真正的寄存器变量。
40.d
41.