Синтаксис при использовании fscanf для заполнения 2D-массива - PullRequest
0 голосов
/ 27 апреля 2020

Я сейчас пытаюсь разработать программу на C, которая берет имя игрока и его счет из текстового файла. И массив имен, и массив оценок являются двухмерными, чтобы упростить отображение высоких результатов в дальнейшем. Прямо сейчас я настроил fscanf следующим образом:

while(feof(file_p) == 0){

fscanf(file_p,"%s %d\n", name[r][c],score[r][c]);
r++;
}

Если я правильно помню,% s обычно означает что-то вроде

  fscanf(file_p,"%s %d\n", 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 %d\n", temp_name,&temp_score); 
   i++; 
   }
   }

Спасибо за помощь!

1 Ответ

0 голосов
/ 27 апреля 2020

Вы мучаете себя без конца, пытаясь согласовать различные типы данных между несколькими массивами, синхронизируя имена с оценками по индексу массива. Хотя это выполнимо с 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, чтобы перезаряжать массивы только для того, чтобы выяснить, что это становится слишком громоздким для последующего управления, что требует большой перезаписи. Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

...