gpt4 book ai didi

c - 从csv文件读取并分成变量

转载 作者:太空宇宙 更新时间:2023-11-04 03:34:25 25 4
gpt4 key购买 nike

我试图将输入值分为两个不同的类别。第一个数组调用teamname将保存团队名称,第二个数组将保存该周的分数。我的输入文件是.csv,代码是以字符串的形式存储的,而不是两个单独的变量。另外,我不懂程序,只熟悉图书馆。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

#define FILEIN "data.csv"
#define FILEOUT "matrix.csv"

int main (void)
{
double nfl[32][32], teamscore[32];
char teamname[30];
int n;
FILE *filein_ptr;
FILE *fileout_ptr;

filein_ptr = fopen (FILEIN, "r");
fileout_ptr = fopen (FILEOUT, "w");

for (n = 1; n <= 32; n++) {
fscanf (filein_ptr, "%s %lf\n", &teamname, &teamscore[n]);
fprintf (fileout_ptr, "%s %f\n", teamname, teamscore);
}

fclose (filein_ptr);
fclose (fileout_ptr);

return 0;
}

我应该说,输入文件的第一列有团队名称,第二列有团队分数。任何帮助都很好。谢谢!
这是一个示例输入文件
钢人,20
爱国者,25岁
袭击者,15
酋长,35岁

最佳答案

除了将&teamname更改为teamname之外,您可能还需要考虑其他一些因素。首先,总是初始化变量。虽然不是必需的,但这有一些积极的好处。对于数值数组,它初始化所有元素,以防止意外读取未初始化的值。对于字符数组,初始化为0将确保字符串的第一个副本(小于总长度)将null-terminated,并防止尝试读取未初始化的值。这只是个好习惯:

    double teamscore[MAXS] = {0.0};
char teamname[30] = {0};
int n = 0;

您已经为 filein_ptrfileout_ptr定义了默认值,您可以对数组大小执行相同的操作。如果数组大小需要更改,则只需提供一个值即可更新,从而使代码更易于维护。
接下来,这是一个相当重要的问题。 main接受参数,由标准定义为 int argc, char **argv(在Unix系统上还可以看到 char **envp,看起来它们都是以等效形式编写的 char *argv[]char *envp[])。这里的要点是使用它们为程序获取参数,这样您就不会被硬编码的 data.csvmatrix.csv文件名所困扰。您可以使用硬编码值,并且仍然可以通过使用简单的 ternary运算符(例如 test ? if true code : if false code;)为用户提供输入所选文件名的能力:
    FILE *filein_ptr = argc > 1 ? fopen (argv[1], "r") : fopen (FILEIN, "r");
FILE *fileout_ptr = argc > 2 ? fopen (argv[2], "w") : fopen (FILEOUT, "w");

在这里,测试 argc > 1(意味着至少有一个由用户给定的参数),如果是真代码 open (argv[1], "r")(打开作为读取参数给定的文件名,如果是假代码 fopen (FILEIN, "r"),则打开默认值(如果不是给定的文件名)。输出文件也是如此。(必须按正确顺序提供)。
然后,如果打开一个文件,则必须在尝试读取该文件之前验证该文件是否已实际打开。虽然可以分别测试输入和输出以判断哪一个失败,但也可以使用一个简单的 ||条件来检查打开是否失败:
    if (!filein_ptr || ! fileout_ptr) {
fprintf (stderr, "error: filein of fileout open failed.\n");
return 1;
}

最后,如果您知道需要读取的数据行数,那么可以使用索引的 for循环,但您很少会事先知道数据文件中的行数。即使使用 for循环,您仍然需要检查 fscanf的返回,以验证您实际上有2个有效的转换(因此得到了您期望的2个值)。检查报税表也提供了另一个好处。它允许您继续阅读,直到您不再从 fscanf获得2个有效的转换。这提供了一种从文件中读取未知数量值的简单方法。但是,您确实需要确保不会尝试在数组中读取超出其容量的值。例如。:
    while (fscanf (filein_ptr, " %29[^,],%lf", teamname, &teamscore[n]) == 2) {
fprintf (fileout_ptr, "%s %f\n", teamname, teamscore[n++]);
if (n == MAXS) { /* check data doesn't exceed MAXS */
fprintf (stderr, "warning: data exceeds MAXS.\n");
break;
}
}

注意:当使用包含字符大小写的格式说明符(如 "%[^,], ...")时,请注意它将读取并在转换为字符串时包含前导和尾随空格。因此,如果您的文件有 ' Steelers ,..'teamname将包含空白。您可以通过在转换开始之前包括一个空间(如 " %29[^,], ..."),并通过指定最大字段宽度来限制可读取的字符数,来修复引导的空白。(本例中的尾随空格在读取后更容易修剪)
将所有的部分放在一起,您可以通过使用来自用户的参数,并验证文件和读取操作,使代码更加灵活和可靠:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>

#define FILEIN "data.csv"
#define FILEOUT "matrix.csv"
#define MAXS 32

int main (int argc, char **argv)
{
/* double nfl[MAXS][MAXS] = {{0}}; */
double teamscore[MAXS] = {0.0};
char teamname[30] = {0};
int n = 0;
FILE *filein_ptr = argc > 1 ? fopen (argv[1], "r") : fopen (FILEIN, "r");
FILE *fileout_ptr = argc > 2 ? fopen (argv[2], "w") : fopen (FILEOUT, "w");

if (!filein_ptr || ! fileout_ptr) {
fprintf (stderr, "error: filein of fileout open failed.\n");
return 1;
}

while (fscanf (filein_ptr, " %29[^,],%lf", teamname, &teamscore[n]) == 2) {
fprintf (fileout_ptr, "%s %f\n", teamname, teamscore[n++]);
if (n == MAXS) { /* check data doesn't exceed MAXS */
fprintf (stderr, "warning: data exceeds MAXS.\n");
break;
}
}

fclose (filein_ptr);
fclose (fileout_ptr);

return 0;
}

测试输入
$ cat ../dat/teams.txt
Steelers, 20
Patriots,25
Raiders, 15
Chiefs,35

注意:前导空白和值之间空白的变化是有意的。
使用/输出
$ ./bin/teams ../dat/teams.txt teamsout.txt

$ cat teamsout.txt
Steelers 20.000000
Patriots 25.000000
Raiders 15.000000
Chiefs 35.000000

如果你还有问题,请告诉我。

关于c - 从csv文件读取并分成变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33761409/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com