Как читать конкретные данные из текстового файла (С)? - PullRequest
0 голосов
/ 26 апреля 2018

Я немного новичок в C (а также на этом сайте), и у меня возник вопрос о проекте, над которым я работаю.Часть, на которой я застрял, - это файл ввода / вывода, так как я никогда не изучал эту часть в моем предыдущем классе.Итак, входной файл (.txt) выглядит следующим образом:

REGISTERS
R5 11
R7 15
R21 4
MEMORY
4 12
12 92
[OTHER STUFF]

Файл дает нам произвольные номера регистров, за которыми следует его содержимое (от R0 до 31, Regs со значением 0 опущено).В следующем разделе приводятся области памяти в аналогичном формате, а затем снова содержимое.Тогда больше разделов, с которыми я могу разобраться позже.

Мой вопрос: как мне прочитать в регистре / ячейках памяти и их значениях?В настоящее время у меня есть массив размера 32 для хранения содержимого и переменная для номера и значения Reg (Пример: Registers [regNumber] = regValue;), но я не знаю, как начать правильно читать значения после слова REGISTERS.

Что я пробовал:

Я немного осмотрелся и мне удалось прочитать в тестовом входном файле только одну строку: "R5 11".Для этого я сделал:

fscanf(file_ptr, "R%d %d", &regNumber, &regValue);

Я напечатал переменные regNumber, regValue, и они правильно дали мне 5 и 11. Но как мне сделать это для любого количества строк после слова REGISTERS и остановиться наслово ПАМЯТЬ?

Я предполагаю, что каким бы ни было решение, я могу сделать то же самое, чтобы прочитать в местах и ​​значениях ПАМЯТИ.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Я бы не стал использовать fscanf здесь, потому что вы не можете смотреть в будущее и видеть, является ли следующая строка REGISTERS или MEMORY или что-то еще.Теоретически вы можете проверить возвращаемое значение fscanf, но код очень быстро запутается.

Лучшее решение - использовать fgets для извлечения всей строки.Если строка равна REGISTERS\n, то вы знаете, что следующие строки являются строками регистра и т. Д. Сам анализ может быть выполнен с помощью sscanf, что похоже на fscanf, но вместо чтения из буфера FILE*,он читает из строки.

Итак, я бы сделал:

enum mode_t {
    REGISTERS = 0,
    MEMORY,
    ...,
    INVALID
};

int parse_file(FILE *file_ptr, int *registers, int some_other_params)
{
    if(file_ptr == NULL || registers == NULL)
        return 0;

    char line[1024];

    enum mode_t mode = INVALID;

    while(fgets(line, sizeof line, file_ptr))
    {
        if(strcmp(line, "REGISTERS\n") == 0)
        {
            mode = REGISTERS;
            continue;
        } else if(strcmp(line, "MEMORY\n") == 0) {
            mode = MEMORY;
            continue;
        } // keep adding if(strcmp.... as needed)

        if(mode == INVALID)
        {
            fprintf(stderr, "Invalid file format\n");
            return 0; // or a better error handling
        }

        int ret;
        switch(mode)
        {
            case REGISTERS:
                ret = parse_registers(line, registers);
                break;
            case MEMORY:
                ret = parse_memory(line, some_other_args);
                break;
            ...
        }

        // evaluate ret and do error handling if necessary
    }

    return 1;
}

Используя mode для состояния анализа, вы можете определить, какой раздел вы анализируете.Затем вам нужно написать такие функции, как parse_registers и parse_memory, которые выполняют реальный анализ строк, например:

int parse_registers(const char *line, int *registers)
{
    if(line == NULL || registers == NULL)
        return 0;

    int regNumber, regValue;

    if(sscanf("R%d %d", &regNumber, &regValue) != 2)
    {
        fprintf(stderr, "Invalid format for REGISTER section\n");
        return 0;
    }

    if(regNumber < 0 || regNumber > 31)
    {
        fprintf(stderr, "Invalid register number %d\n", regNumber);
        return 0;
    }

    registers[regNumber] = regValue;

    return 1;
}

Теперь вы можете реализовать parse_memory и другие parse_xxx функции длядругие разделы файла.

0 голосов
/ 26 апреля 2018

Вы можете прочитать в полной строке текстового файла функцию fgets (), а затем strcmp или strncmp строку для строковых литералов «REGISTERS» и «MEMORY».

То, как ваш input.txtотформатировал все после того, как «REGISTERS» имеет тот же формат до «MEMORY», а все после «MEMORY» - тот же формат.Может быть, что-то вроде следующего будет работать, хотя, возможно, есть лучшие альтернативы:

int main () {
   FILE *fp;
   char str[60];
   int input_type = 0; //you can enum this for the input types you have
   int line_num = 0;

   /* opening file for reading */
   fp = fopen("input.txt" , "r");
   if(fp == NULL) {
      perror("Error opening file");
      return(-1);
   }
   while( fgets (str, 60, fp)!=NULL ) { // dont really need the != NULL compare here.
      line_num++;
      /* Parse the next line in the file */
      if(strcmp(str,"MEMORY") == 0){
         //the next lines will be formatted like memory input lines
         input_type = 2; //This should be an enum or macro
         continue;
      }
      if(strcmp(str,"REGISTERS") == 0){
         //the next lines will be formatted like register input lines
         input_type = 1;//Also should be enum or macro
         continue;
      }
      switch(input_type){
         case 0:
            fprintf(stderr,"Failed to find REGISTER keyword%d\n",line_num);
            break;
         case 1:
            sscanf(str, "R%d %d", &regNumber, &regValue); //parse known string format
            do_something(&regNumber, &regValue);
            break;
         case 2:
            sscanf(str, "%d %d", &memNumber, &memValue); //parse known string format
            do_something_else(&memNumber, &memValue);
            break;
         default:
            fprintf(stderr,"Could not find input format at line %d\n",line_num);
            break;
      }
   }
   fclose(fp);

   return(0);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...