如何在结构体中用malloc动态分配命令行传入的币价与日期数据?
如何在结构体中动态分配日期和价格数组来处理多个CSV加密货币数据
我来帮你解决这个动态内存分配的问题!核心思路是先为每个加密货币的数据定义一个结构体,在读取每个CSV文件时,先获取条目数,再用malloc为日期(字符串数组)和价格(浮点数组)动态分配对应的内存空间,这样就能灵活适配不同文件的条目数量了。
第一步:定义合适的结构体
我们需要一个结构体来存储单种加密货币的所有数据,包括文件名、条目数量,以及动态分配的日期和价格数组:
#include <stdio.h> #include <stdlib.h> #include <string.h> // 定义加密货币数据结构体 typedef struct { char filename[50]; // 存储CSV文件名 int entry_count; // 条目数量(比如253) char **dates; // 动态分配的日期字符串数组 double *prices; // 动态分配的价格数组 } CryptoData;
第二步:处理命令行参数并逐个读取CSV文件
命令行传入的参数是程序名+3个CSV文件名,我们需要遍历这些文件,为每个文件创建对应的CryptoData实例,然后动态分配内存并读取数据:
int main(int argc, char *argv[]) { // 检查命令行参数数量是否正确(程序名+3个文件) if (argc != 4) { fprintf(stderr, "用法: %s <BTC.csv> <NEO.csv> <IOT.csv>\n", argv[0]); return 1; } // 为3种加密货币分配结构体数组内存 CryptoData *crypto_list = malloc(3 * sizeof(CryptoData)); if (crypto_list == NULL) { perror("malloc分配结构体数组失败"); return 1; } // 遍历每个CSV文件 for (int i = 0; i < 3; i++) { const char *filename = argv[i+1]; strncpy(crypto_list[i].filename, filename, sizeof(crypto_list[i].filename)-1); crypto_list[i].filename[sizeof(crypto_list[i].filename)-1] = '\0'; // 确保字符串结束 FILE *fp = fopen(filename, "r"); if (fp == NULL) { perror("打开文件失败"); // 这里要注意:如果前面已经分配了内存,需要先释放再退出 for (int j = 0; j < i; j++) { free(crypto_list[j].dates); free(crypto_list[j].prices); } free(crypto_list); return 1; } // 第一步:读取条目数量(假设文件第一行是数字,比如253) if (fscanf(fp, "%d", &crypto_list[i].entry_count) != 1) { fprintf(stderr, "读取%s的条目数失败\n", filename); fclose(fp); // 同样要释放已分配的内存 for (int j = 0; j < i; j++) { free(crypto_list[j].dates); free(crypto_list[j].prices); } free(crypto_list); return 1; } // 读取完条目数后,要跳过换行符(因为fscanf不会读取换行) fgetc(fp); // 第二步:为日期和价格数组动态分配内存 // 日期是字符串数组,每个元素是一个char*,所以要分配entry_count个char*的空间 crypto_list[i].dates = malloc(crypto_list[i].entry_count * sizeof(char*)); if (crypto_list[i].dates == NULL) { perror("malloc日期数组失败"); fclose(fp); // 释放已分配的资源 for (int j = 0; j < i; j++) { free(crypto_list[j].dates); free(crypto_list[j].prices); } free(crypto_list); return 1; } // 价格是double数组,直接分配entry_count个double的空间 crypto_list[i].prices = malloc(crypto_list[i].entry_count * sizeof(double)); if (crypto_list[i].prices == NULL) { perror("malloc价格数组失败"); free(crypto_list[i].dates); // 先释放已分配的日期数组 fclose(fp); // 释放前面的资源 for (int j = 0; j < i; j++) { free(crypto_list[j].dates); free(crypto_list[j].prices); } free(crypto_list); return 1; } // 第三步:逐行读取日期和价格数据 char date_buf[20]; // 临时存储日期字符串 double price; for (int k = 0; k < crypto_list[i].entry_count; k++) { // 读取CSV行,格式是"MM/DD/YY,price" if (fscanf(fp, "%19[^,],%lf", date_buf, &price) != 2) { fprintf(stderr, "读取%s的第%d条数据失败\n", filename, k+1); // 释放当前文件已分配的内存 free(crypto_list[i].dates); free(crypto_list[i].prices); fclose(fp); // 释放前面的资源 for (int j = 0; j < i; j++) { free(crypto_list[j].dates); free(crypto_list[j].prices); } free(crypto_list); return 1; } // 为当前日期字符串分配内存并复制内容 crypto_list[i].dates[k] = malloc(strlen(date_buf) + 1); if (crypto_list[i].dates[k] == NULL) { perror("malloc单个日期字符串失败"); // 释放当前文件已分配的日期和价格 for (int m = 0; m < k; m++) { free(crypto_list[i].dates[m]); } free(crypto_list[i].dates); free(crypto_list[i].prices); fclose(fp); // 释放前面的资源 for (int j = 0; j < i; j++) { free(crypto_list[j].dates); free(crypto_list[j].prices); } free(crypto_list); return 1; } strcpy(crypto_list[i].dates[k], date_buf); crypto_list[i].prices[k] = price; } fclose(fp); printf("成功读取%s的%d条数据\n", filename, crypto_list[i].entry_count); } // 这里可以添加使用数据的逻辑,比如打印前几条数据 printf("\n示例数据输出:\n"); for (int i = 0; i < 3; i++) { printf("%s 第一条数据:日期=%s,价格=%.2lf\n", crypto_list[i].filename, crypto_list[i].dates[0], crypto_list[i].prices[0]); } // 第四步:释放所有动态分配的内存,避免内存泄漏 for (int i = 0; i < 3; i++) { // 先释放每个日期字符串的内存 for (int k = 0; k < crypto_list[i].entry_count; k++) { free(crypto_list[i].dates[k]); } // 再释放日期数组和价格数组的内存 free(crypto_list[i].dates); free(crypto_list[i].prices); } // 最后释放结构体数组的内存 free(crypto_list); return 0; }
关键要点解释
- 结构体设计:
dates是char**类型,因为每个日期是一个字符串,我们需要先分配一个存储指针的数组,再为每个字符串单独分配内存;prices是double*,直接分配连续的double空间即可。 - 内存分配顺序:先分配结构体数组,再为每个结构体的日期、价格数组分配内存,最后为每个日期字符串分配内存。
- 错误处理:每次
malloc后都要检查是否分配成功,如果失败要及时释放已经分配的内存,避免内存泄漏。 - 内存释放顺序:和分配顺序相反,先释放每个日期字符串,再释放日期数组、价格数组,最后释放结构体数组。
- 命令行参数处理:通过
argc和argv获取传入的文件名,确保参数数量正确。
测试注意事项
- 确保每个CSV文件的第一行是条目数(比如253),之后每行是
MM/DD/YY,价格的格式,例如02/20/18,11403.7。 - 编译时可以用
gcc -o a.exe crypto_reader.c,然后运行a.exe BTC.csv NEO.csv IOT.csv。
内容的提问来源于stack exchange,提问作者Andre
相关产品推荐
相关产品推荐

