2949 字
15 分钟

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

2025-12-09
C

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);
}
//未写待补

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

2025.12.09 C语言程序设计上机实习六
https://mjy.js.org/posts/20251209-c语言程序设计上机实习六/
作者
MaJianyu
发布于
2025-12-09
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
MaJianyu
永远相信,美好的事情即将发生。
分类
标签
站点统计
文章
31
分类
9
标签
53
总字数
147,470
运行时长
0
最后活动
0 天前

目录