跳到正文
TranquilYu's Blog
返回

2025.12.09 C语言程序设计上机实习六

约 24 分钟 · 216 字
作业
文章目录9 节
  1. 必做题
  2. 选做题
  3. 题目1:动态字符串数组的双重排序
  4. 题目2:模拟解析CSV文件
  5. 题目3:排序后存储为CSV风格的字符串
  6. 附:完整代码
  7. TestSortStrings.c
  8. TestParseCSV.c
  9. TestSortSaveAsCSV.c
文章目录9 节

2025.12.09 C语言程序设计上机实习六

必做题

选做题

题目源文件实验六.pdf

题目1:动态字符串数组的双重排序

void SortStrings(char **strs, int n)
{

    if (strs == NULL || n <= 0) // 传入失败或字符串小于等于0则退出函数
    {
        return;
    }

    for (int i = 0; i < n; i++) // 对第i个字符串进行操作
    {
        int len = strlen(strs[i]);
        // 冒泡排序
        for (int j = 0; j < len - 1; j++)
        {
            for (int k = j + 1; k < len; k++)
            {
                if (strs[i][j] > strs[i][k])
                {
                    char temp = strs[i][j];
                    strs[i][j] = strs[i][k];
                    strs[i][k] = temp;
                }
            }
        }
    }

    // 冒泡排序
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            if (strcmp(strs[i], strs[j]) > 0)
            {
                char *temp = strs[i];
                strs[i] = strs[j];
                strs[j] = temp;
            }
        }
    }

}

题目2:模拟解析CSV文件

结构体定义

struct Person {
    char name[20];
    int age;
    char city[20];
};

ParseCSV函数

void ParseCSV(const char *csvData, struct Person **persons, int *count)
{
    if (persons == NULL || count == NULL) return;

    *persons = NULL;
    *count = 0;

    // 若 csvData 为空或 NULL,则 return
    if (csvData == NULL || csvData[0] == '\0')
    {
        return;
    }

    int len = strlen(csvData);
    int lines = 0;
    char *temp = NULL;
    temp = (char *)malloc(sizeof(char) * (len + 1));
    if (!temp) free(temp);
    if (temp == NULL) return;
    memcpy(temp, csvData, len + 1);
    for (int i = 0; i < len; i++)
    {
        if (temp[i] == '\n')
        {
            lines++;
        }
    }

    if (len > 0 && temp[len - 1] != '\n')
    {
        lines++;
    }

    if (lines == 0) return;

    *persons = (struct Person *)malloc(sizeof(struct Person) * lines);
    if (*persons == NULL) return;

    int index = 0;
    int status = 1;

    char *line;
    char *saveptr = NULL;

    line = strtok_r(temp, "\n", &saveptr);

    while(line && status)
    {
        char *saveptr2 = NULL;
        char *name = strtok_r(line, ",", &saveptr2);
        char *ageStr = strtok_r(NULL, ",", &saveptr2);
        char *city = strtok_r(NULL, ",", &saveptr2);
        char *extra = strtok_r(NULL, ",", &saveptr2);

        if (!name || !ageStr || !city || extra != NULL)
        {
            status = 0;
            break;
        }

        if (strlen(name) == 0 || strlen(name) >= 20)
        {
            status = 0;
            break;
        }

        strcpy((*persons)[index].name, name);

        for (int i = 0; ageStr[i]; i++)
        {
            if (ageStr[i] < '0' || ageStr[i] > '9')
            {
                status = 0;
                break;
            }
        }

        if (status == 0) break;

        (*persons)[index].age = atoi(ageStr);

        if (strlen(city) == 0 || strlen(city) >= 20)
        {
            status = 0;
            break;
        }
        strcpy((*persons)[index].city, city);

        index++;
        line = strtok_r(NULL, "\n", &saveptr);

    }

    free(temp);

    if(status == 0 || index == 0)
    {
        free(*persons);
        *persons = NULL;
        *count = 0;
        return;
    }

    *count = index;

    return;
}

AI使用声明:

对于库函数strtok,在本程序中会发生共用缓冲区问题,导致测试例1无法通过。

在《C语言程序设计》附录部分仅介绍了strtok。在AI的帮助下了解到更安全的库函数strtok_r,故更换使用后正常。

若不使用strtok与strtor_r,其他的方法其实还有(包括但不限于)

题目3:排序后存储为CSV风格的字符串

//未写待补

附:完整代码

TestSortStrings.c

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

void SortStrings(char **strs, int n);

// ========== 测试框架 ==========
void run_tests();

// ========== 主函数 ==========
int main() {
    run_tests();
    return 0;
}

void run_tests()
{
    printf("=== 字符串数组双重排序测试 ===\n");
    int pass_count = 0;
    int total_count = 0;

    // 测试用例1:正常情况
    printf("\n测试用例1:正常情况\n");
    char *strs1[] = {malloc(4), malloc(4), malloc(4)};
    strcpy(strs1[0], "cba");
    strcpy(strs1[1], "fed");
    strcpy(strs1[2], "abc");
    SortStrings(strs1, 3);
    if (strcmp(strs1[0], "abc") == 0 && strcmp(strs1[1], "abc") == 0 && strcmp(strs1[2], "def") == 0)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败: 实际 [%s, %s, %s]\n", strs1[0], strs1[1], strs1[2]);
    }
    free(strs1[0]);
    free(strs1[1]);
    free(strs1[2]);
    total_count++;

    // 测试用例2:包含空字符串
    printf("\n测试用例2:包含空字符串\n");
    char *strs2[] = {malloc(1), malloc(5), malloc(6)};
    strcpy(strs2[0], "");
    strcpy(strs2[1], "dcba");
    strcpy(strs2[2], "hello");
    SortStrings(strs2, 3);
    if (strcmp(strs2[0], "") == 0 && strcmp(strs2[1], "abcd") == 0 && strcmp(strs2[2], "ehllo") == 0)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败\n");
    }
    free(strs2[0]);
    free(strs2[1]);
    free(strs2[2]);
    total_count++;

    // 测试用例3:单字符字符串
    printf("\n测试用例3:单字符字符串\n");
    char *strs3[] = {malloc(2), malloc(2), malloc(2)};
    strcpy(strs3[0], "b");
    strcpy(strs3[1], "a");
    strcpy(strs3[2], "c");
    SortStrings(strs3, 3);
    if (strcmp(strs3[0], "a") == 0 && strcmp(strs3[1], "b") == 0 && strcmp(strs3[2], "c") == 0)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败\n");
    }
    free(strs3[0]);
    free(strs3[1]);
    free(strs3[2]);
    total_count++;

    // 测试用例4:大规模动态示例(课堂原题)
    printf("\n测试用例4:大规模动态示例(课堂原题)\n");
    int m = 26;
    char **strs4 = (char**)malloc(m * sizeof(char*));
    for (int i = 0; i < m; i++)
    {
        strs4[i] = (char*)malloc((i + 2) * sizeof(char));
        for (int j = 0; j <= i; j++)
        {
            strs4[i][j] = 'z' - j;
        }
        strs4[i][i + 1] = '\0';
    }

    SortStrings(strs4, m);

    int valid = 1;
    for (int i = 0; i < m; i++)
    {
        size_t len = strlen(strs4[i]);
        for (size_t j = 0; j + 1 < len; j++)
        {
            if (strs4[i][j] > strs4[i][j + 1])
            {
                valid = 0;
                break;
            }
        }
        if (!valid)
        {
            break;
        }
    }

    if (valid)
    {
        for (int i = 0; i < m - 1; i++)
        {
            if (strcmp(strs4[i], strs4[i + 1]) > 0)
            {
                valid = 0;
                break;
            }
        }
    }

    if (valid)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败\n");
    }

    for (int i = 0; i < m; i++)
    {
        free(strs4[i]);
    }
    free(strs4);
    total_count++;

    // 测试用例5:n为0且strs为NULL
    printf("\n测试用例5:n为0且strs为NULL\n");
    SortStrings(NULL, 0);
    printf("  ✔️ 无异常,通过\n");
    pass_count++;
    total_count++;

    printf("\n=== 测试结果 ===\n");
    printf("通过: %d/%d (%.1f%%)\n", pass_count, total_count, (float)pass_count / total_count * 100);
}

void SortStrings(char **strs, int n)
{

    if (strs == NULL || n <= 0) // 传入失败或字符串小于等于0则退出函数
    {
        return;
    }

    for (int i = 0; i < n; i++) // 对第i个字符串进行操作
    {
        int len = strlen(strs[i]);
        // 冒泡排序
        for (int j = 0; j < len - 1; j++)
        {
            for (int k = j + 1; k < len; k++)
            {
                if (strs[i][j] > strs[i][k])
                {
                    char temp = strs[i][j];
                    strs[i][j] = strs[i][k];
                    strs[i][k] = temp;
                }
            }
        }
    }

    // 冒泡排序
    for (int i = 0; i < n - 1; i++)
    {
        for (int j = i + 1; j < n; j++)
        {
            if (strcmp(strs[i], strs[j]) > 0)
            {
                char *temp = strs[i];
                strs[i] = strs[j];
                strs[j] = temp;
            }
        }
    }

}

TestParseCSV.c

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

struct Person {
    char name[20];
    int age;
    char city[20];
};


void ParseCSV(const char *csvData, struct Person **persons, int *count);

// ========== 测试框架 ==========
void run_tests();

// ========== 主函数 ==========
int main()
{
    run_tests();
    return 0;
}

void run_tests()
{
    printf("=== CSV 文件解析为结构体测试 ===\n");
    int pass_count = 0;
    int total_count = 0;

    // 测试用例1:正常情况
    printf("\n测试用例1:正常情况\n");
    const char *csv1 = "Zoe,29,Hangzhou\nAlice,25,Beijing\nBob,30,Shanghai\nCharlie,22,Guangzhou\nDiana,28,Shenzhen";

    struct Person *persons1 = NULL;
    int count1 = 0;

    ParseCSV(csv1, &persons1, &count1);

    if (count1 == 5)
    {
        if (strcmp(persons1[0].name, "Zoe") == 0 && persons1[0].age == 29 && strcmp(persons1[0].city, "Hangzhou") == 0)
        {
            if (strcmp(persons1[1].name, "Alice") == 0 && persons1[1].age == 25 && strcmp(persons1[1].city, "Beijing") == 0)
            {
                if (strcmp(persons1[2].name, "Bob") == 0 && persons1[2].age == 30 && strcmp(persons1[2].city, "Shanghai") == 0)
                {
                    if (strcmp(persons1[3].name, "Charlie") == 0 && persons1[3].age == 22 && strcmp(persons1[3].city, "Guangzhou") == 0)
                    {
                        if (strcmp(persons1[4].name, "Diana") == 0 && persons1[4].age == 28 && strcmp(persons1[4].city, "Shenzhen") == 0)
                        {
                            printf("  ✔️ 通过\n");
                            pass_count++;
                        }
                        else
                        {
                            printf("  ❌ 失败: Diana 行错误\n");
                        }
                    }
                    else
                    {
                        printf("  ❌ 失败: Charlie 行错误\n");
                    }
                }
                else
                {
                    printf("  ❌ 失败: Bob 行错误\n");
                }
            }
            else
            {
                printf("  ❌ 失败: Alice 行错误\n");
            }
        }
        else
        {
            printf("  ❌ 失败: Zoe 行错误\n");
        }
    }
    else
    {
        printf("  ❌ 失败: 记录数不正确,期望 5,实际 %d\n", count1);
    }

    free(persons1);
    total_count++;

    // 测试用例2:空数据
    printf("\n测试用例2:空数据\n");
    const char *empty = "";
    struct Person *persons2 = NULL;
    int count2 = 0;

    ParseCSV(empty, &persons2, &count2);

    if (count2 == 0 && persons2 == NULL)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败\n");
    }
    total_count++;

    // 测试用例3:单行
    printf("\n测试用例3:单行数据\n");
    const char *single = "Tom,35,Chengdu";
    struct Person *persons3 = NULL;
    int count3 = 0;

    ParseCSV(single, &persons3, &count3);

    if (count3 == 1 && strcmp(persons3[0].name, "Tom") == 0 && persons3[0].age == 35 && strcmp(persons3[0].city, "Chengdu") == 0)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败\n");
    }

    free(persons3);
    total_count++;

    // 测试用例4:无逗号
    printf("\n测试用例4:异常格式(无逗号)\n");
    const char *invalid = "John18NewYork\nMary22Paris";
    struct Person *persons4 = NULL;
    int count4 = 0;

    ParseCSV(invalid, &persons4, &count4);
    if (count4 == 0 && persons4 == NULL)
    {
        printf("  ✔️ 通过(格式错误,应返回空)\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:应拒绝解析\n");
    }
    total_count++;

    // 测试用例5:字段数量不一致(某行不是3列)
    printf("\n测试用例5:字段数量不一致(第二行只有2列)\n");
    const char *csv5 = "Zoe,29,Hangzhou\nAlice,25\nBob,30,Shanghai";
    struct Person *persons5 = NULL;
    int count5 = 0;

    ParseCSV(csv5, &persons5, &count5);

    if (count5 == 0 && persons5 == NULL)
    {
        printf("  ✔️ 通过(格式错误,应返回空)\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:应拒绝解析\n");
    }
    total_count++;

    // 汇总结果
    printf("\n=== 测试结果 ===\n");
    printf("通过: %d/%d (%.1f%%)\n", pass_count, total_count, (float)pass_count / total_count * 100);
}


void ParseCSV(const char *csvData, struct Person **persons, int *count)
{
    if (persons == NULL || count == NULL) return;

    *persons = NULL;
    *count = 0;

    // 若 csvData 为空或 NULL,则 return
    if (csvData == NULL || csvData[0] == '\0')
    {
        return;
    }

    int len = strlen(csvData);
    int lines = 0;
    char *temp = NULL;
    temp = (char *)malloc(sizeof(char) * (len + 1));
    if (!temp) free(temp);
    if (temp == NULL) return;
    memcpy(temp, csvData, len + 1);
    for (int i = 0; i < len; i++)
    {
        if (temp[i] == '\n')
        {
            lines++;
        }
    }

    if (len > 0 && temp[len - 1] != '\n')
    {
        lines++;
    }

    if (lines == 0) return;

    *persons = (struct Person *)malloc(sizeof(struct Person) * lines);
    if (*persons == NULL) return;

    int index = 0;
    int status = 1;

    char *line;
    char *saveptr = NULL;

    line = strtok_r(temp, "\n", &saveptr);

    while(line && status)
    {
        char *saveptr2 = NULL;
        char *name = strtok_r(line, ",", &saveptr2);
        char *ageStr = strtok_r(NULL, ",", &saveptr2);
        char *city = strtok_r(NULL, ",", &saveptr2);
        char *extra = strtok_r(NULL, ",", &saveptr2);

        if (!name || !ageStr || !city || extra != NULL)
        {
            status = 0;
            break;
        }

        if (strlen(name) == 0 || strlen(name) >= 20)
        {
            status = 0;
            break;
        }

        strcpy((*persons)[index].name, name);

        for (int i = 0; ageStr[i]; i++)
        {
            if (ageStr[i] < '0' || ageStr[i] > '9')
            {
                status = 0;
                break;
            }
        }

        if (status == 0) break;

        (*persons)[index].age = atoi(ageStr);

        if (strlen(city) == 0 || strlen(city) >= 20)
        {
            status = 0;
            break;
        }
        strcpy((*persons)[index].city, city);

        index++;
        line = strtok_r(NULL, "\n", &saveptr);

    }

    free(temp);

    if(status == 0 || index == 0)
    {
        free(*persons);
        *persons = NULL;
        *count = 0;
        return;
    }

    *count = index;

    return;
}

TestSortSaveAsCSV.c

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

#define MAX_MALLOC 100

char *SortSaveAsCSV(struct Person *persons, int count);

// =================== 测试框架 ===================
void run_tests();

int main()
{
    run_tests();
    return 0;
}

void run_tests()
{
    printf("=== 排序后存储为CSV风格字符串测试 ===\n");
    int pass_count = 0;
    int total_count = 0;

    // 测试用例1:正常情况(多个人,不同年龄)
    printf("\n测试用例1:正常情况\n");
    struct Person people1[] = {
        (struct Person){"Zoe", 29, "Hangzhou"},
        (struct Person){"Alice", 25, "Beijing"},
        (struct Person){"Bob", 30, "Shanghai"}
    };
    char *csv1 = SortSaveAsCSV(people1, 3);

    if (csv1 != NULL && strcmp(csv1, "Alice,25,Beijing\nZoe,29,Hangzhou\nBob,30,Shanghai\n") == 0 && malloc_usable_size(csv1) < MAX_MALLOC)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:输出不正确or内存开辟过大\n");
    }
    free(csv1);
    total_count++;

    // 测试用例2:空数组或NULL输入
    printf("\n测试用例2:空数组或NULL输入\n");
    char *csv2 = SortSaveAsCSV(NULL, 0);
    if (strlen(csv2) == 0)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:应返回空字符串\n");
    }
    total_count++;

    // 测试用例3:单个元素
    printf("\n测试用例3:单个元素\n");
    struct Person person3 = (struct Person){"Tom", 35, "Chengdu"};
    char *csv3 = SortSaveAsCSV(&person3, 1);
    if (csv3 != NULL && strcmp(csv3, "Tom,35,Chengdu\n") == 0 && malloc_usable_size(csv3) < MAX_MALLOC)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:单行输出错误或开辟内存过大\n");
    }
    free(csv3);
    total_count++;

    // 测试用例4:相同年龄(稳定排序)
    printf("\n测试用例4:相同年龄(稳定排序)\n");
    struct Person people4[] = {
        (struct Person){"Zoe", 25, "Hangzhou"},
        (struct Person){"Alice", 25, "Beijing"},
        (struct Person){"Bob", 26, "Shanghai"}
    };
    char *csv4 = SortSaveAsCSV(people4, 3);
    if (csv4 != NULL && strcmp(csv4, "Zoe,25,Hangzhou\nAlice,25,Beijing\nBob,26,Shanghai\n") == 0 && malloc_usable_size(csv4) < MAX_MALLOC)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:排序不稳定或式格错误or开辟内存过大\n");
    }
    free(csv4);
    total_count++;

    // 测试用例5:城市为空字符串
    printf("\n测试用例5:城市为空字符串\n");
    struct Person people5[] = {
        (struct Person){"Zoe", 29, ""},
        (struct Person){"Alice", 25, "Beijing"}
    };
    char *csv5 = SortSaveAsCSV(people5, 2);
    if (csv5 != NULL && strcmp(csv5, "Alice,25,Beijing\nZoe,29,\n") == 0 && malloc_usable_size(csv5) < MAX_MALLOC)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:空城市未正确处理或内存开辟过大\n");
    }
    free(csv5);
    total_count++;

    // 测试用例6:姓名或城市含特殊字符
    printf("\n测试用例6:姓名/城市含特殊字符\n");
    struct Person people6[] = {
        (struct Person){"Li_42", 29, "New-York"},
        (struct Person){"OOP_Programmer", 25, "San-Francisco"}
    };
    char *csv6 = SortSaveAsCSV(people6, 2);
    if (csv6 != NULL && strcmp(csv6, "OOP_Programmer,25,San-Francisco\nLi_42,29,New-York\n") == 0 && malloc_usable_size(csv6) < MAX_MALLOC)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:特殊字符未原样输出或内存开辟过大\n");
    }
    free(csv6);
    total_count++;

    // 测试用例7:负年龄
    printf("\n测试用例7:负年龄\n");
    struct Person people7[] = {
        (struct Person){"Zoe", -5, "Hangzhou"},
        (struct Person){"Alice", 100, "Beijing"}
    };
    char *csv7 = SortSaveAsCSV(people7, 2);
    if (csv7 != NULL && strcmp(csv7, "Zoe,-5,Hangzhou\nAlice,100,Beijing\n") == 0 && malloc_usable_size(csv7) < MAX_MALLOC)
    {
        printf("  ✔️ 通过\n");
        pass_count++;
    }
    else
    {
        printf("  ❌ 失败:负数年龄未正确输出或内存开辟过大\n");
    }
    free(csv7);
    total_count++;

    // 汇总结果
    printf("\n=== 测试结果 ===\n");
    printf("通过: %d/%d (%.1f%%)\n", pass_count, total_count, (float)pass_count / total_count * 100);
}

//未写待补

分享文章:

  1. 2025.12.23 C语言程序设计上机实习八作业 · C语言程序设计上机实习八
  2. 2025.12.16 C语言程序设计上机实习七作业 · C语言程序设计上机实习七
  3. 2025.12.02 C语言程序设计上机实习五作业 · C语言程序设计上机实习五
上一篇
【论文阅读 | ICCV 2025 | M-SpecGene:面向 RGBT 多光谱视觉的通用基础模型】
下一篇
【论文阅读 | CVPR 2024 | RSDet_去除再选择:一种用于 RGB - 红外目标检测的由粗到精融合视角】