Search code examples
cfilefgetstailfseek

C Program to print first and last n lines in a file, what am I doing wrong?


I am new to programming in general. Please note that this is for homework. I am using a txt file with a-z in lowercase. I use the command ./a.out test.txt to run the program, then enter a number.

my code:

#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;
}

Please Help!


Solution

  • I reformatted your code to improve readability. There is a missing { where I indicated. As posted, the code does not compile.

    Your program should be able to print the first n lines, but your method cannot work for the last n lines.

    Allocate an array of n buffers:

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

    For each line read, move the buffers and copy the line at the last position:

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

    There are more efficient methods but you should be able to implement this simple method.

    When you reach the end of file, print the non empty lines from the array.

    EDIT:

    Here is a complete version that uses an array of num+1 buffers. It reads the whole file, printing the first num lines as they are read, and keeping the last num lines in the array at all times, cycling the position at which it read the next line over num+1 buffers.

    At the end of file, if the file has at more than num lines, extra lines must be printed, potentially separated by a -------- if lines are skipped in the middle of the file. The last num lines or less are printed: pos is computed to find the proper buffer modulo num+1 and the lines are printed until the last.

    Here is the code:

    #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;
    }