[C.C++] C语言详解

32 0
Honkers 昨天 20:28 | 显示全部楼层 |阅读模式

C语言详解(从基础到进阶,附实例)

一、C语言概述

1. 诞生与历史

◦ 1972年由丹尼斯·里奇(Dennis Ritchie)在贝尔实验室开发,初衷是重写UNIX操作系统(替代之前的汇编语言)。

◦ 设计哲学:“信任程序员”“保持语言小巧高效”“接近硬件但不失抽象”。

◦ 影响:C++、Java、Python等语言均受C启发,Linux内核、Unix、大部分嵌入式系统、高性能库(如OpenSSL)均用C编写。

2. 核心特点

◦ 高效性:直接操作内存,生成的机器码接近汇编,运行速度极快。

◦ 结构化语言:支持顺序、选择、循环结构,通过函数组织代码。

◦ 跨平台:通过预处理和标准库,代码可在不同系统(Windows/Linux/嵌入式)编译运行。

◦ 指针与内存控制:允许直接操作内存地址,灵活但易错(需小心野指针、内存泄漏)。

二、基础语法与数据类型

1. 第一个C程序:Hello World
#include  // 预处理指令,包含标准输入输出头文件

int main() {         // 主函数,程序入口
    printf("Hello, World!\n");  // 输出函数
    return 0;       // 返回0表示程序正常结束
}
◦ #include:将头文件内容插入当前代码(类似“复制粘贴”)。

◦ main():必须存在且返回int,操作系统通过返回值判断程序是否正常结束。

2. 数据类型
C语言数据类型分为4大类:

◦ 基本类型:
类型 大小(32位系统) 范围(有符号) 示例 
char 1字节 -128 ~ 127 char c = 'A'; 
int 4字节 -2^31 ~ 2^31-1 int num = 100; 
float 4字节 约±3.4e±38(7位有效数字) float pi = 3.14f; 
double 8字节 约±1.8e±308(15位有效数字) double e = 2.718; 

◦ 修饰符:signed(默认有符号)、unsigned(无符号,如unsigned int范围0~4294967295)、short(短整型,至少2字节)、long(长整型,至少4字节,Linux 64位下long为8字节)。

◦ 枚举类型:定义一组命名常量,增强代码可读性。
enum Color { RED, GREEN, BLUE };  // 枚举值默认从0开始
enum Color my_color = GREEN;      // my_color的值为1
◦ 派生类型:数组、指针、结构体、联合体、函数类型。

◦ 空类型:void,用于表示函数无返回值或指针无类型(如void*通用指针)。

3. 变量与常量

◦ 变量定义:类型 变量名;,需先定义后使用。
int age;        // 定义整数变量age
float weight = 65.5;  // 定义并初始化
◦ 常量:

◦ 字面值常量:如10(整数)、3.14(浮点数)、'A'(字符,占1字节)、"Hello"(字符串,末尾隐含\0,占6字节)。

◦ 符号常量:用#define或const定义。
#define PI 3.14159  // 宏定义,预处理阶段替换
const int MAX_SIZE = 100;  // 常变量,运行时不可修改
三、运算符与表达式

1. 常用运算符

◦ 算术运算符:+ - * / %(取余,仅用于整数,如7%3=1),++(自增)、--(自减)。
int a = 5, b = 2;
printf("%d", a / b);  // 输出2(整数除法取整)
◦ 赋值运算符:=(基本赋值),+=、-=、*=、/=、%=(复合赋值)。
a += 3;  // 等价于a = a + 3
◦ 关系运算符:> < >= <= == !=,结果为0(假)或1(真)。

◦ 逻辑运算符:&&(逻辑与)、||(逻辑或)、!(逻辑非),短路特性(如a && b中a为假则不计算b)。

◦ 位运算符(对二进制位操作):&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右移)。
int x = 5;  // 二进制101
printf("%d", x << 1);  // 左移1位得1010(10)
◦ sizeof运算符:计算数据类型或变量占用的字节数,如sizeof(int)通常为4。

2. 运算符优先级
记忆口诀(从高到低):
() [] -> .(最高)→ 单目运算符(! ++ -- sizeof)→ 算术运算符(先乘除取余,后加减)→ 关系运算符 → 逻辑运算符(&&先于||)→ 赋值运算符 → ,(逗号运算符,最低)。
示例:a + b * c等价于a + (b * c),因乘法优先级高于加法。

四、控制结构

1. 顺序结构:代码按书写顺序执行(如赋值、函数调用)。

2. 选择结构

◦ if语句:
int score = 85;
if (score >= 90) {
    printf("A\n");
} else if (score >= 80) {
    printf("B\n");  // 输出B
} else {
    printf("C\n");
}
◦ switch语句:用于多分支判断,case后需为常量表达式,需用break跳出(否则穿透)。
int day = 3;
switch (day) {
    case 1: printf("Monday\n"); break;
    case 2: printf("Tuesday\n"); break;
    case 3: printf("Wednesday\n"); break;  // 输出
    default: printf("Other\n");
}
3. 循环结构

◦ for循环:适用于已知次数的循环。
// 计算1+2+...+100
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum += i;
}
◦ while循环:先判断条件,后执行循环体(可能一次都不执行)。
int n = 5;
while (n > 0) {
    printf("%d ", n);  // 输出5 4 3 2 1
    n--;
}
◦ do-while循环:先执行一次循环体,再判断条件(至少执行一次)。
int m = 0;
do {
    m++;
} while (m < 0);  // 执行一次,m=1
◦ 跳出循环:break(终止整个循环),continue(跳过本次循环剩余代码,进入下一次)。

五、函数:代码复用的核心

1. 函数定义
返回类型 函数名(参数列表) {
    函数体;
    return 表达式;  // 非void类型必须返回值
}
◦ 示例:计算阶乘
int factorial(int n) {  // 值传递,n是实参的副本
    if (n == 0) return 1;
    return n * factorial(n-1);  // 递归调用
}
2. 参数传递

◦ 值传递:函数接收实参的副本,修改形参不影响实参。
void swap(int a, int b) {  // 无法真正交换外部变量
    int temp = a;
    a = b;
    b = temp;
}
◦ 指针传递:通过指针(地址)传递,可修改实参。
void swap_ptr(int *a, int *b) {  // *a是a指向的值
    int temp = *a;
    *a = *b;
    *b = temp;
}
// 调用:swap_ptr(&x, &y);  // &取x的地址
◦ 数组传递:数组名作为参数时退化为指针,需额外传递长度。
void print_array(int arr[], int len) {  // 等价于int *arr
    for (int i=0; i         printf("%d ", arr);
    }
}
3. 函数声明:若函数定义在调用之后,需在调用前声明(告知编译器函数存在)。
int max(int a, int b);  // 声明
int main() {
    printf("%d", max(3, 5));  // 调用
    return 0;
}
int max(int a, int b) {  // 定义
    return a > b ? a : b;
}
六、指针:C语言的灵魂

1. 指针基础

◦ 指针是存储内存地址的变量,用*声明。
int num = 10;
int *ptr = #  // ptr指向num的地址(&取地址)
printf("%p", ptr);  // 输出地址(如0x7fff5fbff8ac)
printf("%d", *ptr);  // 解引用,输出10(*取地址对应的值)
◦ void*通用指针:可指向任何类型,需强制类型转换后解引用。
void *p = #
int x = *(int*)p;  // 强制转换为int*后解引用
2. 指针与数组

◦ 数组名是指向首元素的常量指针,arr等价于*(arr + i)。
int arr[] = {1, 2, 3};
int *p = arr;  // p指向arr[0]
printf("%d", *(p + 1));  // 输出2(等价于arr[1])
◦ 多维数组:int arr[2][3],arr是第i行首元素的指针,arr[j]等价于*(*(arr+i)+j)。

3. 指针数组与数组指针

◦ 指针数组:数组元素是指针(如char *strs[] = {"hello", "world"};)。

◦ 数组指针:指向数组的指针(如int (*p)[5] = &arr;,p指向一个包含5个int的数组)。

4. 动态内存分配

◦ malloc(size):分配size字节的内存,返回void*,需初始化(值随机)。
int *arr = (int*)malloc(5 * sizeof(int));  // 分配5个int的空间
◦ calloc(n, size):分配n个size字节的内存,初始化为0。

◦ realloc(ptr, new_size):调整已分配内存的大小,可能移动地址。

◦ free(ptr):释放内存,释放后指针需置NULL(避免野指针)。
free(arr);
arr = NULL;
七、数组:连续存储的同类型数据

1. 定义与初始化
int scores[5] = {80, 90, 75, 85, 95};  // 初始化5个元素
char name[] = "Alice";  // 长度自动为6(包含\0)
float nums[3] = {1.1, 2.2};  // 未初始化的元素默认0.0
2. 多维数组
int matrix[2][3] = {  // 2行3列
    {1, 2, 3},
    {4, 5, 6}
};
printf("%d", matrix[1][2]);  // 输出6
八、结构体与联合体:自定义复合类型

1. 结构体(struct)

◦ 用于组合不同类型的数据,如学生信息。
struct Student {
    char name[20];
    int age;
    float score;
};  // 分号不能少

struct Student stu = {"Tom", 18, 85.5};  // 初始化
printf("Name: %s, Score: %.1f", stu.name, stu.score);  // 点运算符访问成员

struct Student *p_stu = &stu;
printf("Age: %d", p_stu->age);  // 箭头运算符访问成员
2. 联合体(union)

◦ 成员共享内存空间,同一时间只能存储一个成员(取最后一次赋值的成员)。
union Data {
    int i;
    float f;
    char c;
};

union Data d;
d.i = 10;       // 内存存10(4字节)
d.f = 3.14f;    // 覆盖前4字节,i的值无意义
九、文件操作:数据持久化

1. 文件指针:FILE *fp;,用于标识文件。

2. 打开与关闭文件
fp = fopen("data.txt", "r");  // 只读模式打开
if (fp == NULL) {  // 打开失败
    perror("Error opening file");
    return 1;
}
fclose(fp);  // 关闭文件
◦ 常用模式:"w"(写入,覆盖原有内容)、"a"(追加)、"b"(二进制模式,如"rb")。

3. 读写文件

◦ 字符级:fgetc(fp)(读字符)、fputc(c, fp)(写字符)。

◦ 格式级:fscanf(fp, "%d %s", &num, str)(读格式数据)、fprintf(fp, "%d %s", num, str)(写格式数据)。

◦ 块级:fread(buffer, size, count, fp)(读二进制块)、fwrite(buffer, size, count, fp)(写二进制块)。

4. 文件定位

◦ fseek(fp, offset, SEEK_SET):从文件开头(SEEK_SET)偏移offset字节定位。

◦ rewind(fp):回到文件开头。

十、预处理指令:编译前的文本处理

1. 宏定义(#define)

◦ 无参宏:替换文本。
#define MAX_LEN 100  // 替换所有MAX_LEN为100
#define PI 3.1415926
◦ 带参宏:类似函数,但不检查类型,需注意括号避免优先级问题。
#define SQUARE(x) ((x)*(x))  // 正确写法,避免1+2*1+2的错误
printf("%d", SQUARE(1+2));  // 输出9(正确)
2. 条件编译

◦ 避免头文件重复包含(常用#ifndef):
#ifndef MY_HEADER_H
#define MY_HEADER_H
// 头文件内容
#endif
◦ 根据条件编译代码(如调试开关):
#define DEBUG 1
#if DEBUG
    printf("Debugging...\n");
#endif
十一、常见错误与陷阱

1. 野指针:指针未初始化或指向已释放的内存,访问会导致未定义行为(崩溃或数据损坏)。
解决:定义时初始化为NULL,释放后置NULL,访问前检查if (ptr != NULL)。

2. 数组越界:访问arr[-1]或arr[5](若长度为5,下标0~4),可能覆盖其他变量或触发段错误。
解决:循环中确保下标在合法范围。

3. 未初始化变量:使用未赋值的局部变量(值为随机垃圾值)。
解决:定义时初始化(如int x = 0;)。

4. 内存泄漏:动态分配的内存未调用free(),导致内存浪费。
解决:malloc与free成对使用,复杂逻辑中用注释标记。

5. switch穿透:忘记break导致多个case执行。
解决:养成写break的习惯,或用default处理意外情况。

十二、C语言的应用场景

1. 系统编程:操作系统(Linux内核)、设备驱动、嵌入式系统(资源受限场景)。

2. 高性能计算:数值计算库(如LAPACK)、游戏引擎底层(追求速度)。

3. 网络编程:服务器程序(如Nginx),需控制内存和网络延迟。

4. 硬件交互:直接操作寄存器、端口,适合单片机开发。

十三、示例:学生信息管理(综合应用)
#include
#include
#include

// 定义学生结构体
struct Student {
    int id;
    char name[20];
    float score;
};

// 打印学生信息
void print_student(struct Student stu) {
    printf("ID: %d, Name: %s, Score: %.1f\n", stu.id, stu.name, stu.score);
}

int main() {
    // 静态分配:定义单个学生
    struct Student stu1 = {1, "Alice", 90.5};
    print_student(stu1);

    // 动态分配:创建学生数组
    int n = 2;
    struct Student *stu_arr = (struct Student*)malloc(n * sizeof(struct Student));
    if (stu_arr == NULL) {
        perror("Malloc failed");
        return 1;
    }

    // 初始化数组
    struct Student stu2 = {2, "Bob", 85.0};
    stu_arr[0] = stu1;
    stu_arr[1] = stu2;

    // 写入文件
    FILE *fp = fopen("students.txt", "w");
    if (fp != NULL) {
        for (int i=0; i             fprintf(fp, "%d %s %.1f\n", stu_arr.id, stu_arr.name, stu_arr.score);
        }
        fclose(fp);
    }

    free(stu_arr);
    return 0;
}
十四、总结与学习建议

• 优点:高效、灵活、接近底层,适合理解计算机原理。

• 缺点:安全机制少,需手动管理内存,学习曲线较陡(尤其指针和内存)。

• 学习路径:

1. 掌握基础语法、数据类型、控制结构(1-2周)。

2. 深入指针、数组、结构体(核心难点,需大量练习)。

3. 学习标准库(字符串处理string.h、内存分配stdlib.h、文件操作stdio.h)。

4. 实践项目(如计算器、简易文件管理器、嵌入式驱动)。

• 推荐工具:

◦ 编译器:GCC(Linux/macOS)、Clang、MinGW(Windows)。

◦ 调试器:GDB(命令行)、VS Code调试插件。

◦ 书籍:《C程序设计语言》(K&R,经典入门)、《C陷阱与缺陷》(进阶必读)。

通过以上内容,你将对C语言有全面的理解。记住,C语言的精髓在于指针和内存控制,务必通过大量编写代码和调试来巩固知识,避免纸上谈兵!

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

特级红客

关注
  • 3283
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行