fscanf () не работает с вводом - PullRequest
1 голос
/ 18 января 2012

Моя функция, которая записывает в файл:

Record_t * load_Record(FILE * infile)
{
    Record_t *r;
    char title[TITLE_SIZE];
    char [MEDIUM_SIZE];  
    int ID, rating;
    if ((fscanf(infile,"%d: %s %d", &ID, medium, &rating) != 3 && fgets(title, TITLE_SIZE, infile))){
            return NULL;
    }
    printf("medium is: %s title is: %s\n", medium, title);
    r = create_Record(medium, title);
    set_Record_rating(r, rating);   
    return r;
}

, где Record_t определяется как:

typedef struct Record {
    int ID;
    char * title;
    char * medium;
    int rating;
} Record_t;

Моя основная:

#include "Record.h"

#include <stdlib.h>

int main()
{

    char * title = "The Queen";
    char * medium = "DVD";
    FILE * pfile ;
    struct Record *t = create_Record(medium, title);  //creates a record
    struct Record *s;
    set_Record_rating (t, 3);
    print_Record(t);
    pfile = fopen("output.txt", "w");
    save_Record(t, pfile);
    fclose(pfile);
    destroy_Record(t);  //de-allocates memory
    pfile = fopen("output.txt", "r");
    if(!(s = load_Record(pfile))){
        return 1;
    }
    print_Record(s);
    fclose(pfile);
    destroy_Record(s);      
    return 0;
}   

output.txtпосле записи в файл:

1: DVD 3 The Queen    //checked for excess whitespace(has newline however)

Вывод на терминал:

1: The Queen DVD 3
medium is: DVD title is: �  //title being saved inappropriately  
                          @
2: �
    @ DVD 3

теперь моя fgets неправильная функция!По какой-то причине заголовок сохраняется ненадлежащим образом

Я собираю со следующими флагами: gcc -ansi -std = c89 -pedantic -Wmissing-prototypes -Wall test.c Record.c -o test

где test.c - мой главный

Ответы [ 3 ]

4 голосов
/ 18 января 2012
char * medium;

Это должно быть

char medium[SOME_CONSTANT]; // or char* medium = malloc(x); if you need the
                            // memory to persist after the function returns

Так что на самом деле medium указывает на некоторую память, которой вы владеете. Как и сейчас, ваш указатель указывает на мусор, и вы ожидаете, что fscanf сохранит строку в памяти, на которую он указывает.

Если когда-либо появляется функция, возвращающая указатель на какую-то магически созданную память, вам лучше проверить документацию дважды (если только эта функция не дурацкая strdup). Функция либо ожидает указатель на некоторую уже выделенную память, либо возвращает указатель, который указывает на блок памяти, выделенный кому-то из семейства malloc, и в этом случае вам нужно взять на себя ответственность за его освобождение.

Только в очень редких случаях функции возвращают указатель на память, не занимая предварительно выделенный буфер и не имея malloc d его ( особенно , когда возвращаемая строка имеет непредсказуемый размер для fscanf).

2 голосов
/ 18 января 2012

Вы не выделили буфер для носителя:

char * medium;  

Это просто создает указатель на символ с именем media, вы не зарезервировали пространство памяти для чтения. Это позволит выделить 256 байтов (что позволяет читать до 256 символов) для носителя:

medium = malloc(256);

Или вы можете выделить в стеке:

char medium[256];

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

fwrite(t, sizeof(Record_t), 1, pFile);
fread(t, sizeof(Record_t), 1, pFile);
1 голос
/ 18 января 2012

Несколько способов:

  1. Вы не выделили пространство для чтения строки. Вам нужно:

    char medium[100];
    
  2. Вы не проверяете ошибки должным образом:

    if (!(fscanf(infile,"%d: %s %d", &ID, medium, &rating)
    

    должно быть:

    if (fscanf(infile,"%d: %s %d", &ID, medium, &rating) != 3 ...
    

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

Это царапает поверхность без глубокого анализа всего кода. Обратите внимание, что вам нужно быть уверенным, что вы не пытаетесь вернуть medium к вызывающему коду. Это должно быть хорошо, если create_record() делает разумную работу. Странно, что create_record() не сообщается идентификатор записи.

...