Ошибка при использовании fprintf и fscanf - PullRequest
0 голосов
/ 07 июня 2018

У меня есть архив results.csv, и мне нужно прочитать первую строку этого архива и распечатать его на output.txt.Каким-то образом он печатает случайные символы после всего, и я не могу понять, что не так.

Команда: a.c results.csv

Первая строка: date,home_team,away_team,home_score,away_score,tournament,city,country,neutral

output.txt: date,home_team,away_team,home_score,away_score,tournament,city,country,neutral,(!£,(!£,(!£,(!£,(!£,@,£,(!£,(!£

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


typedef struct
{
    char *line1;
    char *line1a;
    char *line1b;
    char *team1;
    char *team2;
    char *reason;
    char *city;
    char *country;
    char *neutral_field;

}data;


void open_input(char *argv[], FILE **input)
{       

        if((*input=fopen(argv[1], "r")) == NULL)
        {
            printf("%s not found\n", argv[1]);
                exit(1);
        }

}
void open_output(char *string, FILE **output)
{       

        if((*output=fopen(string, "w")) == NULL)
        {
            printf("%s not found\n", string);
                exit(1);
        }

}

void alloc_data(data *d, int size)
{
d->line1 = (char*)malloc(4*sizeof(char)); 
d->team1 = (char*)malloc(9*sizeof(char)); 
d->team2 = (char*)malloc(9*sizeof(char)); 
d->line1a = (char*)malloc(10*sizeof(char)); 
d->line1b = (char*)malloc(10*sizeof(char)); 
d->reason = (char*)malloc(10*sizeof(char)); 
d->city = (char*)malloc(4*sizeof(char)); 
d->country = (char*)malloc(7*sizeof(char)); 
d->neutral_field = (char*)malloc(7*sizeof(char)); 
}

void store(data *d, FILE *input, FILE **output)
{

    fscanf(input,  "%s,%s,%s,%s,%s,%s,%s,%s,%s", d[0].line1, d[0].team1, d[0].team2, d[0].line1a, d[0].line1b, d[0].reason, d[0].city, d[0].country, d[0].neutral_field );
    fprintf(*output,  "%s,%s,%s,%s,%s,%s,%s,%s,%s\n", d[0].line1, d[0].team1, d[0].team2, d[0].line1a, d[0].line1b, d[0].reason, d[0].city, d[0].country, d[0].neutral_field );


}

int main(int argc, char *argv[])
{
    FILE *input;
    FILE *output;
    char *string = "output.txt";
    int size = 1000;

    open_input(argv, &input);   
    open_output(string, &output);   

    data *d;
    d = (data*)malloc(size*sizeof(data)); 
    alloc_data(d, size);

    store(d, input, &output);

    free(d);

    return 0;
}

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

fscanf(input, "%s,%s,%s,%s,%s,%s,%s,%s,%s", d[0].line1, d[0].team1,...

Приведенный выше код пытается прочитать всю строку в d[0].line1, что вызывает переполнение буфера.team1, а остальные будут содержать неинициализированные данные.

Вам необходимо изменить fscanf следующим образом:

fscanf(input, "%3[^ ,\n\t],%9[^ ,\n\t],...

Где 3 - 4 - 1, а 4 - размер d[0].line1

В качестве альтернативы вы можете использовать strtok

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

void store(FILE *input, FILE *output)
{
    char buf[500];
    while(fgets(buf, sizeof(buf), input))
    {
        //strip end-of-line from `buf`
        if(strlen(buf))
            if(buf[strlen(buf) - 1] == '\n')
                buf[strlen(buf) - 1] = 0;

        //tokenize with strtok
        char *token = strtok(buf, ",");
        while(token)
        { 
            fprintf(output, "%s", token);
            token = strtok(NULL, ",");
        }
        fprintf(output, "\n");
    }
}

int main(int argc, char *argv[])
{
    FILE *input = fopen("input.txt", "r");
    FILE *output = fopen("output.txt", "w");
    store(input, output);
    return 0;
}

С приведенным выше кодом вам не нужна дополнительная структура.


Если вы используете структуру для данных, вы должны быть более осторожными.Кажется, вы пытаетесь создать массив 1000 data, но следующее создает только один указатель увеличенного размера, а не массив data
int size = 1000;
data *d;
d = (data*)malloc(size*sizeof(data)); 
alloc_data(d, size);

Кроме того, для каждого malloc должно бытьсоответствующий free.

0 голосов
/ 07 июня 2018

Ваши буферы недостаточно велики, чтобы содержать завершающий байт NUL.scanf сохраняет этот байт NUL (переполнение буфера), но затем объект, которому действительно принадлежит этот байт, может перезаписать его, поэтому, когда printf ищет NUL, он не находит его намного позже в памяти.

Переполнение буфера - большая проблема, чем то, что вы видели, кто знает, какие объекты разбивают те байты NUL, для которых вы не выделяете пространство?А что происходит, когда вы читаете файл данных с несколько иным написанием заголовка?Внезапно ваши жестко запрограммированные размеры выделений станут еще более неправильными, чем уже есть.

...