C语言动态内存分配实现:读取CSV存入info_t结构体数组的方法
C语言解析CSV存入动态结构体数组实现
首先修正原结构体定义的笔误:Char 需改为C语言标准的小写char,否则编译无法通过。
实现思路
- 结构体数组采用动态扩容方案:初始分配4个元素的空间,存储满后每次扩容为原来的2倍,避免频繁申请内存
- 逐行读取文件,单行缓存大小设为256字节符合要求
- 分割单行的三个CSV字段,
name字段单独申请动态内存,长度限制为24字节(含结束符) - 每一步内存申请都做错误校验,申请失败时主动释放已分配的内存,避免内存泄漏
- 结构体数组以
name字段为NULL作为结束哨兵,方便调用方遍历
完整代码实现
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> // 修正后的结构体定义 typedef struct { char *name; int age; double balance; } info_t; // 辅助函数:去除字符串首尾的空白符,适配CSV字段前后有空格的场景 static char* trim(char *str) { while(isspace((unsigned char)*str)) str++; if(*str == 0) return str; char *end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*end)) end--; end[1] = '\0'; return str; } void readFile(FILE *file, info_t **arr) { // 初始化数组参数:初始容量4,当前元素数0 int capacity = 4; int count = 0; *arr = (info_t*)malloc(sizeof(info_t) * capacity); if (*arr == NULL) { perror("结构体数组内存申请失败"); return; } char line_buf[256]; // 单行缓存,符合256字节上限要求 char field_buf[24]; // 单字段缓存,符合24字节上限要求 // 逐行读取文件 while (fgets(line_buf, sizeof(line_buf), file) != NULL) { // 跳过空行 size_t len = strlen(line_buf); if (len <= 1) continue; // 去掉行尾的换行符 if (line_buf[len-1] == '\n') line_buf[len-1] = '\0'; // 扩容判断:当前元素数达到容量的前1位(留最后一位存哨兵) if (count >= capacity - 1) { capacity *= 2; info_t *tmp = (info_t*)realloc(*arr, sizeof(info_t) * capacity); if (tmp == NULL) { perror("结构体数组扩容失败"); // 释放已分配的内存避免泄漏 for (int i = 0; i < count; i++) { free((*arr)[i].name); } free(*arr); *arr = NULL; return; } *arr = tmp; } // 分割CSV字段,默认分隔符为逗号 char *name_str = strtok(line_buf, ","); char *age_str = strtok(NULL, ","); char *balance_str = strtok(NULL, ","); // 字段不全则跳过当前行 if (!name_str || !age_str || !balance_str) continue; // 处理name字段:去空白,限制长度24字节,动态分配内存 name_str = trim(name_str); strncpy(field_buf, name_str, sizeof(field_buf)-1); field_buf[sizeof(field_buf)-1] = '\0'; (*arr)[count].name = (char*)malloc(strlen(field_buf) + 1); if ((*arr)[count].name == NULL) { perror("name字段内存申请失败"); // 释放已分配内存 for (int i = 0; i < count; i++) { free((*arr)[i].name); } free(*arr); *arr = NULL; return; } strcpy((*arr)[count].name, field_buf); // 处理age字段 (*arr)[count].age = atoi(trim(age_str)); // 处理balance字段 (*arr)[count].balance = atof(trim(balance_str)); count++; } // 写入结束哨兵 (*arr)[count].name = NULL; }
调用与内存释放示例
int main() { info_t *info_arr = NULL; FILE *fp = fopen("data.csv", "r"); if (fp == NULL) { perror("文件打开失败"); return 1; } readFile(fp, &info_arr); fclose(fp); if (info_arr == NULL) { return 1; } // 遍历使用结构体数组 for (int i = 0; info_arr[i].name != NULL; i++) { printf("姓名:%s,年龄:%d,余额:%.2lf\n", info_arr[i].name, info_arr[i].age, info_arr[i].balance); } // 释放内存:先释放每个元素的name字段,再释放数组本身 for (int i = 0; info_arr[i].name != NULL; i++) { free(info_arr[i].name); } free(info_arr); return 0; }
内容的提问来源于stack exchange,提问作者user870251
相关产品推荐
相关产品推荐

