HiveBrain v1.2.0
Get Started
← Back to all entries
patterncModerate

Tail implementation in C

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
implementationtailstackoverflow

Problem

Write the program tail, which prints the last n lines of its input. By default, n is 10, let us say, but it can be changed by an optional argument, si that
tail -n
prints the last n lines. The program should behave rationally no matter how unresonable the input or the value n. Write the program so it makes the best use of available storage; lines should be stored as in the sorting program of section 5.6, not in a two-dimensional array of fixed size.

The exercise can be found on page 133 in K&R.

I will explain the way my program works.
First it parses the value of the symbolic argument(if any). Based on the value of the symbolic argument the program will initialize a queue which stores pointer to each line.

Then, the program will read lines and push every line in the queue until the end of files is reached. When the end of file is reached all elements of the queue are printed out.

There are multiple files in my project:

main.c:

#include 
#include 
#include "tail.h"

#define MAXLINES 100
#define LINESIZE 100

int main(int argc, char *argv[]) {
    int linesNumber = 10;

    if(argc > 2) {
        return 1;
    }
    else if(argc == 2) {
        linesNumber = atoi(argv[1] + 1);

        if(linesNumber == 0) {
            return 0;
        }

        initQueue(linesNumber, LINESIZE);
    }
    else {
        initQueue(linesNumber, LINESIZE);
    }

    readLines(LINESIZE, MAXLINES);

    printQueueElements();

    return 0;
}


linesNumber represent the variable that will store the size of the queue. By default this variable is 10. If the value of the symbolic argument is 0 there is no reasone to continue reading lines, so the program will terminate execution.

queue.c

```
#include
#include
#include "alloc.h"

static char **queue;
static int queueSize;

static int head = -1;
static int rear = -1;

static int isEmpty(void) {
return (head == -1 && rear == -1);
}

static int isFull(void) {
return (rear + 1) % queueSize

Solution

That is a lot of code for the job. It can be done significantly more easily in two areas:

  • use an array instead of a queue



  • use the POSIX function, getline, which will handle lines of any size.



If you don't want to use getline (which admittedly might not have existed when K&R wrote their book), concentrate on writing its equivalent.

Here is a version that uses an allocated array or char* pointers. The array is zeroed (by calloc) so that we can tell whether the entry holds a line (which might not be so if the input is less than 10 (or the requested number of) lines.

int
tail(size_t n_lines, FILE *fp)
{
    char **lines = calloc(sizeof(char*), n_lines);
    if (!lines) {
        perror("calloc");
        return -1;
    }
    size_t size = 0;
    size_t in = 0;
    for (char *ln = 0; getline(&ln, &size, fp) > 0; in = (in + 1) % n_lines) {
        if (lines[in]) {
            free(lines[in]);
        }
        lines[in] = ln;
        ln = NULL;
        size = 0;
    }
    for (size_t i = 0; i < n_lines; ++i) {
        if (lines[in]) {
            printf("%s", lines[in]);
            free(lines[in]);
        }
        in = (in + 1) % n_lines;
    }
    free(lines);
    return 0;
}

Code Snippets

int
tail(size_t n_lines, FILE *fp)
{
    char **lines = calloc(sizeof(char*), n_lines);
    if (!lines) {
        perror("calloc");
        return -1;
    }
    size_t size = 0;
    size_t in = 0;
    for (char *ln = 0; getline(&ln, &size, fp) > 0; in = (in + 1) % n_lines) {
        if (lines[in]) {
            free(lines[in]);
        }
        lines[in] = ln;
        ln = NULL;
        size = 0;
    }
    for (size_t i = 0; i < n_lines; ++i) {
        if (lines[in]) {
            printf("%s", lines[in]);
            free(lines[in]);
        }
        in = (in + 1) % n_lines;
    }
    free(lines);
    return 0;
}

Context

StackExchange Code Review Q#43142, answer score: 11

Revisions (0)

No revisions yet.