外观
C 语言笔记
约 3339 字大约 11 分钟
2025-08-16
一、C 语言基础
1.1 什么是 C 语言?
C 语言是一种通用的、过程式的编程语言,最初于 1972 年由丹尼斯·里奇(Dennis Ritchie)在贝尔实验室开发,主要用于编写 Unix 操作系统。C 语言具有以下核心特点:
- 低级语言特性:能够直接操作硬件、管理内存、与操作系统交互
- 可移植性:相对容易移植到不同硬件架构和操作系统
- 简洁高效:语法相对简单,编译后生成的代码效率高
- 灵活性:对程序员限制较少,提供强大的底层控制能力
1.2 为什么学习 C 语言?
- 基础性:现代许多流行语言(C++、Java、C#、JavaScript 等)都受 C 语言影响
- 系统编程:操作系统、嵌入式系统、驱动程序等底层开发的首选语言
- 性能关键:对性能要求高的场景(如游戏引擎、数据库)的重要组成部分
- 理解计算机原理:学习 C 有助于理解内存管理、指针等计算机基础概念
1.3 编译过程
C 语言是编译型语言,源码需要通过编译器转换为可执行文件:
- 预处理:处理
#include、#define等预处理指令 - 编译:将预处理后的代码转换为汇编语言
- 汇编:将汇编语言转换为目标代码(机器码)
- 链接:将目标代码与库函数链接,生成可执行文件
常用编译命令:
gcc hello.c -o hello # 编译 hello.c 生成可执行文件 hello
./hello # 运行可执行文件1.4 基本程序结构
Hello World 示例:
#include <stdio.h>
int main(void) {
// 打印 Hello World
printf("Hello World\n");
return 0;
}程序结构解析:
#include <stdio.h>:预处理器指令,包含标准输入输出头文件int main(void):主函数,程序入口点printf("Hello World\n"):打印字符串到控制台return 0:返回 0 表示程序正常结束
二、基础语法
2.1 注释
单行注释:
// 这是单行注释
int x = 10; // 也可以放在语句尾部多行注释:
/*
这是多行注释
可以跨越多行
*/2.2 标识符与命名规范
命名规则:
- 由字母、数字和下划线组成
- 首字符不能是数字
- 区分大小写
- 不能使用 C 语言关键字作为标识符
最佳实践:
- 变量名用小写:
int student_count; - 常量名用大写:
#define MAX_SIZE 100 - 命名应"见名知意"
2.3 关键字
C 语言有 32 个关键字,例如:
int,char,float,double:数据类型if,else,switch,case:条件语句for,while,do:循环语句return:返回语句struct,union,enum:复合类型
三、数据类型
3.1 基本数据类型
| 类型 | 描述 | 存储大小 | 值范围 |
|---|---|---|---|
char | 字符或小整数 | 1 字节 | -128 到 127 或 0 到 255 |
int | 整数 | 2 或 4 字节 | -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647 |
float | 单精度浮点数 | 4 字节 | 精度 6 位小数 |
double | 双精度浮点数 | 8 字节 | 精度 15 位小数 |
void | 无类型 | 无 | 不适用 |
有符号与无符号:
unsigned int:0 到 65,535 或 0 到 4,294,967,295signed int:默认有符号,范围如上表
3.2 变量声明与初始化
基本语法:
// 声明变量
int age;
// 声明并初始化
int age = 18;
float pi = 3.14159;
char grade = 'A';
// 多个同类型变量
int x = 1, y = 2, z = 3;注意:
- C 语言会在变量声明时分配内存,但不会自动清零
- 变量必须先声明后使用
- 变量的值应该与类型一致
3.3 常量
使用 #define:
#define PI 3.14159
#define MAX_SIZE 100
#define GREETING "Hello, World"
int main() {
printf("PI = %f\n", PI);
printf("Max size = %d\n", MAX_SIZE);
return 0;
}使用 const:
const int MAX_SIZE = 100;
const float PI = 3.14159;
int main() {
// MAX_SIZE = 200; // 错误:不能修改常量
return 0;
}预定义宏:
#include <stdio.h>
int main() {
printf("This function: %s\n", __func__);
printf("This file: %s\n", __FILE__);
printf("This line: %d\n", __LINE__);
printf("Compiled on: %s %s\n", __DATE__, __TIME__);
printf("C Version: %ld\n", __STDC_VERSION__);
return 0;
}四、运算符
4.1 算术运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
+ | 加法 | a + b |
- | 减法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取模(求余) | a % b |
++ | 自增 | a++ 或 ++a |
-- | 自减 | a-- 或 --a |
示例:
int a = 10, b = 3;
printf("a + b = %d\n", a + b); // 13
printf("a - b = %d\n", a - b); // 7
printf("a * b = %d\n", a * b); // 30
printf("a / b = %d\n", a / b); // 3 (整数除法)
printf("a %% b = %d\n", a % b); // 14.2 关系运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
== | 等于 | a == b |
!= | 不等于 | a != b |
> | 大于 | a > b |
< | 小于 | a < b |
>= | 大于等于 | a >= b |
<= | 小于等于 | a <= b |
示例:
int a = 5, b = 10;
printf("a == b: %d\n", a == b); // 0 (false)
printf("a != b: %d\n", a != b); // 1 (true)
printf("a > b: %d\n", a > b); // 0
printf("a < b: %d\n", a < b); // 14.3 逻辑运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
&& | 逻辑与 | a && b |
| ` | ` | |
! | 逻辑非 | !a |
示例:
int a = 1, b = 0;
printf("a && b = %d\n", a && b); // 0
printf("a || b = %d\n", a || b); // 1
printf("!a = %d\n", !a); // 04.4 位运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
& | 按位与 | a & b |
| ` | ` | 按位或 |
^ | 按位异或 | a ^ b |
~ | 按位取反 | ~a |
<< | 左移 | a << b |
>> | 右移 | a >> b |
示例:
unsigned int a = 60; // 0011 1100
unsigned int b = 13; // 0000 1101
int c = 0;
c = a & b; // 12 = 0000 1100
c = a | b; // 61 = 0011 1101
c = a ^ b; // 49 = 0011 0001
c = ~a; // -61 = 1100 0011
c = a << 2; // 240 = 1111 0000
c = a >> 2; // 15 = 0000 11114.5 赋值运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
= | 简单赋值 | c = a + b |
+= | 加且赋值 | c += a 相当于 c = c + a |
-= | 减且赋值 | c -= a 相当于 c = c - a |
*= | 乘且赋值 | c *= a 相当于 c = c * a |
/= | 除且赋值 | c /= a 相当于 c = c / a |
%= | 求模且赋值 | c %= a 相当于 c = c % a |
示例:
int a = 10, c;
c = a; // c = 10
c += a; // c = 20
c -= a; // c = 10
c *= a; // c = 100
c /= a; // c = 10
c %= a; // c = 04.6 运算符优先级
| 优先级 | 运算符 | 结合性 |
|---|---|---|
| 1 | () [] -> . | 从左到右 |
| 2 | ! ~ ++ -- + - (type) * & sizeof | 从右到左 |
| 3 | * / % | 从左到右 |
| 4 | + - | 从左到右 |
| 5 | << >> | 从左到右 |
| 6 | < <= > >= | 从左到右 |
| 7 | == != | 从左到右 |
| 8 | & | 从左到右 |
| 9 | ^ | 从左到右 |
| 10 | ` | ` |
| 11 | && | 从左到右 |
| 12 | ` | |
| 13 | ?: | 从右到左 |
| 14 | = += -= *= /= %= <<= >>= &= ^= ` | =` |
| 15 | , | 从左到右 |
最佳实践:
- 使用括号明确运算顺序,提高代码可读性
- 避免编写过于复杂的表达式
五、流程控制
5.1 条件语句
if 语句:
int score = 85;
if (score >= 90) {
printf("优秀\n");
} else if (score >= 80) {
printf("良好\n");
} else if (score >= 70) {
printf("中等\n");
} else {
printf("需要努力\n");
}switch 语句:
char grade = 'B';
switch (grade) {
case 'A':
printf("优秀\n");
break;
case 'B':
case 'C':
printf("良好\n");
break;
case 'D':
printf("及格\n");
break;
default:
printf("不及格\n");
}5.2 循环语句
for 循环:
// 打印 1 到 10
for (int i = 1; i <= 10; i++) {
printf("%d ", i);
}while 循环:
int i = 1;
while (i <= 10) {
printf("%d ", i);
i++;
}do-while 循环:
int i = 1;
do {
printf("%d ", i);
i++;
} while (i <= 10);循环控制:
break:跳出当前循环continue:跳过当前迭代,继续下一次循环
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break; // 当 i 为 5 时跳出循环
}
if (i % 2 == 0) {
continue; // 跳过偶数
}
printf("%d ", i);
}六、函数
6.1 函数基础
函数定义:
// 返回类型 函数名(参数列表) {
// 函数体
// return 返回值;
// }
int max(int num1, int num2) {
int result;
if (num1 > num2) {
result = num1;
} else {
result = num2;
}
return result;
}函数声明:
// 在 main 函数前声明
int max(int num1, int num2);
int main() {
int a = 100;
int b = 200;
int ret;
ret = max(a, b);
printf("Max value is: %d\n", ret);
return 0;
}6.2 参数传递
值传递:
void swap(int x, int y) {
int temp;
temp = x;
x = y;
y = temp;
}
// 调用后原值不会改变指针传递:
void swap(int *x, int *y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
}
// 调用后原值会改变6.3 作用域
局部变量:
- 在函数或代码块内部定义
- 只在定义它的函数或代码块内有效
全局变量:
- 在所有函数外部定义
- 从定义位置开始到文件结束都有效
#include <stdio.h>
int globalVar = 10; // 全局变量
void func() {
int localVar = 20; // 局部变量
printf("globalVar = %d\n", globalVar);
printf("localVar = %d\n", localVar);
}
int main() {
func();
printf("globalVar = %d\n", globalVar);
// printf("localVar = %d\n", localVar); // 错误:localVar 在此作用域不可见
return 0;
}七、数组与字符串
7.1 数组
一维数组:
// 声明并初始化
int numbers[5] = {1, 2, 3, 4, 5};
float prices[3] = {10.5, 20.7, 30.9};
char chars[4] = {'a', 'b', 'c', '\0'};
// 访问数组元素
printf("First element: %d\n", numbers[0]);
printf("Last element: %d\n", numbers[4]);
// 修改数组元素
numbers[2] = 10;二维数组:
// 声明并初始化
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// 访问元素
printf("matrix[1][2] = %d\n", matrix[1][2]); // 67.2 字符串
字符串定义:
// 使用字符数组
char str1[20] = "Hello";
char str2[] = "World"; // 编译器自动计算大小
// 字符串以 '\0' 结尾
char str3[6] = {'H', 'e', 'l', 'l', 'o', '\0'};常用字符串函数:
#include <string.h>
char str1[20] = "Hello";
char str2[20] = "World";
char str3[40];
// 复制字符串
strcpy(str3, str1); // str3 = "Hello"
// 连接字符串
strcat(str3, " "); // str3 = "Hello "
strcat(str3, str2); // str3 = "Hello World"
// 比较字符串
if (strcmp(str1, str2) == 0) {
printf("Strings are equal\n");
} else {
printf("Strings are not equal\n");
}
// 获取字符串长度
int len = strlen(str3); // len = 11八、指针
8.1 指针基础
指针定义:
int var = 10; // 实际变量声明
int *p; // 指针变量声明
p = &var; // 在指针变量中存储 var 的地址
printf("Address of var variable: %p\n", &var);
printf("Address stored in p variable: %p\n", p);
printf("Value of *p variable: %d\n", *p);指针运算:
int var = 20;
int *p;
p = &var;
printf("Value of var variable: %d\n", var);
printf("Address stored in p variable: %p\n", p);
printf("Value of *p variable: %d\n", *p);
*p = 30; // 修改指针指向的值
printf("New value of var: %d\n", var); // 308.2 指针与数组
数组指针:
int arr[5] = {10, 20, 30, 40, 50};
int *p;
p = arr; // 等同于 p = &arr[0]
for (int i = 0; i < 5; i++) {
printf("*(p + %d) : %d\n", i, *(p + i));
}指针数组:
const int MAX = 3;
int var[] = {10, 100, 200};
int *ptr[MAX];
for (int i = 0; i < MAX; i++) {
ptr[i] = &var[i]; // 赋值为整数的地址
}
for (int i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, *ptr[i]);
}8.3 指针与函数
传递指针给函数:
void swap(int *x, int *y) {
int temp;
temp = *x;
*x = *y;
*y = temp;
}
int main() {
int a = 100, b = 200;
printf("Before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("After swap: a = %d, b = %d\n", a, b);
return 0;
}九、结构体
9.1 结构体定义与使用
定义结构体:
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};创建结构体变量:
// 方法1:先定义结构体,再声明变量
struct Books book1, book2;
// 方法2:定义结构体的同时声明变量
struct Books {
// 成员
} book1, book2;
// 方法3:使用 typedef 简化
typedef struct {
char title[50];
char author[50];
char subject[100];
int book_id;
} Book;
Book book1, book2;访问结构体成员:
strcpy(book1.title, "C Programming");
strcpy(book1.author, "Nuha Ali");
strcpy(book1.subject, "C Programming Tutorial");
book1.book_id = 6495407;
printf("Book title: %s\n", book1.title);
printf("Book author: %s\n", book1.author);
printf("Book subject: %s\n", book1.subject);
printf("Book book_id: %d\n", book1.book_id);结构体指针:
struct Books *ptr;
ptr = &book1;
printf("Book title: %s\n", ptr->title);
printf("Book author: %s\n", ptr->author);十、文件操作
10.1 文件打开与关闭
打开文件:
FILE *fp;
fp = fopen("file.txt", "r"); // 以只读方式打开文件模式:
| 模式 | 描述 |
|---|---|
"r" | 以只读方式打开文件 |
"w" | 以写入方式打开文件(如果文件存在则清空) |
"a" | 以追加方式打开文件 |
"r+" | 以读写方式打开文件 |
"w+" | 以读写方式打开文件(如果文件存在则清空) |
"a+" | 以读写方式打开文件(追加模式) |
关闭文件:
fclose(fp);10.2 文件读写操作
字符读写:
// 写入字符
fputc('A', fp);
// 读取字符
char c = fgetc(fp);字符串读写:
// 写入字符串
fputs("Hello World", fp);
// 读取字符串
char buffer[100];
fgets(buffer, 100, fp);格式化读写:
// 写入格式化数据
fprintf(fp, "Value: %d\n", 10);
// 读取格式化数据
int value;
fscanf(fp, "%d", &value);二进制读写:
// 写入二进制数据
fwrite(&data, sizeof(data_type), 1, fp);
// 读取二进制数据
fread(&data, sizeof(data_type), 1, fp);十一、实用技巧与最佳实践
11.1 内存管理
动态内存分配:
#include <stdlib.h>
int *p;
p = (int *)malloc(5 * sizeof(int)); // 分配 5 个整数的空间
if (p == NULL) {
printf("内存分配失败\n");
exit(1);
}
// 使用内存
for (int i = 0; i < 5; i++) {
p[i] = i + 1;
}
// 释放内存
free(p);内存分配函数:
malloc(size):分配指定大小的内存calloc(num, size):分配并初始化内存realloc(ptr, size):调整已分配内存的大小free(ptr):释放内存
11.2 错误处理
检查文件操作:
FILE *fp = fopen("file.txt", "r");
if (fp == NULL) {
printf("无法打开文件\n");
exit(1);
}检查内存分配:
int *p = (int *)malloc(10 * sizeof(int));
if (p == NULL) {
printf("内存分配失败\n");
exit(1);
}11.3 预处理器指令
条件编译:
#define DEBUG
#ifdef DEBUG
printf("Debug mode enabled\n");
#endif
#ifndef DEBUG
printf("Debug mode disabled\n");
#endif宏定义:
#define PI 3.14159
#define SQUARE(x) ((x) * (x))
int main() {
printf("PI = %f\n", PI);
printf("Square of 5 = %d\n", SQUARE(5));
return 0;
}