Как мне прочитать две строки в каждой строке, строка за строкой, из файла в C - PullRequest
0 голосов
/ 20 мая 2018

Я пытаюсь прочитать строки из файла, который выглядит следующим образом:

String1 A
String2 B
String3 C

и т. Д.

и хранить их в двух отдельных структурных массивах;имя_строки и группа.Все, что я нашел, было для строк, разделенных символом или другими кодами, которые похожи, но не та же самая проблема

#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include <math.h>
#include "string.h"

struct StringStruct {
    char    Stringname[16];
    char    group[1];
}String[100];

int MaxNumLines = 100, i;
char str[25];

int main()
{
    // open String.dat file as a read from file
    FILE *fp1;
    errno_t string_file = fopen_s(&fp1, "String.dat", "r");

    // if String.dat not found,
    if (fp1 == NULL)
    {
        // print error
        printf_s("Error: String.dat not found\n");
        exit(0);
    }
    // if String.dat found
    else
    {
        // print success
        printf_s("File String.dat opened successfully\n");
    }

    // read names and assign groups
    while (fscanf_s(fp1, "%s %s", String[i].Stringname, String[i].group) != EOF)
    {
        // read names one line at a time
        for (i = 0; i < MaxNumLines; i++)
        {
            // read string name
            scanf_s(str, "%s %s", String[i].Stringname, String[i].group);
        }    

    }
    for (i = 0; i < MaxNumLines; i++)
    {
        printf_s("%-12s", String[i].Stringname);
        printf_s("%s", String[i].group);
    }
}

}

Теперь, на мой взгляд, все должно работать,но это не так, и я также получаю предупреждения fscanf_s:

  • предупреждение C4477: 'fscanf_s': строка формата '% s' требует аргумент типа 'unsigned int',но переменный аргумент 2 имеет тип 'char *'
  • примечание: этот аргумент используется в качестве размера буфера
  • предупреждение C4473: 'fscanf_s': недостаточно аргументов для строки формата
  • примечание: заполнители и их параметры ожидают 4 переменных аргумента, но было предоставлено 2
  • примечание: отсутствующий переменный аргумент 3 требуется для строки формата "% s"
  • примечание: этот аргументиспользуется спецификатором преобразования

Но я посмотрел на функцию fscanf_s и все, похоже, соответствует ее описанию использования.

Я не самый опытный вС, но я училсядо сих пор это происходило в течение года, и я пытался найти решение этих проблем в течение нескольких дней, но за это время не добился прогресса.

Ответы [ 3 ]

0 голосов
/ 20 мая 2018
  1. Предложения по исправлению: 1) четкое требование: сканирование - это сканирование входов с клавиатуры, здесь вы хотите прочитать строки из файла, поэтому не используйте сканирование 2) ясная логика: в цикле обработки строки чтения файловстрока не должна снова использовать цикл for.Здесь следует иметь в виду, что одна строка из файловой карты один объект структуры 3) условные обозначения имен: имя массива 'String' не является допустимым именем 4) код многократного использования: длина массива должна совпадать с числомстрок файла.5) ручная очистка: всегда закрывайте файл после открытия, освобождайте память после malloc.
  2. Если вам не нужно разбираться с устройствами / оборудованием, лучше изучить Python, который будет лучше обрабатывать тексты,Указатели и память на c немного сложны.

#include "stdio.h"
#include "stdlib.h"
#include <math.h>
#include "string.h"

struct  Stringstruct
{
    char    Stringname[16];
    char    *group;
};


int MAX_LINE = 100;// max count of chars in one line

int main()
{
    // open String.dat file as a read from file
    FILE *fp1;
    errno_t string_file = fopen_s(&fp1, "String.dat", "r"); 
    char *sep = " \n";//split the string line into tokens.
    char *token = NULL;
    char *next_token = NULL;  
    char buf[100];//100 is the max chars number of one line

    if (fp1 == NULL) {
        // print error
        printf_s("Error: String.dat not found\n");
        exit(0);
    }
    else
    {
        // print success
        printf_s("File String.dat opened successfully\n");
    }

    //get the line count of the file, allocate memory to the array dynamically
    int linecount = 0; 
    while (fgets(buf, MAX_LINE, fp1) != NULL)
    {
        linecount++;
    }
    struct Stringstruct  *myarray = malloc(sizeof(struct Stringstruct)* linecount);

    //back to the start of the file and process the strings line by line
    rewind(fp1);

    int i = -1;
    while (fgets(buf, sizeof(buf), fp1))//read the file line by line
    { 
        i++;
        token = strtok_s(buf, sep, &next_token); 
        int temp = strlen(token);
        strcpy_s(myarray[i].Stringname, strlen(token)+1, token); 

        //since there's newline chars at the end of the string line, like '\n' or '\r\n'
        //normally it will loop for two times, 
        //add the exception processing in this block
        while (token != NULL) 
        {
            // Get next token: 
            if (token != NULL)
            {
                //printf(" %s\n", token);
                token = strtok_s(NULL, sep, &next_token);  
                int temp = strlen(token);
                myarray[i].group = malloc(sizeof(char));
                strcpy_s(myarray[i].group, strlen(token) + 1, token); 
                break;
            }
        }

        //if the index exceed, stop the loop
        if (i >= linecount) {
            printf_s("Error: array mystring over flow\n");
            break;
        }         
    }

    fclose(fp1);//close the file

    for (i = 0; i < linecount; i++)
    {
        printf_s("%-12s", myarray[i].Stringname);
        printf_s("%s\n", myarray[i].group);
        myarray[i].group = NULL;
    }

    free(myarray);
    myarray = NULL;

    system("PAUSE");

    return 0; 
}
0 голосов
/ 23 мая 2018

бритва Оккама.Я не уверен, что мое намерение в моем вопросе было ясно, но я нашел невероятно простое решение моей проблемы:

for(i=0;i<num_strings;i++)
{
    fscanf_s(fp, "%16s", String[i].name, 16);
    fscanf_s(fp, "%2s", String[i].group, 2);
}

16 - максимальная длина имени + ~ 2 и 2 - удобный размер для группы.string.

Печать их в другом цикле подтверждает, что они работают, по крайней мере для меня.Извините, если это очевидный метод для ветеранов, но, поскольку я новичок в этом, я не был уверен, что спросить.

Спасибо тем, кто помог!

0 голосов
/ 20 мая 2018

При использовании семейства функций scanf_s спецификаторы формата %s, %c и %[ ожидают два аргумента, а не один.Первый - это указатель на буфер, в котором должны храниться данные, а второй - размер этого буфера.

Для вашего кода это будет выглядеть примерно так:

fscanf_s(fp1, "%s %s", String[i].Stringname, 16, String[i].group, 1)

Обратите внимание, что обычное семейство функций scanf принимает только один аргумент (указатель на буфер) для этих форматов.

Для получения дополнительной информации об этих функциях здесь .

...