Вы мучаете себя без конца, пытаясь согласовать различные типы данных между несколькими массивами, синхронизируя имена с оценками по индексу массива. Хотя это выполнимо с 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;
( note: typedef
обеспечивает простое удобство, так как нет необходимости вводить struct
перед именем везде, где используется структура)
Затем вы можете прочитать каждую строку в буфер, используя fgets()
или POSIX getline()
, а затем проанализировать имя и оценки для каждого игрока из буфера. Вы можете использовать несколько методов, чтобы разделить значения в вашем буфере на имя и столько ядер, сколько предусмотрено. В этом случае с простыми именами, вероятно, так же просто использовать 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
(поскольку в этой точке нет смещения), но затем число символов, считанных для преобразования каждого ди git хранятся в chars
, поэтому его можно добавить к текущему offset
для следующего чтения)
В целом, пример базового c, который затем выводит имя и оценку для каждого игрок может быть:
#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
( примечание : все пробелы игнорируются, поскольку спецификатор преобразования "%d"
для sscanf()
игнорирует начальные пробелы)
Пример использования / Вывод
Файл просто перенаправляется на stdin
в программу (обработка файла остается на ваше усмотрение, хотя для этого просто требуется получить имя файла для чтения, вызвать fopen()
, а затем проверить, что файл открыт для чтения и изменения stdin
в fgets()
вызове независимо от того, какой у вас указатель FILE*
)
$ ./bin/players_scores < dat/players_scores.txt
John 10, 11, 12, 17
Bob 20, 30, 40, 50, 60, 70
Sue 90, 91, 92
Это выглядело как то, куда вы направлялись с дизайном вашей программы для игроков. Гораздо лучше начать с обработки данных solid, чтобы перезаряжать массивы только для того, чтобы выяснить, что это становится слишком громоздким для последующего управления, что требует большой перезаписи. Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.