for (int i = 0; i < 4; i++) {
for (int j = 0; j <4; i++) {
while (c != EOF)
token = strtok((fgets(token,5,fp)), delim);
}
}
大家好,我是C的新手,我获得了一个项目来获取csv文件并计算每列中平均值的数量。现在我正试图用逗号解析这些行。我发现函数[strtok],但我肯定是错误地实现它。我有csv文件中的行数和列数,我只需要帮助弄清楚如何用“,”解析每一行,并将这些值放入2D数组中。上面是我将用于将值附加到数组的当前代码,但我不断收到“分段错误”。任何帮助将不胜感激。
这是函数的完整代码。我包括stdio.h和stdlib.h:
void main() {
char *strcat(char *dest, const char *src);
char *strtok(char *str, const char *delim);
char *file_name = "test.txt";
FILE *fp = fopen(file_name, "r");
int array[4][4];
//int array1 [2] = {1, 3};
int counter = 0;
char *token = " ";
const char *delim = (const char *)',';
char c = fgetc(fp);
for (int i = 0; i < 4; i++) {
token = "";
for (int j = 0; j <4; i++) {
while (c != EOF)
token = strtok((fgets(token,5,fp)), delim);
}
}
fclose(fp);
}
示例输入将是这样的:
10,20,30,60
40,50,60,70
70,80,90,80
100,110,120,70
答案 0 :(得分:0)
是的,你是对的,你错误地使用了strtok
。
我要做的第一件事就是阅读每一行并使用解析该行
strtok
,就像这样:
char line[1024];
const char *delim=",\n";
while(fgets(line, sizeof line, fp))
{
char *token = strtok(line, delim);
do {
printf("token: %s\n", token);
} while(token = strtok(NULL, delim));
}
strtok
要求必须调用strtok
的所有后续调用
NULL
。当没有更多令牌可以找到时,strtok
将返回NULL
,通常是
已达到行尾。请注意,我在中添加了换行符
分隔符论点。当目标缓冲区足够大fgets
写入时
新线也是。将换行符放在分隔符列表中是个好方法
因为strtok
会为你删除换行符。
上面的代码为您提供了一种获取csv的每个单元格的方法,作为字符串。您
必须自己转换价值观。如果csv,这是棘手的一点
包含空格,引号等,你需要不同的策略来解析
正确的细胞价值。您可以使用strtol
&amp;等功能。朋友哪个
允许你从错误中恢复,但它们不是防弹,会有
他们失败的情况。
一个简单的例子是:
char line[1024];
const char *delim=",\n";
while(fgets(line, sizeof line, fp))
{
char *token = strtok(line, delim);
do {
int val;
if(sscanf(token, "%d", &n) != 1)
fprintf(stderr, "'%s' is not a number!\n", token);
else
printf("number found: %d\n", val);
} while(token = strtok(NULL, delim));
}
请注意,这并未涵盖所有情况,例如引号中的单元格。
要做的最后一件事是存储值。一种方法是
为指向int
数组的指针分配内存并重新分配内存
每个细胞。这里的问题再次出现在csv文件中,有时它们有
格式错误,某些行将为空或某些行将具有更多或更少
列比其他行,这可能是棘手的。在这一点上,这将是一个很好的
想要使用库来解析csv。
以下代码将假设csv格式正确且数量为
所有行的列始终相同,并且没有行超过1023
长字符。当*cols
为0时,我会根据基数计算列数
第一行。如果其他行具有较少的列,则所有剩余值将为0
(因为calloc
将新分配的内存设置为0)。如果有更多
colmuns比第一行,这列将被忽略:
int **parse_csv(const char *filename, size_t *rows, size_t *cols)
{
if(filename == NULL || rows == NULL || cols == NULL)
return NULL;
FILE *fp = fopen(filename, "r");
if(fp == NULL)
return NULL;
int **csv = NULL, **tmp;
*rows = 0;
*cols = 0;
char line[1024];
char *token;
char *delim = ",\n";
while(fgets(line, sizeof line, fp))
{
tmp = realloc(csv, (*rows + 1) * sizeof *csv);
if(tmp == NULL)
return csv; // return all parsed rows so far
csv = tmp;
if(*cols == 0)
{
// calculating number of rows
char copy[1024];
strcpy(copy, line);
token = strtok(copy, delim);
do {
(*cols)++;
} while((token = strtok(NULL, delim)));
}
int *row = calloc(*cols, sizeof *row);
if(row == NULL)
{
if(*rows == 0)
{
free(csv);
return NULL;
}
return csv; // return all parsed rows so far
}
// increment rows count
(*rows)++;
size_t idx = 0;
token = strtok(line, delim);
do {
if(sscanf(token, "%d", row + idx) != 1)
row[idx] = 0; // in case the conversion fails,
// just to make sure to have a defined value
// in the cell
idx++;
} while((token = strtok(NULL, delim)) && idx < *cols);
csv[*rows - 1] = row;
}
fclose(fp);
return csv;
}
void free_csv(int **csv, size_t rows)
{
if(csv == NULL)
return;
for(size_t i = 0; i < rows; ++i)
free(csv[i]);
free(csv);
}
现在你可以像这样解析它:
size_t cols, rows;
int **csv = parse_csv("file.csv", &rows, &cols);
if(csv == NULL)
{
// error handling...
// do not continue
}
...
free_csv(csv, rows);
现在csv[3][4]
会给你第3行第4列的单元格(从0开始)。
修改强>
我从你的代码中注意到的事情:
void main()
错了。 main
应该只有以下原型之一:
int main(void);
int main(int argc, char **argv);
int main(int argc, char *argv[]);
另:
int main(void)
{
char *strcat(char *dest, const char *src);
char *strtok(char *str, const char *delim);
...
}
不要把它放在main
函数中,把它放在外面,也有标准
这个头文件。在这种情况下,请包含string.h
#include <string.h>
int main(void)
{
...
}
另一个
const char *delim = (const char *)',';
这是错的,它就像试图卖苹果并称之为橙色。 ','
是char
类型的单个字符。它的值为44.它与...相同
这样做的:
const char *delim = (const char*) 44;
您正在设置delim
应指向44的地址。
你必须使用双引号:
const char *delim = ",";
请注意,'x'
和"x"
不一样。 'x'
是120(见ASCII),它是
单个字符。 "x"
是一个字符串文字,它返回一个指向开头的指针
一系列以'\0'
结尾的字符结尾的字符,也就是a
串。这些在C中根本不同。