C语言个人精要

计算机编程基础概念

1. 补码的计算

  • 正数和负数在计算机中的存储都是以二进制的形式。对于正数,直接存储其二进制表示;对于负数,则需要取补码的形式存储。
  • 负数在计算机中的存储最高位表示符号(1:负数,0:正数)。

1.1 反码与补码

  • 原码:1000 1000(符号位不变其余位按位取反)
  • 反码:1111 1001(反码+1)

1.1.1 示例

  • 给定 a = -60,则:
    • (~a) + 1 等于 -61,即为 1100 0001(带符号二进制数的补码形式)。

2. 函数声明优化

  • 在函数声明中,参数的名称并不是必需的,只有参数的类型是必需的。因此下面也是有效的声明:
    1
    int max(int, int);

3. 先声明后使用

  • 为了不出问题还是先声明好,或者就写在 main 之前。

4. 编译器问题

  • 没有特别说明。

5. 数组作为参数传递时

  • double getAverage(int *arr, int size):在函数中可以通过指针访问数组元素,如 sum += *(arr + i);sum += arr[i];

6. 随机数

  • srand(unsigned int seed) 是初始化随机数生成种子:
    1. 如果当前系统时间作为种子,由于时间是变化的,种子不同,可以产生不同的随机数。
    2. 计算机中的随机其实不是真正的随机数,如果两次给的种子一样,会生成同样的随机数列。所以,一般会结合不同的时间作为种子来生成随机数,这样更加的随机。
    3. 使用时,参数一般是 unsigned int 类型的整数,比如 srand(10)
    4. 如果不想用 srandrand() 产生的随机数,多次运行,结果是一样的。

7. 枚举

  • 枚举值不能连续,这种枚举无法遍历,枚举中的默认值是前一个+1,int。

8. 输出

  • %p 是打印地址的格式说明符,用于以十六进制格式输出内存地址。

9. 字符串

  • 字符串实际上是使用 null 字符 \0 终止的一维字符数组。
  • strlen 是函数,sizeof 是运算操作符,二者得到的结果类型为 size_t,即 unsigned int 类型。
  • sizeof 计算的是变量的大小,不受字符 \0 影响;而 strlen 计算的是字符串的长度,以 \0 作为长度判定依据。

10. 指针

  • 所有实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,对应指针的值的类型都是一样的,都是一个代表内存地址的长的十六进制数。
  • 在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
  • 如需检查一个空指针,您可以使用 if 语句,如下所示:
    1
    2
    if(ptr) /* 如果 p 非空,则完成 */
    if(!ptr) /* 如果 p 为空,则完成 */
  • 我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量。
  • 函数指针
    • int (*p)(int, int) = &max; // & 可以省略
    • 其中 max 是定义的函数 int max(int x, int y);

11. 回调函数

  • 回调函数是由别人的函数执行时调用你实现的函数。例如,当你到商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。

12. 位域

  • 位域是一种结构类型,成员是按二进位分配的。例如:
    1
    2
    3
    4
    5
    struct bs {
    int a:8;
    int b:2;
    int c:6;
    } data;
  • 位域在本质上就是一种结构类型,不过其成员是按二进位分配的。一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。
  • 结构体内存分配原则
    • 原则一:结构体中元素按照定义顺序存放到内存中,但并不是紧密排列。每个元素存放的位置一定会在自己大小的整数倍上开始。
    • 原则二:在原则一的基础上,检查计算出的存储单元是否为所有元素中最宽的元素长度的整数倍。若是,则结束;否则,将其补齐为它的整数倍。
  • 定义位域时,各个成员的类型最好保持一致,比如都用 char,或都用 int,不要混合使用,这样才能达到节省内存空间的目的。
  • 共用体
    • 使用 union 关键字定义,结构和定义类似于结构体,只是使用和内存不一样。共用体中的所有成员是公用内存的,大小是其中最大的成员的内存,后面的会把前面的值占用。

13. define(预处理)

  • #define 用于定义宏,例如:
    1
    2
    3
    #define PI 3.14159
    #define MAX(a,b) ((a) > (b) ? (a) : (b))
    typedef unsigned char uchar
  • typedef 为数据类型(可以是已有,也可以是用户自定义的)取个别名。
  • #definetypedef 的区别在于:
    • typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名。
    • typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。

14. 输入与输出

  • C 语言把所有的设备都当作文件。【Linux中一切皆是文件】所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕:stdinstdoutstderr
  • 输入
    • scanf("%f", &f);
    • scanf("%s %d", str, &i);
    • 在读取字符串时,只要遇到一个空格,scanf() 就会停止读取,所以 “this is test” 对 scanf() 来说是三个字符串。
    • scanf() 函数返回的值为:正确按指定格式输入变量的个数;也即能正确接收到值的变量个数。
    • scanf("c1=%c", &c1);
    • 输入多个数时,不要加空格。
    • 输入:scanfgetchargets
  • 输出
    • printfputcharputs

15. 文件处理

  • 一般流程是先打开文件(fopen)–读/写文件(与输入输出基本一致,加 f)–处理–关闭文件(fclose)。
  • 读文件是读到缓冲流中。
  • 为什么读的时候是有记忆的?这是因为文件指针在每次读取后会移动到下一个位置,直到文件末尾。

16. 预处理器指令

  • #define 定义宏
  • #include 包含文件
  • #undef 取消宏定义
  • #ifdef 条件编译
  • #if ... #endif 条件编译
  • #error 生成错误信息
  • #pragma 设置编译器选项

17. 头文件

  • #include <file> 引用系统文件
  • #include "file" 引用用户头文件
  • 防止重复包含
    1
    2
    3
    4
    #ifndef HEADER_FILE
    #define HEADER_FILE
    // the entire header file content
    #endif
  • 建议把所有的常量、宏、系统全局变量和函数原型写在头文件中,在需要的时候随时引用这些头文件。

18. 类型转换

  • 类型转换遵循一定的规则,例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    double <--- float
    ^
    |
    |
    long
    ^
    |
    unsigned
    ^
    |
    int <--- short, char

19. 内存管理

  • 动态分配内存
    • void *calloc(int num, int size);
    • void *malloc(int num);
    • void *realloc(void *address, int newsize); (这个一般不要用)
    • 例如:description = (char *)malloc(200 * sizeof(char));
  • 释放内存
    • void free(void *address);
    • 指针释放后要置 NULL

20. scanf 格式说明符

  • d 输入十进制整数
  • o 输入八进制整数
  • x 输入十六进制整数
  • u 输入无符号十进制整数
  • fe 输入实型数(用小数形式或指数形式)
  • c 输入单个字符
  • s 输入字符串
  • ld 长整型
  • Lf 双精度浮点数

21. printf%p 的输出应用

  • %p 表示输出以内存中实际存储一个变量格式(十六进制、32位或64位,视机器的位数而定)的值,通常也就是地址的值,但也不一定,要看具体输出的是什么。

显示 Gitment 评论