|
发表于 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编译通过, 汉字会出现乱码, 因为汉字是占两个字节的, 而本程序是一个字节一个字节读的
吐槽一下:这个东西是真的难写, 倒不是说逻辑上有多难, 那个三级指针就调试了挺久的
|
|