C语言基础教程--从入门到精通
C语言基础教程–从入门到精通(总体概括)
接下来会对每一个章节进行详细的总结与整理,希望对大家有用!大家一起学习!
目录
- C语言基础教程--从入门到精通(总体概括)
- **`接下来会对每一个章节进行详细的总结与整理,希望对大家有用!大家一起学习!`**
- 第一章:C 语言概述与环境搭建
- 1.1 C 语言简介
- 1.2 开发环境搭建
- 1.3 第一个 C 程序
- 第二章:基本语法与数据类型
- 2.1 变量与常量`int age = 25; // 整型变量
- 2.2 基本数据类型
- 2.3 输入输出
- 第三章:运算符与表达式
- 3.1 算术运算符
- 3.2 关系运算符
- 3.3 逻辑运算符
- 第四章:控制结构
- 4.1 条件语句
- 4.2 循环结构
- 第五章:函数
- 5.1 函数定义与调用
- 5.2 递归函数
- 第六章:数组与字符串
- 6.1 一维数组
- 6.2 多维数组
- 6.3 字符串处理
- 第七章:指针
- 7.1 指针基础
- 7.2 指针与数组
- 7.3 指针与函数
- 第八章:结构体与联合体
- 8.1 结构体定义与使用
- 8.2 联合体
- 第九章:文件操作
- 9.1 文件读写基础
- 9.2 二进制文件操作
- 第十章:动态内存管理
- 10.1 malloc 和 free
- 10.2 calloc 和 realloc
- 第十一章:高级主题
- 11.1 函数指针
- 11.2 多文件编程
- 第十二章:最佳实践与调试
- 12.1 代码规范
- 12.2 调试技巧
- 12.3 常见错误
第一章:C 语言概述与环境搭建
1.1 C 语言简介
C 语言由 Dennis Ritchie 于 1972 年在贝尔实验室开发,是一种高效、灵活的通用编程语言。它结合了低级语言的高效性和高级语言的可读性,被称为"系统编程语言"的基石。
主要特点:
1.结构化编程
2.内存直接访问
3.高效执行速度
4.丰富的运算符
5.可移植性强
1.2 开发环境搭建
Windows 环境:
1.安装 MinGW(GCC for Windows)
2.安装代码编辑器(VS Code、Dev-C++)
3.配置环境变量
Linux/macOS 环境:
# 安装 GCC
sudo apt-get install gcc # Ubuntu/Debian
brew install gcc # macOS# 验证安装
gcc --version
1.3 第一个 C 程序
#include <stdio.h> // 标准输入输出头文件int main() { // 程序入口函数printf("Hello, World!\n"); // 输出语句return 0; // 程序正常结束
}
编译与运行:
gcc hello.c -o hello # 编译
./hello # 运行 (Linux/macOS)
hello.exe # 运行 (Windows)
第二章:基本语法与数据类型
2.1 变量与常量`int age = 25; // 整型变量
float salary = 8500.50; // 浮点型变量
const double PI = 3.14159; // 常量
char grade = ‘A’; // 字符变量`
2.2 基本数据类型
类型 | 大小 (字节) | 范围 | 格式说明符 |
---|---|---|---|
char | 1 | -128 到 127 | %c |
int | 4 | -2^31 到 2^31-1 | %d |
float | 4 | 3.4E-38 到 3.4E+38 | %f |
double | 8 | 1.7E-308 到 1.7E+308 | %lf |
void | – | 无值 | – |
2.3 输入输出
#include <stdio.h>int main() {int num;printf("请输入一个整数: ");scanf("%d", &num); // 读取输入printf("你输入的是: %d\n", num);printf("浮点数: %.2f\n", 3.14159); // 保留两位小数return 0;
}
第三章:运算符与表达式
3.1 算术运算符
int a = 10, b = 3;
int sum = a + b; // 13
int diff = a - b; // 7
int product = a * b; // 30
int quotient = a / b; // 3 (整数除法)
int remainder = a % b; // 1
3.2 关系运算符
int x = 5, y = 10;
printf("%d\n", x == y); // 0 (false)
printf("%d\n", x != y); // 1 (true)
printf("%d\n", x > y); // 0
printf("%d\n", x < y); // 1
3.3 逻辑运算符
int age = 25;
int hasLicense = 1; // trueif (age >= 18 && hasLicense) {printf("可以开车\n");
}if (age < 18 || !hasLicense) {printf("不能开车\n");
}
第四章:控制结构
4.1 条件语句
// if-else
int score = 85;
if (score >= 90) {printf("优秀\n");
} else if (score >= 60) {printf("及格\n");
} else {printf("不及格\n");
}// switch-case
char grade = 'B';
switch(grade) {case 'A': printf("优秀\n");break;case 'B': printf("良好\n");break;default:printf("其他\n");
}
4.2 循环结构
// for 循环
for(int i = 0; i < 5; i++) {printf("%d ", i); // 0 1 2 3 4
}// while 循环
int count = 5;
while(count > 0) {printf("%d ", count--); // 5 4 3 2 1
}// do-while 循环
int num;
do {printf("请输入正数: ");scanf("%d", &num);
} while(num <= 0);
第五章:函数
5.1 函数定义与调用
#include <stdio.h>// 函数声明
int add(int a, int b);int main() {int result = add(5, 3);printf("5 + 3 = %d\n", result);return 0;
}// 函数定义
int add(int a, int b) {return a + b;
}
5.2 递归函数
// 计算阶乘
int factorial(int n) {if (n == 0 || n == 1)return 1;elsereturn n * factorial(n - 1);
}int main() {printf("5! = %d\n", factorial(5)); // 120return 0;
}
第六章:数组与字符串
6.1 一维数组
// 声明与初始化
int numbers[5] = {1, 2, 3, 4, 5};// 访问元素
printf("第一个元素: %d\n", numbers[0]); // 1// 遍历数组
for(int i = 0; i < 5; i++) {printf("%d ", numbers[i]);
}
6.2 多维数组
// 二维数组(矩阵)
int matrix[2][3] = {{1, 2, 3},{4, 5, 6}
};// 访问元素
printf("第二行第一列: %d\n", matrix[1][0]); // 4
6.3 字符串处理
注意:这段代码在运行时可能会报错,主要原因是缓冲区溢出问题。
#include <string.h>char str1[20] = "Hello";
char str2[] = "World";// 字符串连接
strcat(str1, " ");
strcat(str1, str2); // "Hello World"// 字符串长度
int len = strlen(str1); // 11// 字符串比较
if(strcmp(str1, "Hello World") == 0) {printf("字符串相等\n");
}
错误原因分析:
1.内存计算错误:
初始str1内容:“Hello”(5字符) + ‘\0’ = 6字节
添加空格后:"Hello "(6字符) + ‘\0’ = 7字节
添加"World"后:“Hello World”(11字符) + ‘\0’ = 12字节
虽然12 < 20,但问题出在strcat的工作机制
2.strcat函数的工作方式:
strcat会从目标字符串的结束符’\0’处开始追加新内容
第一次strcat(str1, " “)后:str1变为"Hello \0”
第二次strcat(str1, str2)时:
从’ ‘后的’\0’开始覆盖
追加"World"(5字符)和结束符’\0’
最终得到"Hello World\0"(12字节)
缓冲区溢出风险:
虽然本例最终长度12 < 20,但如果初始数组更小(如char str1[12]),会溢出
实际开发中这种写法有隐患
解决方案
方法1:确保足够缓冲区 + 安全初始化
#include <stdio.h>
#include <string.h>int main() {// 增大缓冲区并初始化为全零char str1[20] = {0};char str2[] = "World";// 安全拷贝初始值strcpy(str1, "Hello");strcat(str1, " ");strcat(str1, str2);printf("连接结果: %s\n", str1); // Hello Worldprintf("长度: %zu\n", strlen(str1)); // 11if(strcmp(str1, "Hello World") == 0) {printf("字符串相等\n");}return 0;
}
方法2:使用更安全的 snprintf (推荐)
#include <stdio.h>
#include <string.h>int main() {char str1[20];const char* str2 = "World";// 安全格式化拼接snprintf(str1, sizeof(str1), "%s %s", "Hello", str2);printf("结果: %s\n", str1);return 0;
}
方法3:手动控制拼接过程
#include <stdio.h>
#include <string.h>int main() {char str1[20] = "Hello";char str2[] = "World";// 计算剩余空间size_t remain = sizeof(str1) - strlen(str1) - 1; // 安全追加strncat(str1, " ", remain);remain -= 1; // 更新剩余空间strncat(str1, str2, remain);printf("%s\n", str1);return 0;
}
为什么原始代码可能崩溃:
如果编译器在内存中布局时,str1后面紧跟着受保护的内存区域,即使12<20,连续两次strcat操作可能触发内存保护机制(如Stack Canary)。使用安全函数可避免这类问题。
第七章:指针
7.1 指针基础
int num = 10;
int *ptr = # // ptr指向num的地址printf("num的值: %d\n", num); // 10
printf("num的地址: %p\n", &num); // 内存地址
printf("ptr的值: %p\n", ptr); // 与&num相同
printf("ptr指向的值: %d\n", *ptr); // 10
7.2 指针与数组
int arr[3] = {10, 20, 30};
int *ptr = arr; // 指向数组首元素printf("第一个元素: %d\n", *ptr); // 10
printf("第二个元素: %d\n", *(ptr+1)); // 20
7.3 指针与函数
// 通过指针交换两个变量的值
void swap(int *a, int *b) {int temp = *a;*a = *b;*b = temp;
}int main() {int x = 5, y = 10;swap(&x, &y);printf("x=%d, y=%d", x, y); // x=10, y=5return 0;
}
第八章:结构体与联合体
8.1 结构体定义与使用
// 定义结构体
struct Student {char name[50];int age;float gpa;
};int main() {// 声明结构体变量struct Student stu1;// 访问成员strcpy(stu1.name, "张三");stu1.age = 20;stu1.gpa = 3.8;// 结构体指针struct Student *ptr = &stu1;printf("姓名: %s\n", ptr->name); // 张三return 0;
}
8.2 联合体
union Data {int i;float f;char str[20];
};int main() {union Data data;data.i = 10;printf("整数: %d\n", data.i);data.f = 3.14;printf("浮点数: %.2f\n", data.f); // 覆盖之前的值return 0;
}
第九章:文件操作
9.1 文件读写基础
#include <stdio.h>int main() {FILE *file;// 写入文件file = fopen("test.txt", "w");if(file != NULL) {fprintf(file, "Hello, File!\n");fclose(file);}// 读取文件char buffer[100];file = fopen("test.txt", "r");if(file != NULL) {while(fgets(buffer, 100, file) != NULL) {printf("%s", buffer);}fclose(file);}return 0;
}
9.2 二进制文件操作
struct Product {int id;char name[50];float price;
};int main() {// 写入二进制数据struct Product p1 = {1, "Laptop", 999.99};FILE *file = fopen("products.dat", "wb");fwrite(&p1, sizeof(struct Product), 1, file);fclose(file);// 读取二进制数据struct Product p2;file = fopen("products.dat", "rb");fread(&p2, sizeof(struct Product), 1, file);printf("产品: %s, 价格: %.2f\n", p2.name, p2.price);fclose(file);return 0;
}
第十章:动态内存管理
10.1 malloc 和 free
#include <stdlib.h>int main() {// 分配内存int *arr = (int*)malloc(5 * sizeof(int));if(arr == NULL) {printf("内存分配失败\n");return 1;}// 使用内存for(int i = 0; i < 5; i++) {arr[i] = i * 10;}// 释放内存free(arr);return 0;
}
10.2 calloc 和 realloc
int main() {// 分配并初始化内存int *arr = (int*)calloc(5, sizeof(int));// 重新分配内存arr = (int*)realloc(arr, 10 * sizeof(int));// 使用更大的数组for(int i = 5; i < 10; i++) {arr[i] = i * 10;}// 释放内存free(arr);return 0;
}
第十一章:高级主题
11.1 函数指针
#include <stdio.h>// 加法函数
int add(int a, int b) {return a + b;
}// 减法函数
int subtract(int a, int b) {return a - b;
}int main() {// 声明函数指针int (*operation)(int, int);// 指向加法函数operation = add;printf("5 + 3 = %d\n", operation(5, 3));// 指向减法函数operation = subtract;printf("5 - 3 = %d\n", operation(5, 3));return 0;
}
11.2 多文件编程
main.c:
#include <stdio.h>
#include "math_operations.h"int main() {printf("5 + 3 = %d\n", add(5, 3));printf("5 - 3 = %d\n", subtract(5, 3));return 0;
}
math_operations.h:
#ifndef MATH_OPERATIONS_H
#define MATH_OPERATIONS_Hint add(int a, int b);
int subtract(int a, int b);#endif
math_operations.c:
#include "math_operations.h"int add(int a, int b) {return a + b;
}int subtract(int a, int b) {return a - b;
}
编译命令:
gcc main.c math_operations.c -o program
第十二章:最佳实践与调试
12.1 代码规范
1.使用有意义的变量名
2.添加必要的注释
3.保持函数简洁(不超过50行)
4.使用适当的缩进(推荐4空格)
5.避免使用全局变量
12.2 调试技巧
1.使用printf调试
2.编译器警告选项:
gcc -Wall -Wextra -pedantic program.c -o program
3.使用GDB调试器:
gcc -g program.c -o program
gdb ./program
12.3 常见错误
// 1. 数组越界
int arr[5] = {1,2,3,4,5};
printf("%d", arr[5]); // 无效访问// 2. 未初始化指针
int *ptr;
printf("%d", *ptr); // 未定义行为// 3. 内存泄漏
int *data = malloc(100 * sizeof(int));
// 忘记 free(data)// 4. 悬空指针
int *ptr = malloc(sizeof(int));
free(ptr);
printf("%d", *ptr); // 访问已释放内存
结语:C 语言学习路径
基础阶段:掌握语法、数据类型、控制结构
进阶阶段:深入指针、内存管理、文件操作
高级阶段:学习数据结构、算法、系统编程
精通阶段:研究操作系统内核、编译器开发