|
发表于 2021-2-7 09:50:26
|
显示全部楼层
先上代码测试, 然后再解释
- /*
- used: UTF-8
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <conio.h>
- #include <string.h>
- int main(void)
- {
- char ***data = NULL; //储存所读取的数据---实际上可以翻译为:(*data)[][], 即储存字符串的二维数组
- FILE *fp; //要读取的文件指针
- int i, j, k = 0; //计数器
- int temp; //临时数据
- char gets_test = '\0'; //读取的字符
- int lines = 1; //被读取文件的行数
- //打开文件
- if ((fp = fopen("test.csv", "r")) == NULL)
- {
- return -1;
- }
- //读取文件的行数
- while (!feof(fp))
- {
- gets_test = fgetc(fp);
- if (gets_test == '\n')
- {
- lines++;
- }
- }
- gets_test = '\0'; //将字符清空, 以便后面的判断
- rewind(fp); //回到文件开始位置
- int num[lines]; //文件中每行数据的个数
- //初始化
- for (i = 0; i < lines; i++)
- {
- num[i] = 1;
- }
- //读取文件中每行数据的个数
- for (i = 0; i < lines; i++)
- {
- while (gets_test != '\n')
- {
- gets_test = fgetc(fp);
- if (gets_test == ',')
- {
- num[i]++;
- }
- if (gets_test == EOF)
- {
- goto exits; //如果读取到文件末, 则直接跳转到exits继续进行下一步
- }
- }
- gets_test = '\0'; //对读取到的字符进行重置, 避免因读到'\n'而导致无法读取下一行
- }
- exits:
- rewind(fp); //回到文件开始位置
- int num_max; //文件中, 在所有行中, 每行数据个数最多的值
- int temp_num[lines]; //每行数据个数的临时数据
- //将数据复制到临时数据中, 以便进行
- memcpy(temp_num, num, sizeof(int) * lines);
- //当文件行数超过一行时, 对数据个数进行排序, 得出最大值[此处使用降序]
- if (lines > 1)
- {
- for (i = 1; i <= lines; i++)
- {
- for (j = 0; j < lines; j++)
- {
- if (temp_num[i - 1] < temp_num[i])
- {
- temp = temp_num[i - 1];
- temp_num[i - 1] = temp_num[i];
- temp_num[i] = temp;
- }
- }
- }
- num_max = temp_num[0];
- }
- else
- {
- num_max = num[0]; //当文件只有一行时, 最大值就是当前行的数据个数
- }
- //每行每个数据的具体大小, 这里直接设置每行数据个数的最大值
- //当然, 这里设置成指针再进行其他操作也行, 不过复杂度就相对较高了
- int test[lines][num_max];
- //对数组进行初始化
- for (i = 0; i < lines; i++)
- {
- for (j = 0; j < num_max; j++)
- {
- test[i][j] = 0;
- }
- }
- //读取数据
- for (i = 0; i < lines; i++)
- {
- gets_test = ' ';
- for (j = 0; (gets_test != '\n' && gets_test != EOF);j++)
- {
- gets_test = fgetc(fp);
- if (gets_test == ',' || gets_test == '\n' || gets_test == EOF)
- {
- test[i][k] = j;
- j = -1; //这里之所以为-1是因为for循环会多加一个1
- if (k < (num[i] - 1)) //这里防止数组越界
- {
- k++;
- }
- }
- }
- k = 0; //当i发生变化时, 需要对k进行重置, 否则将无法读取下一行与当前数据同样位置的数据z
- }
- rewind(fp);
- //对data进行动态申请内存, 以尽量不浪费内存
- data = (char ***)malloc(sizeof(char ***) * lines);
- for (i = 0; i < lines; i++)
- {
- data[i] = (char **)malloc(sizeof(char **) * num[i]);
- for (j = 0; j < num[i]; j++)
- {
- data[i][j] = (char *)malloc(sizeof(char *) * (test[i][j]));
- }
- }
- //对申请的内存进行初始化, 以防乱码等情况
- for (i = 0; i < lines; i++)
- {
- for (j = 0; j < num[i]; j++)
- {
- for (k = 0; k < test[i][j]; k++)
- {
- memset(data[i][j], 0, sizeof(char *) * (test[i][j]));
- }
- }
- }
- //读取信息并储存到data中
- for (i = 0; i < lines; i++)
- {
- //将num[i]作为临时数据
- temp = num[i];
- //对读取到的数据个数进行判断后再读取
- for (j = 0; temp > 0; j++)
- {
- //重置k以免因特殊字符而导致多读取或少读取的情况
- k = 0;
- for (k = 0; k < test[i][j]; k++)
- {
- gets_test = fgetc(fp);
- if (gets_test != ',' && gets_test != '\n')
- {
- data[i][j][k] = gets_test;
- }
- else
- {
- //当读取到的数据为特殊字符时, 对k进行赋值
- //这里之所以是-1也是因为for循环的问题, 循环结束后会执行k++, 易导致读取的数据不完整
- k = -1;
- }
- }
- //当前行当前个数的数据读取完之后, 进行赋值, 以便判断, 防止造成数组越界等情况
- temp--;
- }
- }
-
- //打印读取到的数据并确认
- for (i = 0; i < lines; i++)
- {
- for (j = 0; j < num[i]; j++)
- {
- printf("%s ", data[i][j]);
- }
- putchar(10);
- }
- fclose(fp); //关闭文件
- free(data); //释放data
- getch();
- return 0;
- }
复制代码
实例如下:
第一次调试:
- 1,2,3,4,5,6,7,8,9,10,11,12
- q,w,e,r,t,y,u,i,o,p,a,[,]
- "?????","it's too dificult!!!","make it isn't so easy!"
复制代码
输出:
- 1 2 3 4 5 6 7 8 9 10 11 12
- q w e r t y u i o p a [ ]
- "?????" "it's too dificult!!!" "make it isn't so easy!"
复制代码
原谅我等级不够没法上传图片 备注:GCC 4.8.1编译通过, 汉字会出现乱码, 因为汉字是占两个字节的, 而本程序是一个字节一个字节读的
吐槽一下:这个东西是真的难写 , 倒不是说逻辑上有多难, 那个三级指针就调试了挺久的
|
|