- 编译时错误:语法错误error
- 运行时的错误:warning
- 逻辑错误:程序没有达到你想要的结果
- 算法:零个或多个输入,一个或多个输出,有穷性,确定性,有效性
- 要求:正确性,可读性,健壮性(防止崩溃),高效率和低存储量的需求。(可扩展性)
- 表示方法:用自然语言表示算法(如,汉语),用流程图表示算法,用伪代码表示算法,用计算机语言表示算法
- 编码规范:每个语句单独一行,缩进,空行,命名可读性,注释,函数数据
- 如何缩进和空白:1,在#include和程序之间加空行。2,变量的定义之后加空行,在return之前加空行。3,代码的每个逻辑段落之间加空行。4,双目运算符两侧加空格。5,逗号和分号后加空格。6,要用缩进体现语句块之间的层次关系。
- 如何写注释:1,可以单行注释,也可以多行注释。2,文件的顶部要注释,说明文件的一些信息。3,函数要注释,说明函数的功能,函数创建者等信息。4,对代码的注释可以写在代码行的后面,也可以写在逻辑段落的上面,中间不加空行。
10.标识符的命名:1,命名要清晰明了,见名知义,可以用完整的单词和易于理解的缩写。2,要遵守苹果的命名规范:标识符用驼峰命名法。3,禁止使用汉语拼音作为表示符的名称,全部用英文。
11.十进制转换成二进制:除二反序求余。除八,除16。
12.二进制每三位合成一位,前面加0,转成八进制。四位合成一组,前面加0x,转换成16进制,abcdef。x小写,后面的也小写,前面的大写,后面也大写。
13.指针pointer,数据类型的一种,存储内存中的地址。unsigned char。共用体Untion。空类型,void,对函数返回值或者参数的限定。指数形式,5.3E2
14.可以在常量后面加限定符如:93628746827683UL,unsigned long ,%lu
15.默认double %lf,6.6F float%f, 6.6L多精度浮点型%Lf必须用大写。
16.hhh,八进制,xdd十六进制。
17.字符型常量可以直接进行算数运算,以ACSCII值
18. 不可见字符,“sfii”,其实后面有个 ,常用在字符串之后,它的ASCII就是0。
19.1byte(字节)=8 bit。
20.小端,地址是小的那个,大端
21.赋值。初始化(比赋值好)。
22.有符号32767,,无符号65535 short二的十六次方减一 默认有符号(-32768最高位既是符号位,又是数据位)。
23.127,255 char 二的八次方减一 有无符号无明确规定,视编译器而定,gcc默认有符号。只占一个字节。
24.char 8 short 16 int 32 long 64 longlong 64 指针64(指针跟cpu有关)。
25.浮点型以指数形式存储。
26.指针的四个重要概念:int a = 5; int*p = &a;1,指针的类型(int)。2,指针所指向的类型(int 四个字节),a的地址,printf(“a = %p”,p)。3,指针的值()。4,指针本身占据的内存区(定义p时分配给它的空间,八个字节)printf(“p = %p”,&p),指针p的地址。
27.sizeof计算出后面的参数占多少个字节。只看类型,不会运算求值的。编译期就能得到结果,不是在运行期。
28.隐性类型转换,强制类型转换
29.取余%,只能用于int类型。
30.短路求值:m=5;n =!m||m++;此时,m还是5,把它短路了。
31.逗号运算符是c语言优先级最低的运算符,最高的是()。
32.& 取址运算符,对象为变量,结果为对象地址。
33.* 指针间接寻址运算符(解引用),对象为指针,结果为:指针变量所保存的内存地址当中的内容。
34.指针声明符,解引运算符。
35.*p,*(p+1),前面是指针,后面也是指针。如果(int)*p,则p++或*(p+1)指向的地址加四,(*p)++,就是a++,a是p指向的内容。
36.野指针,当指针指向的内容是我们没有权限访问的时候,我们通过指针间接访问会报段错误:segmentation fault。(最好不要出现随机指针)
37.NULL==0;宏定义。可以int *p = NULL;避免野指针的错误。
38.格式化输出函数printf (可以用man命令man 3 printf ,q推出)。其中有:普通字符,占位符,转义字符。空位,默认右对齐;左对齐,加-号 %-5.3f 占五位空间,保留小说点后三位。%E 以指数形式打印。
39.scanf 尽量避免使用过多格式,用空白字符(空格,tab,回车)作为分割。
40.如果使用非空白字符,则输入必须按照原样输入,包括 , 等
41.scanf有返回值,返回值是有效数据的个数;
42.当遇到%c时,空格字符也是有效字符
43.int putchar(int c);int getchar(void);char ch = getchar();
44.选择结构:单分支,多分支。嵌套,注意使用括号,以便配对
45.如果加了其他函数库,gcc 名.c –lm。上一步,command+z
46.switch,case后必须为可精确进行比较的int和char类型的常量。或者整形常量表达式:’a’ +1,但不能重复。浮点型不能判断是否相等。
47.break和default一定要写。
48.能够使用switch就用switch,它的效率比if的要高。
49.循环结构:循环条件和循环体。
50.while和do while差别就在第一次执行程序是假的情况。
51.for循环。主要用于循环次数已知的循环,i 就是循环控制变量。不要在for循环内部修改循环变量;
- 数组:一维数组,二维数组。
53.数组时最基本的构造类型,是一组相同类型数据的组成。数组,名和下标, C89,下标必须是常量。C99,下标可以变动,变长数组,不建议使用。
54.通过下标来访问数组,单个数组元素。数组一经定义,就不能对其整体操作,只能一个一个的访问里面的元素。
55.一个数组名不能作为左值。
56.数组只有初始化的时候才能用{}赋值。
57.数组的初始化:全部元素初始化,未赋值的直接是0,int a[12] = {1,12,25,2,12,}。
58.全部数组初始化,可以省略数组长度,但最好不要。
59.验证数组个数,sizeof(c)/sizeof(int); 验证数组连续排布,打印地址。
60.数组,一定要尽量避免越界问题。编译器不会提示这个问题,暂时可能是对的,但以后可能会出错,非常危险。
61.随机数,rand()包含stdlib 每次取,默认是一,其实是假随机数。
62.设计种子srand(time(0或者null))time.h。真随机数。
63.二维数组:一个数组的元素是另外一个数组。a[3][4],3行4列,外数组3个元素,内数组4个元素。所有元素地址都是连续的。其实,编译器也是把二位数组看成一维数组。数组名[行下标][列下标]
64.初始化,如果内部数组没有{},则顺序初始化。
65.行长度可以省略,列长度不能省略,也就是只能省略第一个下标。
66.一维数组和指针
67.数组名a可以看作一个指针,它的值是数组首元素的地址&a[0],其类型是数组元素的类型。数组名没有自己的内存地址,跟指针不一样。
68.sizeof(a),&a 这两种情况下,不代表指针
69.数组名作为右值,即使指向数组首元素的地址;
70.数组名不能作为左值;左值必须是可以修改的;
71.地址就是指针
72.解引操作和下标操作完全一样。
73.*和&可以抵消。*&p == p;
74.指针也可以进行下标操作。
75.当两个指针指向同一个数组,两指针可以进行比较操作和相减操作, 相减结果是中间相差元素的个数,不是直接地址的相减。
76.遍历整个数组。
77.int a[5],int *b, *a对 *b错 a++错 b++对。
78.字符数组。
79.“happy ”,最后的 看不见。
80.char str[] = {‘a’,’s’,’ ’}。char str[] = “as”。char *ps = “as” 前两者一样,跟第三者不一样,第三个表示一个字符串常量。第二个表示一种初始化的方式,第三种表示一个字符串常量
81.strlen这个函数求得是字符串或者字符数组或者自负指针指向字符串的长度,到’ ’结束,长度不包括’ ’。<string.h>
82.sizeof是个运算符,求得的是表达式的数据类型在内存中所占的字节数。
83.%s输入输出时遇到’ ’,也结束。
84.越界。
85.拼接strcat。
86.函数:
87.mian函数的参数,只有两种情况:int main(void)。 int main(int argc, char *argv[])
88.main函数的返回值,给操作系统来看,如果正常退出,返回值是0,不正常退出,返回值非零;可以通过shell查看退出状态,命令是 echo $;
89.函数的原型,函数的定义,函数的声明
90.函数的定义:编译器只有看到函数的定义才会生成指令,程序运行时才会分配内存,带{}和其中的内容
91.函数的声明:
92.隐式声明:如果没有声明,默认生成。根据这个函数调用时传递过来的值来确定其参数类型,返回值默认是int。声明:在main函数之前,在调用之前!!!进行函数的声明。给编译器提供有用的信息,函数名,返回值类型,参数类型和;。
93.函数的原型:void yaHua(void) 方法和声明都提供函数的原型。
94.形参:名称(可省略),形参类型,形参个数。调用时类型不用写,实参类型,个数一定要对(严格一致)。
95.实参唯一作用就是给行参初始化,形参实参占据不同内存存储区,形参无法改变实参。
96.栈桢
97.局部变量:函数内部,生存周期是当前函数结束时。不同函数中可以定义同名的局部变量。行参也是
98.全局变量:在头文件下边声明,定义在函数外,生存周期,从定义开始,到程序结束。作用域:整个程序,所有函数都能调用,静态存储区。如果没有初始化,程序开始时,系统自动赋值为零
99.就近原则,有同名局部变量,就会暂时屏蔽全局变量。
- 静态的局部变量,static int main 。分配在静态存储区,生存周期和全局变量一样。作用域还是当前函数,初始化只有第一次,以后都不再初始化,按照上次运行后的结果计算。
- 静态全局变量:生存周期不变,作用域:仅在当前文件中有效。佛则可以在整个项目中所有文件使用。
- 静态函数 static void fun(void):限制函数仅在当前文件中有效。方便多人开发。
- 能用局部变量,不要用全局变量,所有函数都能访问全局变量,因此很容易出错,出现bug很难查找,并且,占用内存;
- 返回值:
- 函数无返回值,也可以用return退出函数。
- 有返回值,但没写return,则返回不确定值,非常危险。
- 返回值交给临时变量,临时变量在main函数中起作用
- 返回值要么是0要么是1的函数,在程序中通常充当控制表达式,函数名以is开头, 谓词
- 指针类型参数:不要返回指向已经释放的指针0。
- 数组作为函数参数:
- 数组作为函数参数,编译器自动将其转化为一个指针,原因:传递一个数组耗费大量时间和空间,效率低。数组元素在内存中是连续的,只要知道第一个元素的地址,其他元素就可以访问到。
- 当用函数对一个数组进行操作时,需要传递两个参数,一个是元素的首地址,一个是数组元素的个数。
- void array(int b[10]); sizeof(b) = 8/4看是32位还是64位。
- 在函数行参中,数组就是指针。
- 多文件编译:头文件、预处理
- 使用头文件的好处:1,当某一个函数声明需要修改时,只有头文件需要更新,不需要一个个修改原文件。2,可以保证所有源文件都使用头文件中的同一份声明。
- 源文件:具体怎么实现的,头文件只是一个接口。
- 头文件中不要定义函数,只有函数的声明,否则会duplicate 重复定义
- 声明可以多个,定义只能一次。
- 预处理 :以#开头的指令 -E:展开宏定义,添加行号和文件标示,把用’’开头的多行代码拼接成一行(第二行顶头写),删除注释,替换成空格。
- gcc -E 1.c -O 1.i 预处理 (出现两个框)。
- 宏定义:变量式宏定义,不带参数的宏。宏名全部一般大写。#define PI 3.1415626。只是符号替换,增加可移植性和可读性。在其他文件中不能用,不要加; 宏定义中还可以用之前定义的宏名。
- 函数式宏定义,带参数的宏定义。每一个参数都加上(),外面再加上一个(),使用宏,很容易产生歧义,比如num++。
- 缺点:容易产生歧义,所以尽可能的加()来避免歧义。只是简单的字符替换,不会进行类型检查。如果参数是一个带有副作用的表达式,比如num++,宏的副作用并不是发一次。
- 优点:不需要传参,传返回值,分配和释放栈桢,效率较高。对于代码量较小,频繁被调用的函数,可以用函数式宏定义来替换。
- #undef。。。,,,#12345,#后面的自动转为字符串。1##2##3 自动合并为123.宏最好写在头文件中。
- 文件包含#include<库文件> ”自定义文件”。现在当前目录找,如果没找到,再去系统文件的头文件目录去找。可以包含.c文件,但一般不会这么做。支持相对路径,允许嵌套。
- 条件编译
- #ifdef MAX
- …..
- #else
- …..
- #endif
- 软件的调试版本DEBUG和发行版本RELEASE的控制。version版本
- 防止重复包含头文件
- #define V 2
- …
- 结构体
- struct student
- {
- int number; 成员 或者 成员变量
- char name[20];
- char sex;
- int age;
- }s1,s2;
- 写在头文件下面
- int main(void)
- {
- struct student s3;
- struct student s4;
- return 0;
- }
- s1;s2;全局变量。。s3;s4;局部变量
- 1,数组元素要求同一类型,结构体的成员不要求同一类型。
- 2.定义类型的时候不分配内存。定义变量的时候再分配内存,内存是所有成员所占内存之和。
- 3,成员访问操作符;s1.age = 20;
- 4,{ }只能在初始化的时候使用,赋值只能用成员访问操作符。
- 5,数组一经定义以后就不能进行整体访问,只能访问里面的元素。
- 结构体变量可以进行整体赋值,相当于把s1中所占内存全部复制到s2所占的内存中。(一般,只有整体赋值时才会整体操作)
- 6,在内存中起始地址 %p &s1或者&s1.number如果number是字符串,不用取地址了s1.name。
- 7,第一个字母大写!!
- 结构体指针:p->,(*p).,
- 结构体数组
- typedef:起别名,只是给已经存在的类型起个名字。
- 应用场合
- 1,基本数据类型
- 2,指针
- 3,结构体
- 4,枚举
- 5,函数指针
- 作用
- 1,给某个类型起一个代表某个含义的别名,表示某一类特定用处的变量。
- 2,简化复杂类型书写
- 3,方便程序的移植
- #define 只是简单符号替换;预编译期。typedef先生成类型 ,再用这个类型,去定义变量。编译期
- 内存对齐:牺牲一点内存空间,但提高了性能。合理调节结构体变量顺序,可以节省空间
- 联合体
- union data{ int i;float f}
- 内存是最长的占的内存,记录的是最后的值。
- 枚举
- enum weekday{。,。,。,。}day;
- 当变量只是取某些固定的值,增加可读性。
- 枚举常量:默认值是从0开始,以后每个枚举常亮自动加一,枚举常量的本质就是int
- 弱语法,一般不会报错,取值只好在枚举常量范围内,不要去其他值。
- 内存的动态申请和释放
- void*malloc(size_t size)
- 在堆中申请;
- void*free(void*p)释放p指向的内存,释放不是清零,而是不能操纵了,释放之后
- p = NULL;
- if(NULL == p){…};
- free(p)
- 通用类型指针(空类型指针)一般用在内存接口。
- void*p = NULL 8字节
- 其他类型指针可以直接转化为void*,不需要强制转换,反过来也可以GNU体系,ANSI标准,要强转。
- 不能*p = 1;不能对空类型指针解引用操作;
- p++也不行(ANSI不允许)(虽然GNU可以,它等同于char*)
- 我们在真实设计时,尽量遵从ANSI。
- malloc和free一般配对使用。当我们想用指针去间接操纵内存,我们要先看看我们是否有这个权限。#include<stdlib.h>。
- 栈内存自主释放,堆内存不会。
- 链表:数据域,地址域。
- 地址可以强转成指针。
- 二维数组名是一个指向一维数组的指针。
- 指向指针的指针。函数指针(能看懂语法)。
- 文件:一种相关数据的集合。
- 文件名:这个数据集的名称。
- 数据 -文件-内存。
- 文本文件cat od -tx1 -tc -Ax 1.txt。二进制文件:.c .i .s .o(二进制文件)。
- std err in(读) out stdio.h。IO操作
- stdin(读写) stdout(读写) stderr(读写)。
- 文件指针的定义,打开文件,文件的读或者写,文件的关闭操作。FILE *fp = NULL; 结构体变量。FILE *fopen(const char *path, const char *mode)。返回值:NULL或指针。
- r (读),r+(读,写), w(先清零(替换原内容),再写,如果没有,自动创建), w+(读,写), a(追加,如果文件不存在,创建), a+(读和追加),
- exit(1) = return 1;stdlib.h
- 只读要保证文件存在。
- int fclose(FILE *fp),正常返回0,异常返回EOF(-1)
- 有打开就有关闭。关闭之后,不能再做操作。
- #ifndef errno extern int errno; #endif。
- perror(const char *);会把错误码解释成字符串输出,方便调试和定位。
- 以字节为单位int fgetc(FILE *stream);读,返回读到的字节,或者EOF(出错或者文件结束)。文件的打开方式必须是可读的。
- int fputc(int c, FILE *stream)。c:写入的字节,stream:文件指针。打开方式必须可写,包括追加。putchar
- 以字符串为单位:
- char *fgets(char *s, int size, FILE *stream);
- s:缓冲区首地址
- size:缓冲区的长度;
- 返回地址或NULL;
- 都到 结束,并在结尾加上 ;
- 不适合读二进制文件,因为遇到 认为是普通字符;
- int fputs(const char *s, FILE *stream)
- 返回写入的字符数和EOF,遇到 结束。不写入
- size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)二进制文件
- ptr缓冲区首地址
- size:一块数据块所占的字节,
- nmemb:数据快的个数,
- 返回nmemb或者小于nmemb或者0
- fwrite(const void *ptr)….
- 返回值也一样。
- int fprint(FILE *stream, const char*format…)
- int sprintf(char *str, const char *format..)
- int snprintf(char *str, size_t size, const char*format…)
- int fscanf(FILE *strem,const char *formt…)
- int sscanf(const char *str,const char *format,…)
- 文件的读写位置指针:
- int fseek(FILE *stream, long offset, int whence)
- long ftell(FILE *stream)返回位置指针当前所在位置,如果出错,返回-1
- void rewind(FILE *stream)移动到开头
- SEEK_SET开头
- SEEK_CUR当前位置
- SEEK_END结尾
- IO缓冲区buffer
- file -》 buffer -》 date
- (IO)buffer必须写满,才会输送到date中去。
- 全缓冲:常规文件(写满才输出)
- 行缓冲:加个换行符就会输出
- 无缓冲:stderr
- 程序退出退出之前,都会输送到date
- fflush(FILE *stream)清空文件缓冲区
- fflush(stdout)
- fflush(NULL)对所有打开的文件缓冲区做flush操作
- 位运算
- 以bit为单位处理
- 位运算操作数必须是整数。
- 对有符号位进行位运算,很容易出错,尽量避免位操作。对于无符号数可以进行位操作
- 掩码mask
- 对某些位或某一位取反,异或0还是原数,异或1原数取反。 与本身异或是0。
- 在函数内申请内存,在函数外使用
- 1,函数返回值进行传递,传递申请堆内存的地址。
- 2,二级指针作为函数参数,在函数内部对二级指针指向的内存(一级指针)进行改变。