отримати рядок з файлу

Чому вивід цього коду - це кілька випадкових слів у пам'яті?

void conc()
{
    FILE *source = fopen("c.txt", "r+");
    if(!source)
    {
        printf("Ficheiro não encontrado");
        return;
    }

    short i = 0;
    while(fgetc(source) != EOF)
        i++;

    char tmp_str[i];
    fgets(tmp_str, i, source);
    fclose(source);
    printf("%s", tmp_str);
}

Це має дати мені зміст файлу, я думаю.

1
Ви склали вашу заявку?
додано Автор Midhun MP, джерело
чи є ваш цикл while , як це передбачено?
додано Автор Bill, джерело

6 Відповіді

Тому що після того, як ви пройшли через файл за допомогою fgetc() , індикатор позиції знаходиться в кінці файлу. fgets() не має нічого прочитати. Вам потрібно скинути його так, щоб він вказував на початок, використовуючи rewind (source); .

До речі, не прокручуйте файл за допомогою fgetc() , це надзвичайно потворне рішення. скористайтеся fseek() та ftell() або lseek() , щоб отримати розмір файлу:

fseek(source, SEEK_END, 0);
long size = ftell(source);
fseek(source, SEEK_SET, 0);//or rewind(source);

альтернатива:

off_t size = lseek(source, SEEK_END, 0);
rewind(source);
7
додано
+1 для альтернатив.
додано Автор 0decimal0, джерело
@TelmoVaz Ви ласкаво просимо. До речі, не використовуйте файл двічі, замість цього використовуйте ftell() .
додано Автор user529758, джерело
О! Ці маленькі (великі) речі ... дякую вам, сер!
додано Автор Telmo Vaz, джерело

Use rewind(source); before fgets(tmp_str, i, source);

1
додано

Після того як ваш fgetc() - цикл ви досягнете EOF, і якщо ви не fseek (source, 0l, SEEK_SET) повернетеся до початку, ви більше не отримаєте дані У будь-якому випадку вам слід уникати читання файлу двічі. Замість цього використовуйте fstat (fileno (джерело), ​​...) , щоб визначити розмір файлу.

0
додано

Кожного разу, коли ви телефонуєте fgetc (), ви пересуваєте вказівник внутрішнього файлу на один символ далі. По завершенні циклу() цикл покажчика файлу буде в кінці файлу. Наступні виклики, намічені для читання на ручці файлу, не зможуть виконати умови EOF.

У посібнику Fgets сказано, що:

    

Якщо кінець файлу виникає під час спроби прочитати символ, встановлюється індикатор eof (feof). Якщо це відбувається до того, як будь-які символи можуть бути прочитані, покажчик повертається нульовим покажчиком (а вміст str залишається незмінним).

  

Наслідком є ​​те, що tmp_str залишається незмінним. Сміття, яке ви повертаєте під час виклику printf, фактично є частиною функції stack conc ().

Рішенням вашої проблеми було б перемотування покажчика файлу за допомогою fseek() перед викликом fgets ().

fseek(source, 0, SEEK_SET);

Тоді кращий спосіб отримати розмір вашого файлу буде fseek до кінця файлу, і використовувати ftell, щоб отримати поточну позицію:

long size;
fseek(source, 0, SEEK_END);
size = ftell(source);

При цьому, ваш код все ще має проблему. Коли ви виділяєте в стек (змінні, локальні для функції), вам слід вказати розмір змінної в момент складання. Тут ваш компілятор виділяє довжину масиву довжини 0. Я пропоную вам дослідити динамічне розміщення за допомогою malloc ключового слова новий , якщо ви кодування на C ++.

Правильний розподіл буде виглядати наступним чином:

char *tmp_str = malloc(size);
// Here you read the file
free(tmp_str);

Простішим рішенням може бути попереднє виділення рядка, достатньо великого для зберігання вашого файлу.

char tmp_str[1024 * 100];//100Kb

Потім використовуйте змінну size , яку ми отримали раніше, щоб переконатися, що файл буде поміщений у tmp_str перед читанням.

0
додано

fgetc читає символ із потоку. fgets читає рядок із потоку.

Тепер у вашому коді ви повторюєте через кінець файлу. Таким чином, виклик fgets у потоці просто поверне NULL і залишить вміст буфера незмінним. У вашому випадку ваш буфер не ініціалізується. Це пояснює випадкові значення, які ви бачите.

Замість того, щоб читати повний файловий вміст за допомогою fgetc, щоб отримати кількість символів, я рекомендую використовувати fseek/ftell (див. Відповідь з цього нитка )

0
додано

Ваш код неправильний. Як було сказано раніше:

  1. Ви не повинні читати файл двічі
  2. Щоб динамічно розподілити масив, потрібно використовувати оператор new (у c ++) або функція malloc (в с)

Якщо вам потрібен код для читання вмісту файлу, спробуйте виконати наступне (вибачте, але я його не склав, він все одно повинен працювати добре):

FILE* source = fopen("c.txt", "r+b");
if(!source){return;}
fseek(source, 0, SEEK_END);
size_t filesize = ftell(source);
fseek(source, 0, SEEK_SET);
char* buf = new char[filesize+1];//+1 is for '/0'
fread(buf, sizeof(char), filesize, source);
fclose(source);
buf[filesize]=0;
printf("%s", buf);
delete buf;
0
додано