Программа C для печати первых и последних n строк в файле, что я делаю неправильно?

Я новичок в программировании в целом. Обратите внимание, что это домашнее задание. Я использую текстовый файл с az в нижнем регистре. Я использую команду ./a.out test.txt для запуска программы, затем ввожу число.

мой код:

#include <stdio.h>

static void cat(FILE *fp, int num) {
    int count = 0;
    char buffer[4096];

    while (fgets(buffer, sizeof(buffer), fp) != 0) {
        if (count == num)
            break;
        else
            count++;
        fputs(buffer, stdout);
    }
}

int main(int argc, char *argv[]) {
    int num, count = 0;
    long length;
    char buffer[4096];

    FILE *fp;
    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        printf("Can't open this file\n");
        return 0;
    }

    scanf("%d", &num);
    cat(fp, num);
    printf("...\n");

    fseek(fp, 0, SEEK_END);
    length = ftell(fp);
    fseek(fp, (length - 2), SEEK_SET);
    printf("1\n");
    while (fgets(buffer, sizeof(buffer), fp) != 0) {
        fputs(buffer, stdout);
    }
    if (ftell(fp) == '\n') {
        count++;
        length = ftell(fp);
        fseek(fp, (length - 4), SEEK_SET);
        printf("2\n");
        while (fgets(buffer, sizeof(buffer), fp) != 0) {
            fputs(buffer, stdout);
        }
    } else {  //<------ missing opening brace
        length = ftell(fp);
        fseek(fp, (length - 2), SEEK_SET);
        printf("3\n");
        while (fgets(buffer,s izeof(buffer), fp) != 0) {
            fputs(buffer, stdout);
        }
        if (count == num) {
            printf("4\n");
            while (fgets(buffer, sizeof(buffer), fp) != 0) {
                fputs(buffer, stdout);
        }
    }

    fclose(fp);
    return 0;
}

Пожалуйста помоги!


person N. Cvt.    schedule 14.02.2016    source источник
comment
Пожалуйста, добавьте пробелы между операторами, ваш код плохо читается, и что это за ftell(fp)=='\n'? зачем ты это делаешь?   -  person Iharob Al Asimi    schedule 14.02.2016
comment
Вы разместили код, который не скомпилировался?   -  person Martin James    schedule 15.02.2016


Ответы (2)


Я переформатировал ваш код, чтобы улучшить читаемость. Там, где я указал, отсутствует {. Как написано, код не компилируется.

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

Выделите массив из n буферов:

char (*array)[4096] = calloc(4096, num);

Для каждой прочитанной строки перемещайте буферы и копируйте строку в последнюю позицию:

memmove(array[0], array[1], sizeof(array[0] * (num - 1));
strcpy(array[num - 1], buffer);

Есть более эффективные методы, но вы должны быть в состоянии реализовать этот простой метод.

Когда вы дойдете до конца файла, напечатайте непустые строки из массива.

ИЗМЕНИТЬ:

Вот полная версия, в которой используется массив num+1 буферов. Он читает весь файл, печатая первые num строк по мере их чтения и постоянно сохраняя последние num строк в массиве, циклически повторяя позицию, в которой читается следующая строка, из num+1 буферов.

В конце файла, если файл содержит более num строк, должны быть напечатаны дополнительные строки, потенциально разделенные --------, если строки в середине файла пропущены. Печатаются последние num строк или меньше: pos вычисляется, чтобы найти правильный буфер по модулю num+1, и строки печатаются до последнего.

Вот код:

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

int main(int argc, char *argv[]) {
    int num, pos, count;
    FILE *fp;
    char (*array)[4096];  /* pointer to an array of buffers */

    if (argc < 2) {
        printf("Usage headtail filename [number]\n");
        return 1;
    }
    fp = fopen(argv[1], "r");
    if (fp == NULL) {
        printf("Cannot open file %s\n", argv[1]);
        return 1;
    }
    if (argc > 2) {
        /* get the number from the command line if 2 args were given */
        if (sscanf(argv[2], "%d", &num) != 1) {
            num = -1;
        }
    } else {
        /* otherwise read from standard input */
        if (scanf("%d", &num) != 1) {
            num = -1;
        }
    }
    if (num < 0) {
        printf("Invalid number\n");  /* negative or non numeric */
        return 1;
    }

    /* allocate space for num+1 buffers */
    array = malloc(4096 * (num + 1));

    for (count = pos = 0; fgets(array[pos], 4096, fp) != NULL; count++) {
        /* printing the first num lines */
        if (count < num)
            fputs(array[pos], stdout);
        /* cycle buffers for num lines + 1 extra buffer */
        if (++pos >= num + 1)
            pos = 0;
    }
    if (count > num) {
        /* more lines to print */
        pos = count - num;
        if (pos > num) {
            /* print place holder for missing lines */
            printf("...\n");
        } else {
            /* print from the last line printed */
            pos = num;
        }
        for (; pos < count; pos++) {
            fputs(array[pos % (num + 1)], stdout);
        }
    }
    fclose(fp);
    return 0;
}
person chqrlie    schedule 14.02.2016
comment
что ты имеешь в виду? Как я уже говорил выше, я мало что знаю о программировании, поэтому не могли бы вы объяснить немного больше? - person N. Cvt.; 15.02.2016
comment
Спасибо за ответ! Теперь мне просто нужно это понять... :P - person N. Cvt.; 15.02.2016
comment
@N.Cvt.: Я обновил ответ, указав более простой и эффективный метод, который использует меньше памяти. Изучите это, должно быть легче понять. - person chqrlie; 15.02.2016
comment
Хороший! Вместо того, чтобы выделять большой буфер (часть) для каждой строки, было бы лучше динамически выделять отдельный буфер (правильного размера) для каждой строки. Я беззастенчиво добавляю ссылку на один из своих ответов с такой функцией строки чтения для справки: - person Daniel Jour; 15.02.2016
comment
@DanielJour: Спасибо за альтернативу. На самом деле это может быть не так эффективно: если файл длинный, мой метод просто считывает файл в список циклического буфера. Ваш метод с использованием getline() будет продолжать освобождать старые строки и кропотливо выделять новую для каждой прочитанной строки. Ваш метод имеет то преимущество, что поддерживает слишком длинные строки, но использует очень неэффективную схему перераспределения фрагментами по 9 байтов. Вы должны по крайней мере сделать временный буфер длиной 1024 байта. - person chqrlie; 15.02.2016
comment
Действительно, размер фрагмента, а также масштабирование размера фрагмента (если он добавлен) должны быть улучшены. Что меня беспокоит, так это пустая трата места, если строки не такие длинные (4095) и если n велико. - person Daniel Jour; 15.02.2016
comment
Спасибо еще раз за помощь! Обязательно запомню! - person N. Cvt.; 15.02.2016

1) Вы должны проверить, меньше ли размер файла размера буфера.

2) Если вы собираетесь читать файл для n строк в кусках данных за раз, читайте его по одной строке за раз. вероятно, с помощью fscanf. Таким образом, вы можете отслеживать, сколько строк вы прочитали/напечатали. Также это помогает узнать, достаточно ли строк в вашем файле.

person Hardhik    schedule 14.02.2016