制器坊 编程基础

C 语言基础:保存源码、编译、运行与读错

把 Hello World 保存成文件,分别完成编译与运行。配合操作示例、图解和检查点,完成第一次练习,再逐步排查使用中的问题。

信息层级:【有据可查】= 附官方文档或可信来源链接;【社区共识】= 社区用户普遍经验,未经官方确认;【待考察/推测】= 推测或暂未能核实,请谨慎对待。

🎯 目标:看得懂 AI 生成的 C 代码与编译报错,而不是成为 C 专家。官方/权威参考:cppreference C 部分、GCC 文档。【有据可查】


1. C 是什么?用在哪?

【社区共识】C 是贴近硬件的系统编程语言:操作系统内核、嵌入式、数据库、解释器(如 CPython)大量用 C 编写。特点:快、可控、但内存要自己管。

图 1

2. Hello World 与编译

#include <stdio.h>

int main(void) {
    printf("Hello, %s! %d\n", "world", 42);
    return 0;
}
gcc -Wall -Wextra -g hello.c -o hello   # -Wall -Wextra 打开常见警告,-g 带调试信息
./hello

【社区共识】永远打开 -Wall -Wextra:很多 Bug 在警告阶段就能发现。


3. 基础语法速查

主题 示例 说明
变量与类型 int a = 1; double b = 2.5; char c = 'x'; 类型必须声明
数组 int arr[5] = {1,2,3,4,5}; 下标从 0 开始,不检查越界
字符串 char s[] = "hi"; 以 '\0' 结尾的字符数组
指针 int *p = &a; *p = 10; & 取地址,* 解引用
条件 if (a > 0) {...} else {...} 0 为假,非 0 为真
循环 for (int i = 0; i < n; i++) {...} / while (...) —
函数 int add(int x, int y) { return x + y; } 先声明后使用
结构体 struct Point { int x, y; }; 自定义复合类型
动态内存 int *p = malloc(n * sizeof *p); ... free(p); 申请了必须释放
宏 #define MAX 100 预处理阶段文本替换

4. 常用标准库函数

头文件 函数 用途 注意
<stdio.h> printf / fprintf / snprintf 格式化输出 格式符与参数类型要匹配(%d int、%f double、%s 字符串、%zu size_t)
<stdio.h> scanf / fgets 输入 读字符串优先 fgets,避免溢出
<stdio.h> fopen / fclose / fread / fwrite 文件 检查 fopen 是否返回 NULL
<stdlib.h> malloc / calloc / realloc / free 动态内存 检查返回值;不要重复 free
<stdlib.h> atoi / strtol / exit / qsort 转换、退出、排序 strtol 能报告错误,比 atoi 安全
<string.h> strlen / strcmp / strcpy / strncpy / memcpy / memset 字符串与内存 strcpy 不检查长度,易溢出
<math.h> sqrt / pow / fabs 数学 链接时可能需要 -lm
<errno.h> + <string.h> errno / strerror(errno) 读取系统错误原因 配合 perror("fopen") 最方便

来源:cppreference C 标准库【有据可查】


5. 读懂报错

5.1 编译器报错的结构

main.c:7:5: error: 'conut' undeclared (first use in this function); did you mean 'count'?
  7 |     conut++;
    |     ^~~~~
部分 含义
main.c:7:5 文件 : 行 : 列
error / warning 错误必须修;警告强烈建议修
说明文字 原因,常附带 did you mean 建议
^~~~ 指向出问题的位置

原则:从第一个错误开始修,后面的错误常常是第一个引起的连锁反应。【社区共识】

5.2 常见错误对照表

报错 阶段 常见原因 处理
expected ';' before ... 编译 上一行漏分号 看报错行的上一行
'x' undeclared 编译 拼写错误、未声明、作用域外 检查拼写与声明位置
implicit declaration of function 'foo' 编译(警告/错误) 没 #include 对应头文件或未声明函数 加头文件或函数原型
incompatible types / makes pointer from integer 编译 指针与整数混用 检查 & 与 *
format '%d' expects argument of type 'int' 编译警告 printf 格式符不匹配 改格式符
undefined reference to 'sqrt' 链接 没链接库 加 -lm 或对应库
undefined reference to 'main' 链接 没有 main 函数或文件没参与编译 检查编译命令
Segmentation fault (core dumped) 运行 空指针、越界、使用已释放内存 用 gdb 或 -fsanitize=address 定位
double free or corruption 运行 重复释放、堆被写坏 AddressSanitizer
stack smashing detected 运行 栈上数组越界 检查数组下标与字符串长度

5.3 定位运行时崩溃

gcc -g -fsanitize=address,undefined main.c -o main && ./main

【有据可查:GCC Instrumentation Options】AddressSanitizer 会打印出错行号与内存访问情况。


6. 和 AI 协作的提示【社区共识】

  • 把完整报错 + 编译命令 + 相关代码一起给 AI,而不是只说"编译不过"。
  • 让 AI 生成 C 代码时要求:"检查所有 malloc 返回值、所有 free、所有数组边界"。
  • AI 写的字符串处理代码要特别审查缓冲区长度。

7. 本篇无法核实/需谨慎的点

  • 不同编译器(GCC、Clang、MSVC)的报错措辞不同,本文以 GCC 为例。
  • C 标准版本(C11/C17/C23)间的细节差异未展开。

小白练习:把本文流程逐项走通

练习目标:把 Hello World 保存成文件,分别完成编译与运行。

上文已介绍概念、配置和操作示例。下面侧重第一次实际操作时的顺序、检查点和结果核对;需要查具体参数时回到对应小节。命令逐条输入,看到上一条的结果后再继续。

  1. 先按 GCC 官方文档或所选系统工具链文档安装编译器,再运行 gcc --version;装一个编辑器不等于装了编译器。

    补充说明:版本检查应输出 GCC 版本信息;若命令不存在,先按自己的系统准备编译器。只有编辑器还不能将源码变成程序。

  2. 新建练习文件夹,用编辑器保存原文的 Hello World 为 hello.c。开启文件扩展名显示,确认不是 hello.c.txt。

    补充说明:用文本编辑器保存上文完整 C 示例,采用 UTF-8。Windows“另存为”可选“所有文件”,确认文件没有变成 hello.c.txt。

  3. 打开终端,用 cd 进入保存 hello.c 的目录,再列出文件确认位置。

    补充说明:hello.c 是输入源码,-o hello 指定编译输出名,-Wall -Wextra 打开常见警告,-g 增加调试信息。编译有错误时先修复,不运行以前留下的输出文件。

  4. 单独运行原文的 gcc 编译命令。无 error 后确认可执行文件已经生成,随后再运行它。

    补充说明:终端所属系统与编译目标应一致。原生 Windows GCC 目标通常生成 hello.exe,在 PowerShell 中用 .\hello.exe;Bash 中使用原文的 ./hello。

  5. Bash 使用 ./hello;Windows PowerShell 下的 Windows 可执行文件通常使用 .\hello.exe。先确认编译目标,不混用两种环境。

    补充说明:完整输出应为 Hello, world! 42。%s 对应字符串 world,%d 对应整数 42,\n 让输出换行,return 0 表示正常结束。

  6. 预期看到 Hello, world! 42。修改一个数字后重新编译,再运行;运行旧程序不会自动读取新的源码。

    补充说明:修改 42 为 7 后,分别保存、重新编译、再运行,检查变化。语法表中的 n、a 等是片段变量,需要所在程序的定义,不要把速查表逐行拼成一个程序。

继续浏览制器坊 返回顶部 ↑
教程图解100%
教程图解
灵犀台