C 入门:编译、变量与类型
从一个能运行的程序开始,再学习变量、分支、循环和函数。本文按 C11 的基础语法组织;后续学习指针和内存管理前,先完成末尾练习。
1. 编译并运行第一个程序
需要可用的 C 编译器。下面使用 GCC;安装方式随操作系统而异,先用 gcc --version 确认命令可用。
将下面的代码保存为 hello.c:
#include <stdio.h>
int main(void)
{
printf("Hello, World!\n");
return 0;
}stdio.h 声明标准输入输出函数。main 是程序入口,void 表示没有参数,return 0 表示正常结束。花括号组成代码块;声明和表达式语句通常以分号结束,代码块后不一律加分号。
在 Linux/macOS 的终端执行:
gcc -std=c11 -Wall -Wextra hello.c -o hello
./helloWindows 使用 GCC 时可输出 hello.exe,再在 PowerShell 中执行 ./hello.exe。编译失败时先读第一条错误;编译成功但不能启动时,再检查当前目录与可执行文件名。不要把终端提示符一起复制到命令里。
2. 声明变量与选择类型
变量需要类型和名称。先初始化,再读取;不要依赖未初始化的局部变量。
int count = 3;
double price = 2.5;
char grade = 'A';
double total = count * price;| 需求 | 基础写法 | 要确认的边界 |
|---|---|---|
| 整数计数 | int count = 3; | 类型范围由实现决定,不能假定所有整数类型都是同样大小 |
| 带小数的数值 | double price = 2.5; | 浮点数不能精确表示所有小数 |
| 一个字符 | char grade = 'A'; | 单引号表示字符常量;字符编码另行考虑 |
| 一段字符串 | char name[] = "Ada"; | 字符数组结尾包含 \0,不是独立的字符串基本类型 |
| 一组同类型数据 | int scores[3] = {80, 90, 100}; | 下标只能使用 0 到 2 |
| 组合字段 | struct Point { int x; int y; }; | 结构体成员各有自己的存储 |
| 共享存储表示不同成员 | union Value { int i; double d; }; | 不能当成多个成员同时独立存值的结构体 |
| 一组具名整数常量 | enum State { STOPPED, RUNNING }; | 枚举用于表达状态或有限选项 |
| 指向对象 | int *p = &count; | 解引用前必须确认指针有效、对象仍在生存期内 |
| 不返回值的函数 | void show(void); | void 不等于可以声明一个普通空类型变量 |
同一个整数可以用不同进制写出:26、0x1A、032 都表示十进制26,前导 0 在这种整数字面量中表示八进制,不能把 032 当十进制32。通用转换方法和练习统一见进制与转换,这里不重复整张转换表。
这里先认识指针、结构体与联合体的用途,不在初学阶段展开动态内存管理。想看某个对象占用的字节数,使用 sizeof;不要把某台机器上的结果写成语言通则。
3. 分支、循环与函数
if 根据条件选择分支;for 重复执行;函数给一段处理过程起名字,参数传入数据,返回值传回结果。
#include <stdio.h>
int sum(const int values[], int length)
{
int total = 0;
for (int i = 0; i < length; ++i) {
total += values[i];
}
return total;
}
int main(void)
{
int scores[] = {80, 90, 100};
int total = sum(scores, 3);
if (total >= 270) {
printf("total=%d, passed\n", total);
} else {
printf("total=%d, retry\n", total);
}
return 0;
}预期输出 total=270, passed。调用方把元素数量传给函数;数组形参不会自动携带数组长度,不能在 sum 中通过 sizeof(values) 推算原数组元素数。
4. 作用域、命名与注释
示例中的 total 分别属于两个函数,各自独立。优先把变量放在使用它的最小作用域;需要共享数据时先通过参数传递,不必为了演示 extern 引入可变全局变量。
名称区分大小写,不能用关键字;业务名称尽量使用普通字母开头,避免占用实现保留的下划线名称。// 注释到行尾,/* ... */ 是块注释,块注释不能嵌套。
5. 练习与后续学习
- 把数组改为四个成绩,更新传入的长度,确认总分正确。
- 将阈值作为函数参数传入,返回是否达标。
- 说明
count、&count和*p分别表示什么。
完成后再学习字符串处理、指针与数组的关系、结构体和动态内存。数制基础可先读进制转换。
参考解法与预期(先完成练习)
- 使用
int scores[] = {80, 90, 100, 70};并传长度4,预期total=340, passed。不能只增加元素却仍传3。 - 在
sum定义之后、main之前增加函数:
int meets_target(const int values[], int length, int target)
{
return sum(values, length) >= target;
}在 main 中用 meets_target(scores, 4, 340) 判断为真,阈值341为假;本练习只处理上面的少量成绩,不承诺任意整数求和都不溢出。 3. count 是整数值,&count 是该对象地址;当 p = &count 且对象仍存活时,*p 访问同一个整数。空指针不能解引用。
本文命令和新增答案仅作静态核对,示例未执行;首个程序的预期为 Hello, World! 后换行、退出0。
编译参数依据:GCC 总体选项。
继续阅读
- 开发实践
- 开发实践
- 开发实践