一个简单的 C 程序
c
#include <stdio.h>
#include <assert.h>
/*
* 这是 main 函数 (main function)
* 一般情况下(有宿主环境)C 程序的入口点
*/
int main(void) {
// 输出一行字
puts("hello world");
int a, b;
scanf("%d%d", &a, &b);
assert(b != 0, "b cannot be zero");
printf("%g\n", (double)a / b);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1. C 项目的创建(以 Lightly 为例)
提示
本小节和下一小节以 Lightly 为例,但你也可以用自己本地的环境运行。
点击 在线使用
点击 新建项目,选择 C,C 语言标准 选择 C11,项目名称自拟,其他可选项默认
经过一小段时间的初始化,工作区已经准备好了:
可以见到项目里面新建了两个文件夹,源码文件 main.c
里面生成了一个输出 hello world 的示例代码; 源码文件上面还有一个叫 .clang-format
的文件,里面有些设置项
2. C 文件的编译运行
- 打开
main.c
,将上方代码粘贴进去,点击绿色三角形按钮即可编译运行 - 在屏幕上输出了
hello world
3. 包含标准库头文件
看以下的高亮代码行:
c
#include <stdio.h>
#include <assert.h>
/*
* 这是 main 函数 (main function)
* 一般情况下(有宿主环境)C 程序的入口点
*/
1
2
3
4
5
6
7
2
3
4
5
6
7
我们可以看到,代码的第一行和第二行具有 #include <...>
的形式,这是包含标准库头文件的写法。
- 以
#
开头的是一条预处理器指令 (Preprocessor Directive),我们将在 10 - 预处理器 这一章中详细讲解预处理器的功能。 #include
指令是把目标文件的内容“原封不动”地粘贴到此文件,我们将在 10.2#include
这一节中详细讲解#include
的用法。<stdio.h>
是标准库提供的一个头文件,需要包含它才能使用其中的内容。第 11 章 标准库概述 会提到<stdio.h>
这个头文件及其功能。
4. 注释 (Comment)
看以下的高亮代码行:
c
#include <stdio.h>
#include <assert.h>
/*
* 这是 main 函数 (main function)
* 一般情况下(有宿主环境)C 程序的入口点
*/
int main(void) {
// 输出一行字
puts("hello world");
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
这片代码中有两种注释:行内注释和块注释。我们将在 3.1 注释 中详细讲解。
5. main 函数
c
/*
* 这是 main 函数 (main function)
* 一般情况下(有宿主环境)C 程序的入口点
*/
int main(void) {
// 输出一行字
puts("hello world");
4
5
6
7
8
9
10
11
5
6
7
8
9
10
11
5.1 程序入口点
- 一般来说,一个 C 程序从
main()
函数开始执行,也从main()
函数结束
5.2 main 函数的几种原型
- 标准规定的:
int main(void)
- 标准规定的:
int main(int argc, char* argv[])
- 很多编译器实现的:
int main(int argc, char* argv[], char* envp[])
6. 返回值 (return value, RV)
看下面的高亮代码行:
c
printf("%g\n", (double)a / b);
return 0;
}
17
18
19
20
18
19
20
return
的东西是函数的返回值- 如果
main()
函数的返回值为 0,则说明程序正常退出。我们将在 21 - 程序支持 中讲解main()
函数退出时发生的一些情况,以及那时可以进行的一些操作。 - 主函数正常执行到末尾如同返回 0。
7. 库函数
看下面的高亮代码行:
c
// 输出一行字
puts("hello world");
int a, b;
scanf("%d%d", &a, &b);
assert(b != 0, "b cannot be zero");
printf("%g\n", (double)a / b);
10
11
12
13
14
15
16
17
11
12
13
14
15
16
17
puts
scanf
printf
这三个是标准库提供的函数。它们的功能如下:
puts
用于输出字符串并换行。scanf
用于读取数据。printf
用于格式化输出。
除此之外,也可以定义自己的函数。我们将在 6. 函数 中详细介绍如何定义自己的函数。
8. 初识断言 (Assertion)
看下面的高亮代码行:
c
assert(b != 0, "b cannot be zero");
printf("%g\n", (double)a / b);
16
17
17
我们可以看到,第 16 行具有 assert( ... )
的形式,它是一个断言。
8.1 什么是断言
断言是用于进行调试和错误处理的工具。
它允许程序员在代码中插入条件检查,以确保程序在运行时满足特定的前提条件。
如果断言的条件不成立,程序将终止执行并生成一条错误消息,提供关于出错位置和原因的信息。有个被普遍应用的技巧是使用逗号运算符额外提供错误消息。
8.2 使用断言
c
#include <assert.h>
int main(void){
int a = -5;
assert(a > 0);
}
1
2
3
4
5
6
2
3
4
5
6
程序终止执行,因为断言的条件 a > 0
不成立。
控制台可能打印出以下内容:
txt
***.c:4: main: Assertion `a > 0' failed.
Program terminated with signal: SIGSEGV
1
2
2
8.3 用途
用于防御性编程,缩小错误可能存在的范围,便于调试。