Appearance
第一个程序:亲手让电脑开口
预计学习时长:约 3 小时(建议分两次:写程序 + 概念消化)· 环境:VS2026 / gcc / clang
🎯 学习目标
学完本讲,你将能够:
- 独立写出、编译并运行一个完整的 C 程序
- 说清 main 函数的作用,以及
#include、return 的含义 - 用 printf 打印文字、整数、字符,知道什么是库函数和头文件
- 区分字符与字符串,解释 \0 的作用
- 认识常用关键字、ASCII 编码、转义字符、语句分类和注释
🔗 先修知识
- 第 1 讲:C 语言是什么
- 编译器没装好?附录 A:环境搭建指南(本讲假设你已能创建项目)
先修自检(三问)
- C 源代码文件的后缀是什么?
- 从源代码到能运行的程序,要经过哪两个步骤?
- 源文件和头文件的后缀分别是什么?
一、第一个 C 程序
下面是一个完整的 C 程序,请逐字符敲进编辑器(不要复制粘贴,亲手敲第一遍):
📄 hello.c · ✅ 完整程序(可直接复制编译)
c
#include <stdio.h>
int main()
{
printf("hello C\n");
return 0;
}VS2026 中运行的快捷键:Ctrl + F5(开始执行不调试)。运行成功后会看到:
text
hello C先记住这个程序的四个组成部分,接下来逐一讲透:
text
#include <stdio.h> ← 引入头文件
int main() ← 主函数(入口)
{ ... } ← 函数体
printf(...); ← 调用库函数打印
return 0; ← 返回,结束程序二、main 函数:程序的入口
2.1 入口规则
不管程序有多少行、多少个文件,执行都从 main 函数开始,它也叫主函数。main 前面的 int 表示函数结束时返回一个整数;函数体最后的 return 0; 表示“程序正常结束”,前后呼应。🟢
🧩 示意片段
c
int main()
{
// 所有要执行的代码写在这里
return 0; // 0 表示正常结束
}规则:
- main 函数有且仅有一个;
- 一个项目即使有多个 .c 文件,也只能有一个 main——入口只能有一个。
2.2 第一次写代码的高频错误
| 错误 | 例子 | 正确 |
|---|---|---|
| main 拼成 mian | int mian() | int main() |
| main 后漏括号 | int main | int main() |
| 用了中文符号 | printf("hi"); | 全部用英文半角 |
| 语句漏分号 | printf("hi") | printf("hi"); |
💡 判断中文符号的小技巧:中文标点在编辑器里占两个字符的宽度。报错时先找这四类问题。
三、printf 与标准库
3.1 printf 是库函数
printf 的功能是在标准输出设备(屏幕)上打印信息。它不是我们自己写的,而是标准库提供的函数——这种现成的函数叫库函数。
为了让程序员不重复造轮子,C 标准规定了一组常用函数(输入输出、数学计算、字符串处理等),由编译器厂商按标准实现,随编译器一起提供,这就是标准库。
3.2 头文件与 #include
库函数使用前要包含对应的头文件。printf 声明在 <stdio.h> 中,所以文件顶部写:
c
#include <stdio.h> // stdio = standard input/output少了它,gcc 会报“implicit declaration of function 'printf'”(函数未声明)。
3.3 printf 也能打印不同类型
📄 printf_types.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
printf("%d\n", 100); // %d:整数
printf("%c\n", 'q'); // %c:单个字符
printf("%.2f\n", 3.14); // %.2f:小数,保留 2 位
return 0;
}%d、%c、%f 叫占位符(格式说明符),会被后面的值替换。占位符的完整用法在第 3 讲:数据类型和变量中系统讲解。
四、关键字
int、if、return 这类名字是 C 语言保留的,称为关键字(保留字)。
- 关键字有固定的特殊含义,留给语言本身使用;
- 给变量、函数起名时不能与关键字相同;
- 关键字不能自己创造。
C89 的 32 个关键字:
text
auto break case char const continue
default do double else enum extern
float for goto if int long
register return short signed sizeof static
struct switch typedef union unsigned void
volatile whileC99 新增:inline、restrict、_Bool、_Complex、_Imaginary(C11/C23 又有增加,如 _Static_assert、_Generic 等,用到再讲)。完整表见 cppreference 关键字。
五、字符与 ASCII 编码
5.1 字符用单引号
键盘敲出的 a、q、@、# 都叫字符,C 语言中用单引号括起:
c
'a' 'b' '@' 'Q'5.2 ASCII 编码
计算机中一切数据都是二进制。为统一字符与数字的对应,美国国家标准学会(ANSI)制定了 ASCII 编码,C 语言字符遵循它。每个字符对应一个整数(ASCII 码值)。
必记的几组值:
| 字符 | ASCII 值 | 字符 | ASCII 值 | |
|---|---|---|---|---|
'A' ~ 'Z' | 65 ~ 90 | '0' ~ '9' | 48 ~ 57 | |
'a' ~ 'z' | 97 ~ 122 | '\n' 换行 | 10 | |
| 大小写差值 | 32 | 0 ~ 31 | 不可打印字符 |
💡 不用背全表,但 65、97、48、32、10 这五个数要张口就来。
5.3 用 %c 打印字符
📄 ascii.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
printf("%c\n", 'Q'); // 直接给字符:Q
printf("%c\n", 81); // 给 ASCII 码值,81 就是 Q
printf("%d\n", 'Q'); // 反过来,看字符的码值:81
return 0;
}%c 把整数当字符显示,%d 把字符当整数显示——这能直观验证“字符本质是整数”。
5.4 打印全部可打印字符
ASCII 32~127 是可打印字符。下面程序每行打印 16 个:
📄 printable.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
for (int i = 32; i <= 127; i++)
{
printf("%c ", i);
if (i % 16 == 15)
printf("\n");
}
return 0;
}这里提前用了 for 循环,语法在第 6 讲细讲,现在只需知道它让 i 从 32 逐个变到 127。
六、字符串与 \0
6.1 字符串用双引号
双引号括起的一串字符叫字符串:
c
"abcdef"
"hello C"用 %s 打印字符串:
6.2 \0 是结束标志
字符串 "abc" 表面 3 个字符,实际末尾隐藏一个 \0(ASCII 值 0),它是字符串的结束标志。printf、strlen 等函数遇到 \0 就停止。🟢
📄 zero_end.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
char arr1[] = {'a', 'b', 'c'}; // 只有 3 个字符,没有 \0
char arr2[] = "abc"; // 字符串自动带 \0
printf("%s\n", arr1); // abc 后面跟乱码(越界寻找 \0)
printf("%s\n", arr2); // abc
return 0;
}arr1 没有结束标志,printf 会继续读后面的内存,直到碰巧遇到字节 0,所以出现随机乱码。手动补上 \0 就正常:
📄 zero_end_fix.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
char arr1[] = {'a', 'b', 'c', '\0'};
char arr2[] = "abc";
printf("%s\n", arr1); // abc
printf("%s\n", arr2); // abc
printf("%s\n", "abc\0def"); // abc(中间的 \0 让打印提前结束)
return 0;
}⚠️ 乱码不是玄学
看到乱码,第一反应应该是“字符串缺少 \0 或编码不匹配”,而不是电脑坏了。%s 打印的起点之后,必须有一个 \0。
七、转义字符
7.1 为什么需要转义
普通 n 打印出来是字母 n;加反斜杠写成 \n,含义变成“换行”——反斜杠“转变了字符的原意”,所以叫转义字符。
7.2 常用转义字符
| 转义 | 含义 | 转义 | 含义 | |
|---|---|---|---|---|
\n | 换行 | \\ | 一个反斜杠 | |
\t | 水平制表符(Tab) | \' | 单引号 | |
\r | 回车(回到行首) | \" | 双引号 | |
\b | 退格 | \a | 警报(响铃) | |
\f / \v | 换页 / 垂直制表 | \? | 问号(防三字母词) | |
\0 | null,ASCII 0 | \ddd | 1~3 位八进制数 | |
\xdd | 十六进制数(如 \x41 是 A) |
📄 escape.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
printf("%c\n", '\''); // 打印一个单引号:'
printf("%s\n", "\""); // 打印一个双引号:"
printf("路径:c:\\test\\code\n"); // 想显示一个 \,代码里要写两个
printf("%c\n", '\130'); // 八进制 130 = 十进制 88 = X
printf("%c\n", '\x41'); // 十六进制 41 = 十进制 65 = A
return 0;
}💡 最容易踩的坑:Windows 文件路径 c:\new 写进字符串必须是 "c:\\new",否则 \n 会被解释成换行。
📘 提高(L2):\x 的“贪吃”规则
\x 会把后面所有十六进制字符(0~9、a~f)全部吃掉,所以字符串 "\x41bc" 没问题(b、c 虽是十六进制字符,会被一起读入,结果可能不是你想的)。需要边界时可用字符串拼接:"\x41" "bc"。八进制 \ddd 最多吃 3 位,相对安全。
八、语句的分类
C 程序由一条条语句构成,共五类:
| 类别 | 说明 | 例子 |
|---|---|---|
| 空语句 | 只有分号,什么都不做 | ; |
| 表达式语句 | 表达式加分号 | b = a + 5; |
| 函数调用语句 | 函数调用加分号 | printf("hi"); |
| 复合语句 | { } 括起的代码块 | main 的函数体 |
| 控制语句 | 控制执行流程 | if / for / return 等 |
空语句用于“语法上需要一条语句、但无事可做”的场合,例如循环占位。
控制语句共 9 种,分三类:
九、注释
注释是给人看的说明,编译器会忽略它,对程序行为没有影响。
9.1 两种写法
块注释:
c
/* 单行注释 */
/*
多行注释
*/行注释(C99 新增),只管当前行:
c
// 这是一行注释
int x = 1; // 这也是注释三条规则:
/* */不能嵌套,遇到第一个*/注释就结束;漏写结束符会把后面的代码全“注释掉”。- 引号内的注释符号只是普通字符:
printf("// hello /* world */\n");会原样打印。 - 编译时注释被替换成一个空格:
min/* 注释 */Value变成min Value,不是minValue。
💡 好注释解释“为什么这么做”,而不是重复“代码做了什么”;写必要的注释,是一种编码习惯。
⚠️ 常见坑与报错(本讲汇总)
| 你看到的现象 | 原因 | 修法 |
|---|---|---|
| 一堆语法错误 | 用了中文括号/分号 | 切英文输入法重写 |
main 报未定义/链接错误 | 拼成 mian 或漏 () | 写 int main(void) 完整形式 |
| gcc 报 implicit declaration of 'printf' | 漏了 #include | 顶部加 #include <stdio.h> |
| 打印字符串带乱码 | 字符数组没有 \0 | 末尾补 '\0' 或用字符串初始化 |
| 路径里字母被换行/吞掉 | c:\new 中 \n 是转义 | 写成 c:\\new |
| 块注释后大片代码失效 | 漏写 */ 或尝试嵌套 | 用编辑器的注释高亮检查 |
| 语句报错 expected ';' | 漏分号 | 每条语句末尾检查 |
| gcc 报 arr undeclared | 示例片段当成完整程序 | 示意片段不能单独编译 |
更多见附录 C:常见错误清单。
🛠️ 动手练习
📊 本讲网页练习进度0 / 5(0%)
进度自动保存在本浏览器;编程题不计数,请在编辑器中完成。
练习 1 · ⭐ 基础 · 选择判断
知识点:main 函数
题干:下列说法正确的是?(多选)
练习 2 · ⭐ 基础 · 读输出
知识点:%c 与字符码值
题干:写出输出:
📄 ex2.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
printf("%c%c%c\n", 72, 73, 33);
return 0;
}请写出输出:
空①
练习 3 · ⭐ 基础 · 读输出
知识点:\0 与 ASCII 运算
题干:写出输出:
📄 ex3.c · ✅ 完整程序
c
#include <stdio.h>
int main()
{
printf("%s\n", "hello\0world");
printf("%c\n", 'A' + 32);
printf("%d\n", '\n');
return 0;
}请按打印顺序填出三个结果(提示:两个字符一个数):
空①空②空③
练习 4 · ⭐ 基础 · 找错改错
知识点:基础语法
题干:下面代码有多处错误,请把所有错误项选出来(多选):
🧩 待改错片段
c
#include <stdio.h>
int mian()
{
printf("hello);
return 0
}练习 5 · ⭐ 基础 · 程序填空
知识点:转义字符
题干:写出每条 printf 的实际输出:
🧩 待补全片段
c
printf("a\tb\n"); // \t 显示为 ______,\n 表示 ______
printf("%c", '\''); // 输出字符 ______
printf("%s", "\\"); // 输出字符 ______请填出四个空(字符或名称都算对,如 Tab/制表符):
空①空②空③空④
练习 6 · ⭐⭐ 提高 · 写小程序
知识点:多条 printf 排版
🛠 动手编程题 · 请在 VS2026(或你的编辑器)中完成
打印一张“个人名片”,包含姓名、专业、爱好,每行一项,可加简单边框。
✅ 过关标准:运行后至少显示 3 行信息,排版整齐。
网页内无法练习写代码,亲手敲、亲手编译才能真正学会。下方按顺序展开 思路 → 步骤 → 答案。
💡 提示 1(思路)
每一项用一个 printf,配合 \n 换行,边框可用 -、| 拼。
🧭 提示 2(步骤)
- 先打印一行分隔线
- 三行信息
- 再一行分隔线
🔑 参考答案与解释
c
#include <stdio.h>
int main()
{
printf("----------------\n");
printf("姓名:张三\n");
printf("专业:软件工程\n");
printf("爱好:编程、音乐\n");
printf("----------------\n");
return 0;
}排版关键:所有内容都在格式字符串里,想对齐就数好字符宽度。
练习 7 · ⭐⭐ 提高 · 写小程序
知识点:ASCII 码值输出字符
🛠 动手编程题 · 请在 VS2026(或你的编辑器)中完成
不允许在代码里直接写字母,只用 ASCII 码值,用 printf 输出单词 `CODE`。
✅ 过关标准:输出 CODE 四个大写字母。
网页内无法练习写代码,亲手敲、亲手编译才能真正学会。下方按顺序展开 思路 → 步骤 → 答案。
💡 提示 1(思路)
查 C、O、D、E 的码值,用 %c 连续打印。
🧭 提示 2(步骤)
C=67,O=79,D=68,E=69。
🔑 参考答案与解释
c
#include <stdio.h>
int main()
{
printf("%c%c%c%c\n", 67, 79, 68, 69);
return 0;
}这个练习确认你理解“字符即整数”。
练习 8 · ⭐⭐⭐ 挑战 · 写小程序
知识点:printf 图案排版
🛠 动手编程题 · 请在 VS2026(或你的编辑器)中完成
用 printf 打印一个由星号组成的直角三角形(5 行,逐行递增)。
✅ 过关标准:输出形状如下:
text
*
**
***
****
*****网页内无法练习写代码,亲手敲、亲手编译才能真正学会。下方按顺序展开 思路 → 步骤 → 答案。
💡 提示 1(思路)
每行星号个数等于行号,用五行 printf 即可(暂时不用循环)。
🧭 提示 2(步骤)
- 每行一个 printf
- 星号依次 1~5 个,每行末尾 \n
🔑 参考答案与解释
c
#include <stdio.h>
int main()
{
printf("*\n");
printf("**\n");
printf("***\n");
printf("****\n");
printf("*****\n");
return 0;
}等学完第 6 讲循环,五行可以压缩成三行代码——先记下这个“繁琐版本”,到时你会真切感到循环的威力。也可以试试把图案改成菱形或爱心。
📝 小结与自测
核心结论
- C 程序从 main 开始,main 唯一,返回 0 表示正常结束。
- printf 是标准库函数,用前
#include <stdio.h>;%d、%c、%f、%s 对应不同类型。 - 字符用单引号、本质是 ASCII 整数;字符串用双引号、末尾隐藏 \0。
- 转义字符由反斜杠引导:\n 换行、\t Tab、\ 反斜杠、\ddd、\xdd。
- 语句五类,注释两种;/* */ 不嵌套,// 为 C99 行注释。
自测清单
| 我能独立做到 | ✅ |
|---|---|
| 不看资料默写出 hello.c 并运行成功 | |
| 说出 65、97、48、32、10 对应什么 | |
| 解释 \0 的作用和乱码成因 | |
| 在字符串中正确使用 \ 和 " | |
| 写出两种注释并说清嵌套限制 | |
| 打印星号三角形 |
🔬 选学拓展(L3)
以下内容为选学
跳过不影响下一讲。
L3-1:main 的标准写法与 void
标准托管环境下,main 推荐两种原型:int main(void)(无参数)和 int main(int argc, char **argv)(带命令行参数)。void 显式声明“不接受参数”。另外,从 main 返回相当于调用 exit;返回值会成为进程退出码,0 表示成功,非 0 表示异常。
L3-2:ASCII 之外:中文怎么存
ASCII 只够表示英文。为表示全世界文字,出现了 Unicode(给每个字符一个唯一编号,码点如 U+4E2D 是“中”);具体传输存储采用 UTF-8、UTF-16 等编码,UTF-8 兼容 ASCII 且是今天互联网的主流。本教程源码文件建议保存为 UTF-8,这也是 VitePress 的默认编码。
L3-3:printf 的返回值
printf 返回成功打印的字符个数(不含 \0),如 int n = printf("abc"); 后 n 为 3。现在用不到,但调试输出时偶尔有帮助。
预告:下一讲学习数据类型和变量,让程序记住并处理数据。