C语言期末复习笔记

C语言期末备考突击复习笔记

这份笔记包括了C语言基础学习的一些难点,而不是从基本语法开始写起,

1. 数组与指针

核心概念

  1. 数组名 = 首地址

    • int a[5];a 的值等于 &a[0]
    • 区别:在 Java 中数组是对象,在 C 中数组是连续内存块。
  2. 指针运算(跳格子)

    • 指针加减不是简单的数学加减,而是基于数据类型的大小(步长)

    • 假设地址为 1000:

c 复制代码
     int *p = (int*)1000;
     p + 1; // 结果是 1004 (跳过 4 字节)
     
     double *d = (double*)1000;
     d + 1; // 结果是 1008 (跳过 8 字节)
  1. 二维数组内存布局

    • 二维数组(如 int a[2][3])在内存中是**连续"拉直"**存储的(行主序)。
    • a[0][2] 的下一个元素紧挨着 a[1][0]

⚠️ 高频易错点:指针声明

  • 指针数组 (Array of Pointers): int *p[10];
    • [] 优先级高,先结合。本质是数组,里面存了 10 个指针。
  • 数组指针 (Pointer to Array): int (*p)[10];
    • () 强制结合。本质是指针,指向一个长度为 10 的数组。
    • 场景:用于指向二维数组的一行。

2. 字符串

核心概念

  • 没有 String 类型 :C 语言用字符数组 char[] 模拟字符串。
  • 结束标记 :必须以 \0 结尾。"Hi" 实际占用 3 字节 ('H', 'i', '\0')。

⚠️ 陷阱:只读 vs 可写C

c 复制代码
// 1. 字符数组 (栈内存) ->  可以修改
char s[] = "Hello";
s[0] = 'X'; // 变成 "Xello"

// 2. 字符串字面量指针 (常量区) ->  禁止修改 (崩溃)
char *p = "Hello";
p[0] = 'X'; // Segmentation Fault!

⚠️ 陷阱:输入读取

  • scanf("%s", s): 遇到空格就停止。输入 "Hello World" -> 只读入 "Hello"。
  • fgets(s, size, stdin): 可以读取带空格的整行。

3. 函数

核心概念

  1. 值传递 (Pass by Value)

    • 默认情况下,函数参数传递的是复印件。修改形参不会影响实参。
  2. 传址调用 (Pass by Reference)

    • 想修改外面的变量,必须传地址
c 复制代码
   // ✅ 标准交换函数
   void swap(int *x, int *y) {
       int temp = *x; // 1. 取出 x 指向的值
       *x = *y;       // 2. 修改 x 指向的内存
       *y = temp;     // 3. 修改 y 指向的内存
   }
   // 调用:swap(&a, &b);

C⚠️ 致命错误:悬空指针

  • 绝对禁止返回局部变量的地址。
c 复制代码
  int* error_func() {
      int a = 10;
      return &a; // ❌ 函数结束 a 就被销毁了,返回的地址是废的
  }

静态变量

  • static int x = 0;: 记忆力超强。函数结束不销毁,下次调用保留上次的值。

4. 结构体

核心概念

  • 定义与大小
c 复制代码
  struct Student {
      char name[20]; // 20字节
      int age;       // 4字节
  };
  // sizeof(struct Student) 至少 24 字节
  • 成员访问

    • 变量访问:stu.age (点号)
    • 指针访问:p->age (箭头),等价于 (*p).age
  • 字符串赋值

    • ❌ 错误:stu.name = "Tom"; (数组名是常量)
    • ✅ 正确:strcpy(stu.name, "Tom"); (需要 <string.h>)

5. 链表

这是 C 语言最灵活的数据结构,也是考试大题热门。

5.1 结点的定义

c 复制代码
struct Node {
    int data;           // 数据域
    struct Node* next;  // 指针域:指向下一个同类结点
};

5.2 创建头结点

c 复制代码
struct Node* head = (struct Node*)malloc(sizeof(struct Node)); // 申请内存
head->next = NULL; // 初始为空链表,指向 NULL

5.3 遍历/输出链表

c 复制代码
void print_list(struct Node* head) {
    struct Node* p = head->next; // 假设带头结点,从第一个真数据开始
    // 如果是不带头结点的链表,就写 p = head;

    while (p != NULL) {          // 只要 p 指向的地方有房子
        printf("%d -> ", p->data);
        p = p->next;             // 关键动作:移动指针到下一格
    }
    printf("NULL\n");
}

5.4 插入结点

场景:把 newNode 插到 p 结点的后面。

口诀:先连后,再连前(防止断链)。

c 复制代码
// 1. 新结点的右手先拉住后面的人 (B)
newNode->next = p->next;

// 2. p 的右手松开 B,改去拉住新结点
p->next = newNode;

5.5 删除结点

场景:删除 p 后面的那个结点(假设叫 target)。

口诀:先备份,再过河拆桥,最后清理门户。

c 复制代码
// 1. 备份:先找到要删的目标,记下来
struct Node* target = p->next;

// 2. 拆桥:让 p 直接跳过 target,连上 target 的下一个人
p->next = target->next;

// 3. 释放:把 target 占用的内存还给系统 (防止内存泄漏)
free(target);

6. 共用体 & 枚举

  • 共用体 (union) :
    • 所有成员共用同一块地盘(省空间)。
    • 陷阱 :写了 u.f (float),之前的 u.i (int) 就被覆盖成乱码了。
  • 枚举 (enum) :
    • enum Color { RED, GREEN, BLUE };
    • 本质是整数常量:RED=0, GREEN=1, BLUE=2。提高代码可读性。

7. 文件操作

操作三部曲

  1. 打开 : FILE *fp = fopen("文件名", "模式"); if (fp == NULL) return; // 必须检查打开是否成功
  2. 读写 : fprintf, fscanf
  3. 关闭 : fclose(fp); (必做!)

打开模式

  • "r" (Read): 只读。文件不存在则报错 (NULL)。
  • "w" (Write): 只写 。文件存在则清空覆盖;不存在则创建。
  • "a" (Append): 追加。在文件末尾写,不覆盖原内容。

常用函数

c 复制代码
// 写入文本到文件
fprintf(fp, "Name: %s, Age: %d\n", name, age);

// 从文件读取数据
fscanf(fp, "%s %d", buffer_name, &buffer_age);
相关推荐
Lee川17 小时前
优雅进化的JavaScript:从ES6+新特性看现代前端开发范式
javascript·面试
Lee川20 小时前
从异步迷雾到优雅流程:JavaScript异步编程与内存管理的现代化之旅
javascript·面试
晴殇i1 天前
揭秘JavaScript中那些“不冒泡”的DOM事件
前端·javascript·面试
绝无仅有1 天前
Redis过期删除与内存淘汰策略详解
后端·面试·架构
绝无仅有1 天前
Redis大Key问题排查与解决方案全解析
后端·面试·架构
AAA梅狸猫1 天前
Looper.loop() 循环机制
面试
AAA梅狸猫1 天前
Handler基本概念
面试
Wect1 天前
浏览器缓存机制
前端·面试·浏览器
掘金安东尼1 天前
Fun with TypeScript Generics:玩转 TS 泛型
前端·javascript·面试
掘金安东尼1 天前
Next.js 企业级落地
前端·javascript·面试