c-使用fscanf填充2D数组时的语法



我目前正在尝试用C语言设计一个程序,从文本文件中获取玩家的姓名和分数。名称数组和分数数组都是2D的,有助于以后更容易地显示高分。现在我有fscanf这样设置:

while(feof(file_p) == 0){
fscanf(file_p,"%s %dn", name[r][c],score[r][c]);
r++;
}

如果我没记错的话,%s通常意味着类似的东西

fscanf(file_p,"%s %dn", name,score);

我只是不知道如何控制使用这种格式将每个名称放入哪一行。

输入

John 10
Bob 20
Sue 90

预期输出

name[0][] = John    score[0][0] = 10
name[1][] = Bob     score[1][0] = 20
name[2][] = Sue     score[2][0] = 30

这里还有一些代码。我曾使用临时1D数组和strcpy将其转换为2D数组,但我不熟悉字符串库,因此也没有成功。

void displayHighScores(FILE*fp){
char name[MAX][MAX]; 
int i = 0,x = 0,score[MAX][MAX]; 
char temp_name[MAX];
int temp_score;
// Gather scores from the Document
fp = fopen(FILENAME, "r"); 
while (feof(fp) == 0) {
//gets info from Document and stores in temp variables
fscanf(fp,"%s %dn", temp_name,&temp_score); 
i++; 
}
}

谢谢你的帮助!

试图协调多个数组之间的不同数据类型,并通过数组索引将名称与分数同步,这让你苦不堪言。虽然这在2值的情况下是可行的,但它会失控,变得难以管理。相反,当您需要将不同类型的多个值作为C中的单个对象进行协调时,您应该考虑struct

在这里,如果您定义一个简单的结构来插入玩家名称、一个分数数组,然后是为该玩家存储的分数数量的计数器,那么您可以简单地为程序中的玩家声明一个结构数组,并将数据读取到玩家的每个结构中。这样,每个玩家的名字和所需的分数在单个struct中进行协调。例如,您可以将结构声明为类似于:

/* if you need a constant, #define them or use an enum */
enum { NSCORES = 10, MAXNAME = 64, NPLAYER = 128, MAXLINE = 256 };
typedef struct {                /* simply struct for a player */
char name[MAXNAME];         /* using a typedef for convenience */
int ns, scores[NSCORES];    /* ns tracks the number of scores */
} player_t;

(注意:typedef提供了一个简单的便利,不必在使用结构的所有位置的名称之前键入struct(

然后,您可以使用fgets()或POSIXgetline()将每一行读取到缓冲区中,然后从缓冲区中解析每个玩家的名称和分数。您可以使用多种方法将缓冲区中的值拆分为名称和所提供的内核数量。在这种情况下,使用简单的名字,使用sscanf()并在缓冲区中保留位置偏移量以读取所有剩余分数可能同样容易。

(将行拆分为值的另一种选择是使用一对指针将每个值括起来进行提取,使用strtok()函数(或strsep()(标记行,或者使用strchr()strspn()strcspn()的指针组合——由您决定(

您可以使用fgets()读取行,使用sscanf()分离类似于的值

int main (void) {
char buf[MAXLINE];          /* buffer to read entire line of input */
size_t n = 0;               /* counter for number of players read */
player_t player[NPLAYER] = {{ .name = "" }};    /* array of players */
/* while array not full, read each line of input into buf */
while (n < NPLAYER && fgets (buf, MAXLINE, stdin)) {
int offset;     /* to keep offset from beginning of buf */
/* read name from buf, save no. of chars read in offset */
if (sscanf (buf, "%s%n", player[n].name, &offset) == 1) {
int chars;  /* to track characters consumed for each score */
/* read score, save no. of chars read */
while (player[n].ns < NSCORES && sscanf (buf + offset, "%d%n",
&player[n].scores[player[n].ns], &chars) == 1) {
offset += chars;    /* update offset with chars read */
player[n].ns++;     /* update no. of scores for player */
}
}
if (player[n].ns)       /* if scores stored for player */
n++;                /* increment player index to next player */
}

(注意:读取name消耗的字符直接存储在offset中(因为此时没有偏移(,但随后为转换每个数字而读取的字符数存储在chars中,因此可以将其添加到当前offset中进行下一次读取(

总而言之,一个输出每个玩家的名字和分数的基本例子可能是:

#include <stdio.h>
/* if you need a constant, #define them or use an enum */
enum { NSCORES = 10, MAXNAME = 64, NPLAYER = 128, MAXLINE = 256 };
typedef struct {                /* simply struct for a player */
char name[MAXNAME];         /* using a typedef for convenience */
int ns, scores[NSCORES];    /* ns tracks the number of scores */
} player_t;
int main (void) {
char buf[MAXLINE];          /* buffer to read entire line of input */
size_t n = 0;               /* counter for number of players read */
player_t player[NPLAYER] = {{ .name = "" }};    /* array of players */
/* while array not full, read each line of input into buf */
while (n < NPLAYER && fgets (buf, MAXLINE, stdin)) {
int offset;     /* to keep offset from beginning of buf */
/* read name from buf, save no. of chars read in offset */
if (sscanf (buf, "%s%n", player[n].name, &offset) == 1) {
int chars;  /* to track characters consumed for each score */
/* read score, save no. of chars read */
while (player[n].ns < NSCORES && sscanf (buf + offset, "%d%n",
&player[n].scores[player[n].ns], &chars) == 1) {
offset += chars;    /* update offset with chars read */
player[n].ns++;     /* update no. of scores for player */
}
}
if (player[n].ns)       /* if scores stored for player */
n++;                /* increment player index to next player */
}
for (size_t i = 0; i < n; i++) {                /* loop over players */
printf ("%-10s", player[i].name);           /* output name */
for (int j = 0; j < player[i].ns; j++)      /* loop over scores */
printf (j ? ", %d" : "%d", player[i].scores[j]);  /* output scores */
putchar ('n');         /* tidy up with newline */
}
}

示例输入

为了展示如何为每个玩家获取多个(和不同数量的(分数,输入为每个玩家提供不同数量的分数:

$ cat dat/players_scores.txt
John 10 11   12   17
Bob 20  30   40   50  60  70
Sue 90 91 92

(注意:由于sscanf()"%d"转换说明符忽略前导空白,因此忽略所有空白(

示例使用/输出

文件只需在stdin上重定向到程序(文件处理留给您,尽管只需获得要读取的文件名,调用fopen(),然后验证文件是否打开以供读取,并将fgets()调用中的stdin更改为FILE*指针(

$ ./bin/players_scores < dat/players_scores.txt
John      10, 11, 12, 17
Bob       20, 30, 40, 50, 60, 70
Sue       90, 91, 92

这看起来像是你为玩家设计的程序。从可靠的数据处理开始要好得多,而用阵列向前推进却发现它变得太难管理,这会导致大量重写。仔细看看,如果你还有问题,请告诉我。

最新更新