C语言新手知识大全(三)

简介: 教程来源 https://app-adzoyybqtaf5.appmiaoda.com 本教程系统讲解C语言核心概念:指针(基础、数组、函数应用)、结构体与联合体、动态内存管理、文件I/O、预处理指令,并以学生管理系统实战贯穿,代码规范、注释清晰,助初学者扎实掌握C语言精髓。

七、指针

7.1 指针基础
指针是C语言最核心、最强大的特性,也是初学者最困惑的部分。

#include <stdio.h>

int main() {
    int num = 42;

    // 指针变量:存储地址
    int *ptr = &num;   // &取地址符

    // 打印地址和值
    printf("num的值:%d\n", num);
    printf("num的地址:%p\n", &num);
    printf("ptr的值(地址):%p\n", ptr);
    printf("ptr指向的值:%d\n", *ptr);  // *解引用符

    // 通过指针修改变量
    *ptr = 100;
    printf("修改后num的值:%d\n", num);

    // 指针的大小
    printf("指针大小:%zu 字节\n", sizeof(ptr));

    // 空指针
    int *nullPtr = NULL;
    if (nullPtr == NULL) {
        printf("空指针\n");
    }

    return 0;
}

7.2 指针与数组

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};

    // 数组名是指向首元素的指针
    int *ptr = arr;  // 等价于 &arr[0]

    // 使用指针访问数组元素
    printf("arr[0] = %d, *ptr = %d\n", arr[0], *ptr);
    printf("arr[1] = %d, *(ptr+1) = %d\n", arr[1], *(ptr + 1));

    // 指针运算
    printf("指针加法:ptr+2 指向 %d\n", *(ptr + 2));

    // 遍历数组
    printf("数组元素:");
    for (int i = 0; i < 5; i++) {
        printf("%d ", *(ptr + i));
    }
    printf("\n");

    // 使用指针遍历
    printf("指针遍历:");
    int *p = arr;
    int *end = arr + 5;
    while (p < end) {
        printf("%d ", *p);
        p++;
    }
    printf("\n");

    // 二维数组与指针
    int matrix[2][3] = {
  {1, 2, 3}, {4, 5, 6}};
    int (*row)[3] = matrix;  // 指向一维数组的指针

    printf("matrix[1][2] = %d\n", row[1][2]);
    printf("*(*(matrix+1)+2) = %d\n", *(*(matrix + 1) + 2));

    return 0;
}

7.3 指针与函数

#include <stdio.h>

// 指针作为函数参数(实现多返回值)
void get_min_max(int arr[], int size, int *min, int *max) {
    *min = arr[0];
    *max = arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] < *min) *min = arr[i];
        if (arr[i] > *max) *max = arr[i];
    }
}

// 函数指针:指向函数的指针
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }

int calculate(int (*operation)(int, int), int x, int y) {
    return operation(x, y);
}

// 返回指针的函数
int* find_max(int arr[], int size) {
    int *max = &arr[0];
    for (int i = 1; i < size; i++) {
        if (arr[i] > *max) {
            max = &arr[i];
        }
    }
    return max;
}

int main() {
    // 多返回值
    int numbers[] = {3, 7, 1, 9, 4, 2, 8, 5, 6};
    int min, max;
    get_min_max(numbers, 9, &min, &max);
    printf("最小值:%d,最大值:%d\n", min, max);

    // 函数指针
    printf("add: %d\n", calculate(add, 10, 5));
    printf("subtract: %d\n", calculate(subtract, 10, 5));
    printf("multiply: %d\n", calculate(multiply, 10, 5));

    // 函数指针数组
    int (*operations[])(int, int) = {add, subtract, multiply};
    for (int i = 0; i < 3; i++) {
        printf("结果%d: %d\n", i, operations[i](10, 5));
    }

    // 返回指针的函数
    int *maxPtr = find_max(numbers, 9);
    printf("最大值:%d,地址:%p\n", *maxPtr, maxPtr);

    return 0;
}

八、结构体与联合体

8.1 结构体

#include <stdio.h>
#include <string.h>

// 结构体定义
struct Student {
    int id;
    char name[50];
    int age;
    float score;
};

// 结构体别名(typedef)
typedef struct {
    int year;
    int month;
    int day;
} Date;

// 结构体嵌套
struct Teacher {
    char name[50];
    Date birthDate;
    struct Student* students;  // 指向学生的指针
};

int main() {
    // 结构体变量声明与初始化
    struct Student stu1 = {1001, "张三", 20, 85.5};
    struct Student stu2;

    // 访问成员
    stu2.id = 1002;
    strcpy(stu2.name, "李四");
    stu2.age = 21;
    stu2.score = 92.0;

    printf("学生信息:\n");
    printf("学号:%d\n", stu1.id);
    printf("姓名:%s\n", stu1.name);
    printf("年龄:%d\n", stu1.age);
    printf("成绩:%.1f\n", stu1.score);

    // 结构体数组
    struct Student class[3] = {
        {1001, "张三", 20, 85.5},
        {1002, "李四", 21, 92.0},
        {1003, "王五", 19, 78.5}
    };

    printf("\n班级学生:\n");
    for (int i = 0; i < 3; i++) {
        printf("%d\t%s\t%.1f\n", class[i].id, class[i].name, class[i].score);
    }

    // 结构体指针
    struct Student *ptr = &stu1;
    printf("\n通过指针访问:\n");
    printf("姓名:%s\n", ptr->name);  // 等价于 (*ptr).name
    printf("成绩:%.1f\n", ptr->score);

    // 计算平均分
    float sum = 0;
    for (int i = 0; i < 3; i++) {
        sum += class[i].score;
    }
    printf("班级平均分:%.1f\n", sum / 3);

    // 结构体大小
    printf("Student大小:%zu 字节\n", sizeof(struct Student));
    printf("Date大小:%zu 字节\n", sizeof(Date));

    return 0;
}

8.2 联合体与枚举

#include <stdio.h>

// 联合体:所有成员共享同一块内存
union Data {
    int i;
    float f;
    char str[20];
};

// 枚举
enum Color {
    RED,    // 0
    GREEN,  // 1
    BLUE    // 2
};

enum Weekday {
    MON = 1,
    TUE,
    WED,
    THU,
    FRI,
    SAT,
    SUN
};

// 联合体与结构体结合
struct Variant {
    enum { TYPE_INT, TYPE_FLOAT, TYPE_STRING } type;
    union {
        int intVal;
        float floatVal;
        char stringVal[50];
    } value;
};

void printVariant(struct Variant v) {
    switch (v.type) {
        case TYPE_INT:
            printf("整数:%d\n", v.value.intVal);
            break;
        case TYPE_FLOAT:
            printf("浮点数:%.2f\n", v.value.floatVal);
            break;
        case TYPE_STRING:
            printf("字符串:%s\n", v.value.stringVal);
            break;
    }
}

int main() {
    // 联合体
    union Data data;
    data.i = 100;
    printf("data.i = %d\n", data.i);
    printf("data.f = %f\n", data.f);  // 垃圾值

    data.f = 3.14;
    printf("data.f = %f\n", data.f);
    printf("data.i = %d\n", data.i);  // 被覆盖

    printf("联合体大小:%zu 字节\n", sizeof(union Data));

    // 枚举
    enum Color color = RED;
    printf("RED = %d\n", color);

    enum Weekday today = WED;
    if (today == WED) {
        printf("今天是星期三\n");
    }

    // 联合体与结构体结合(类型安全)
    struct Variant v1 = {TYPE_INT, .value.intVal = 42};
    struct Variant v2 = {TYPE_FLOAT, .value.floatVal = 3.14159};
    struct Variant v3 = {TYPE_STRING, .value.stringVal = "Hello"};

    printVariant(v1);
    printVariant(v2);
    printVariant(v3);

    return 0;
}

九、动态内存管理

9.1 malloc、calloc、realloc、free

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
    // malloc:分配内存,不初始化
    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;
    }

    printf("malloc分配:");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // calloc:分配内存并初始化为0
    int *arr2 = (int*)calloc(5, sizeof(int));
    if (arr2 == NULL) {
        printf("内存分配失败\n");
        free(arr);
        return 1;
    }

    printf("calloc分配(自动清零):");
    for (int i = 0; i < 5; i++) {
        printf("%d ", arr2[i]);
    }
    printf("\n");

    // realloc:重新分配内存大小
    int *arr3 = (int*)realloc(arr, 10 * sizeof(int));
    if (arr3 == NULL) {
        printf("内存重新分配失败\n");
        free(arr);
        free(arr2);
        return 1;
    }
    arr = arr3;

    for (int i = 5; i < 10; i++) {
        arr[i] = i * 10;
    }

    printf("realloc扩展后:");
    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 动态字符串
    char *str = (char*)malloc(100 * sizeof(char));
    if (str) {
        strcpy(str, "动态分配的字符串");
        printf("动态字符串:%s\n", str);
        free(str);
    }

    // 动态结构体
    struct Student {
        int id;
        char name[50];
    };

    struct Student *student = (struct Student*)malloc(sizeof(struct Student));
    if (student) {
        student->id = 1001;
        strcpy(student->name, "张三");
        printf("动态结构体:%d, %s\n", student->id, student->name);
        free(student);
    }

    // 释放内存
    free(arr);
    free(arr2);

    // 避免内存泄漏:释放后设置为NULL
    arr = NULL;

    return 0;
}

十、文件操作

10.1 文件读写

#include <stdio.h>
#include <stdlib.h>

int main() {
    // 写入文件
    FILE *fp = fopen("test.txt", "w");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return 1;
    }

    fprintf(fp, "Hello, C语言!\n");
    fprintf(fp, "这是第二行\n");
    fclose(fp);
    printf("文件写入成功\n");

    // 读取文件
    fp = fopen("test.txt", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return 1;
    }

    printf("\n文件内容:\n");
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        printf("%s", buffer);
    }
    fclose(fp);

    // 追加写入
    fp = fopen("test.txt", "a");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return 1;
    }

    fprintf(fp, "这是追加的行\n");
    fclose(fp);
    printf("\n追加成功\n");

    // 二进制文件写入
    int numbers[] = {10, 20, 30, 40, 50};
    fp = fopen("data.bin", "wb");
    fwrite(numbers, sizeof(int), 5, fp);
    fclose(fp);

    // 二进制文件读取
    int readNumbers[5];
    fp = fopen("data.bin", "rb");
    fread(readNumbers, sizeof(int), 5, fp);
    fclose(fp);

    printf("\n二进制读取:");
    for (int i = 0; i < 5; i++) {
        printf("%d ", readNumbers[i]);
    }
    printf("\n");

    return 0;
}

10.2 文件位置操作

#include <stdio.h>

int main() {
    FILE *fp = fopen("test.txt", "r");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return 1;
    }

    // 获取当前位置
    long pos = ftell(fp);
    printf("初始位置:%ld\n", pos);

    // 读取一行
    char buffer[100];
    fgets(buffer, sizeof(buffer), fp);
    printf("读取:%s", buffer);

    pos = ftell(fp);
    printf("当前位置:%ld\n", pos);

    // 设置位置到文件开头
    rewind(fp);
    printf("重置后位置:%ld\n", ftell(fp));

    // 定位到文件末尾
    fseek(fp, 0, SEEK_END);
    printf("文件末尾位置:%ld\n", ftell(fp));

    // 定位到指定位置
    fseek(fp, 10, SEEK_SET);
    printf("定位到第10个字节后位置:%ld\n", ftell(fp));

    fclose(fp);

    return 0;
}

十一、预处理指令

#include <stdio.h>

// 宏定义
#define PI 3.14159
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))

// 条件编译
#define DEBUG 1

// 防止头文件重复包含
#ifndef MY_HEADER_H
#define MY_HEADER_H
// 头文件内容
#endif

int main() {
    // 使用宏
    printf("PI = %.5f\n", PI);
    printf("SQUARE(5) = %d\n", SQUARE(5));
    printf("MAX(10, 20) = %d\n", MAX(10, 20));

    // 条件编译
    #if DEBUG
        printf("调试模式:变量值...\n");
    #else
        printf("发布模式\n");
    #endif

    // #运算符:将参数转换为字符串
    #define STR(x) #x
    printf("STR(hello) = %s\n", STR(hello));

    // ##运算符:连接两个标记
    #define CONCAT(a, b) a##b
    int xy = 100;
    printf("CONCAT(x, y) = %d\n", CONCAT(x, y));

    // 预定义宏
    printf("文件名:%s\n", __FILE__);
    printf("行号:%d\n", __LINE__);
    printf("编译日期:%s\n", __DATE__);
    printf("编译时间:%s\n", __TIME__);
    printf("函数名:%s\n", __func__);

    return 0;
}

十二、实战案例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_STUDENTS 100
#define NAME_LEN 50

// 学生结构体
typedef struct {
    int id;
    char name[NAME_LEN];
    int age;
    float score;
} Student;

// 全局变量
Student students[MAX_STUDENTS];
int studentCount = 0;

// 函数声明
void addStudent();
void displayAll();
void searchStudent();
void deleteStudent();
void updateStudent();
void saveToFile();
void loadFromFile();
void showMenu();

int main() {
    loadFromFile();  // 加载已有数据

    int choice;
    do {
        showMenu();
        printf("请选择操作:");
        scanf("%d", &choice);
        getchar();  // 清除缓冲区

        switch (choice) {
            case 1:
                addStudent();
                break;
            case 2:
                displayAll();
                break;
            case 3:
                searchStudent();
                break;
            case 4:
                updateStudent();
                break;
            case 5:
                deleteStudent();
                break;
            case 6:
                saveToFile();
                printf("数据已保存,退出系统\n");
                break;
            default:
                printf("无效选择,请重新输入\n");
        }
    } while (choice != 6);

    return 0;
}

void showMenu() {
    printf("\n==================\n");
    printf("学生信息管理系统\n");
    printf("==================\n");
    printf("1. 添加学生\n");
    printf("2. 显示所有学生\n");
    printf("3. 搜索学生\n");
    printf("4. 修改学生信息\n");
    printf("5. 删除学生\n");
    printf("6. 退出系统\n");
    printf("==================\n");
}

void addStudent() {
    if (studentCount >= MAX_STUDENTS) {
        printf("学生数量已达上限\n");
        return;
    }

    Student newStudent;
    printf("请输入学号:");
    scanf("%d", &newStudent.id);

    // 检查学号是否重复
    for (int i = 0; i < studentCount; i++) {
        if (students[i].id == newStudent.id) {
            printf("学号已存在\n");
            return;
        }
    }

    printf("请输入姓名:");
    scanf("%s", newStudent.name);
    printf("请输入年龄:");
    scanf("%d", &newStudent.age);
    printf("请输入成绩:");
    scanf("%f", &newStudent.score);

    students[studentCount++] = newStudent;
    printf("学生添加成功\n");
}

void displayAll() {
    if (studentCount == 0) {
        printf("暂无学生数据\n");
        return;
    }

    printf("\n学生列表:\n");
    printf("学号\t姓名\t年龄\t成绩\n");
    printf("--------------------------------\n");
    for (int i = 0; i < studentCount; i++) {
        printf("%d\t%s\t%d\t%.1f\n", 
               students[i].id, 
               students[i].name, 
               students[i].age, 
               students[i].score);
    }

    // 统计信息
    float sum = 0;
    int maxScore = students[0].score;
    int minScore = students[0].score;
    char maxName[NAME_LEN], minName[NAME_LEN];

    for (int i = 0; i < studentCount; i++) {
        sum += students[i].score;
        if (students[i].score > maxScore) {
            maxScore = students[i].score;
            strcpy(maxName, students[i].name);
        }
        if (students[i].score < minScore) {
            minScore = students[i].score;
            strcpy(minName, students[i].name);
        }
    }

    printf("\n统计信息:\n");
    printf("总人数:%d\n", studentCount);
    printf("平均分:%.2f\n", sum / studentCount);
    printf("最高分:%s (%.1f)\n", maxName, maxScore);
    printf("最低分:%s (%.1f)\n", minName, minScore);
}

void searchStudent() {
    int id;
    printf("请输入要搜索的学号:");
    scanf("%d", &id);

    for (int i = 0; i < studentCount; i++) {
        if (students[i].id == id) {
            printf("\n找到学生:\n");
            printf("学号:%d\n", students[i].id);
            printf("姓名:%s\n", students[i].name);
            printf("年龄:%d\n", students[i].age);
            printf("成绩:%.1f\n", students[i].score);
            return;
        }
    }
    printf("未找到学号为%d的学生\n", id);
}

void updateStudent() {
    int id;
    printf("请输入要修改的学号:");
    scanf("%d", &id);

    for (int i = 0; i < studentCount; i++) {
        if (students[i].id == id) {
            printf("当前信息:\n");
            printf("姓名:%s\n", students[i].name);
            printf("年龄:%d\n", students[i].age);
            printf("成绩:%.1f\n", students[i].score);

            printf("\n请输入新的姓名:");
            scanf("%s", students[i].name);
            printf("请输入新的年龄:");
            scanf("%d", &students[i].age);
            printf("请输入新的成绩:");
            scanf("%f", &students[i].score);

            printf("信息修改成功\n");
            return;
        }
    }
    printf("未找到学号为%d的学生\n", id);
}

void deleteStudent() {
    int id;
    printf("请输入要删除的学号:");
    scanf("%d", &id);

    for (int i = 0; i < studentCount; i++) {
        if (students[i].id == id) {
            // 将后面的元素前移
            for (int j = i; j < studentCount - 1; j++) {
                students[j] = students[j + 1];
            }
            studentCount--;
            printf("学生删除成功\n");
            return;
        }
    }
    printf("未找到学号为%d的学生\n", id);
}

void saveToFile() {
    FILE *fp = fopen("students.dat", "wb");
    if (fp == NULL) {
        printf("文件打开失败\n");
        return;
    }

    fwrite(&studentCount, sizeof(int), 1, fp);
    fwrite(students, sizeof(Student), studentCount, fp);
    fclose(fp);

    printf("数据保存成功\n");
}

void loadFromFile() {
    FILE *fp = fopen("students.dat", "rb");
    if (fp == NULL) {
        printf("首次运行,无历史数据\n");
        return;
    }

    fread(&studentCount, sizeof(int), 1, fp);
    fread(students, sizeof(Student), studentCount, fp);
    fclose(fp);

    printf("加载了%d个学生数据\n", studentCount);
}

来源:
https://app-adzoyybqtaf5.appmiaoda.com

相关文章
|
2月前
|
人工智能 机器人 芯片
人工智能|YOLOv8实战
本内容为安全帽检测实战项目,基于YOLOv8模型,涵盖Kaggle数据获取、自定义yaml配置、模型训练(yolo_train.py)与测试(yolo_test.py),并提供服务器(FastAPI+Docker)、边缘(Jetson+TensorRT)及国产嵌入式(RK3588+RKNN)三类部署方案,支持工业场景实时智能识别。(239字)
478 1
|
存储 安全 网络协议
绕过WAF和多个防护软件提权案例
绕过WAF和多个防护软件提权案例
597 0
|
5月前
|
人工智能 弹性计算 搜索推荐
开源 OpenClaw 实战:30 分钟在阿里云部署你的第一个 AI Agent
阿里云推出OpenClaw一键部署方案,仅需9.9元即可在轻量应用服务器、无影云电脑或ECS上快速搭建本地优先AI助理。三步完成:选环境→一键安装配置(集成百炼API)→个性化任务分配,零代码轻松启用智能体。
642 4
|
9月前
|
机器学习/深度学习 人工智能 自然语言处理
教育行业如何做GEO?让AI成为你的课程推荐官
过去,学生找课程靠搜索;现在,他们直接问AI:“附近有哪些性价比高的编程课?”或“商科最好的在线大学?”——AI不会简单罗列链接,而是直接推荐答案。如果你的教育机构没被AI“看见”,可能已经错过了新一轮流量红利。 作为深耕GEO领域的实战团队,数聚酷科技结合教育行业特性,总结出以下可落地的GEO优化策略,帮助你的课程和…
660 6
|
4月前
|
JavaScript 前端开发 UED
前端组件库——uView UI知识点大全(三)
教程来源 http://oplhc.cn/category/artificial-intelligence.html uView提供丰富工具函数(时间处理、数据验证、防抖节流、对象操作)、HTTP请求封装及全局配置;支持easycom按需加载与手动引入,优化性能;uView Pro全面升级Vue 3+TS,新增u-fab、u-text等高实用组件。
|
4月前
|
人工智能 安全 数据可视化
2026 版 OpenClaw Windows 一键部署:5 分钟零代码新手教程
OpenClaw 是一款开源AI智能体,支持Windows一键可视化安装(v2.6.2)。本教程详解2026最新部署流程:从环境准备、下载安装包,到自动配置与启动,全程无需命令行,适合新手快速搭建本地AI助手。
|
6月前
|
机器学习/深度学习 决策智能 开发者
从单 Agent 到多智能体系统:工程复杂度如何指数级上升
多智能体系统工程难点不在模型调用,而在协作复杂度的指数级增长:状态组合爆炸、交互路径不可枚举、调试成本非线性上升。其本质是“协调问题”而非“执行问题”,成败关键在于统一状态管理与协作协议设计。
|
存储 机器学习/深度学习 缓存
🚀 力扣热题 394:字符串解码(详细解析)(Go语言版)
文章提供了两种解法:栈结构和递归解法。栈解法通过维护数字栈与字符串栈,依次处理 `[` 和 `]`,构造解码结果;递归解法则利用函数调用逐层解析嵌套结构。两者时间复杂度均为 $O(n)$,空间复杂度也为 $O(n)$。栈解法直观易懂,适合初学者;递归解法优雅简洁,适合处理深度嵌套规则。掌握这两种方法,可灵活应对类似问题,提升解题能力。
574 11
|
存储 缓存 固态存储
云计算基础-存储虚拟化(深信服aSAN分布式存储)
每秒钟的IOPS数,该指标主要用于评价小块IO性能,体现存储系统的IO延时能力和并发能力。业界一般默认IOPS指的是4K块大小的IO性能,该值越大说明性能越好。
674 1