Implementation of unix utility tail in C I've written a simple implementation of tail as part of reading The C Programming Language by Kernighan &amp; Ritchie.

The question states to write tail, which prints the last n lines of its input. By default, n is 10 but should be able to be specified by writing:
tail -n to print the last n lines. I don't think the program has to open and read files, as that hasn't been covered in the book as of yet.

I chose to take input as tail -n &lt;number&gt; and wrote the code for parsing the arguments in (hopefully) that would allow for addition of more arguments at a later date easier using the switch statement. However right now, if there were more arguments (say x and z) one could write tail -xzn 10 which would be valid, printing the last 10 lines of input - which maybe could be viewed as a problem.

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;

#define MAXLEN 1000

int tail(char *buffer[], int n);
int read_line(char *line, int max);
void print_lines(char* buffer[], int n);

static int lines_read = 0;

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

  while(--argc &gt; 0 &amp;&amp; (*++argv)[0] == '-') {
    while((c = *++argv[0])) {
      switch(c) {
        case 'n':
          if(argc-1 &gt; 0)
            number_of_lines = atoi(*(argv+1));
          break;
      }
    }
  }  

  char *line_buffer[number_of_lines];

  if(tail(line_buffer, number_of_lines) &lt; 0) {
    printf("ERROR: failed to allocate memory for a line.\n");
    return -1;
  }

  printf("Output:\n"); 
  print_lines(line_buffer, number_of_lines);

  return 0;
}

int tail(char *buffer[], int n) {
  int characters_read = 0;
  char *p, line[MAXLEN];

  while((characters_read = read_line(line, MAXLEN)) &gt; 0) {
    if((p = malloc(sizeof(char)*characters_read)) == NULL) {
      return -1;
    }
    strcpy(p, line);
    buffer[lines_read++ % n] = p;
  }

  return 0;
}

int read_line(char *line, int max) {
  int c, chars_read = 0;

  while((c = getchar()) != EOF &amp;&amp; c != '\n' &amp;&amp;  ++chars_read &lt; max-1)
    *line++ = c;

  *line = '\0';

  return chars_read;
}

void print_lines(char *buffer[], int n) {
  for(int i=0; i &lt; (lines_read &gt; n ? n : lines_read); i++)
    printf("%s\n", buffer[lines_read &gt; n ? lines_read++ % n : i]);
}
Avoid globals. lines_read is naturally suited to return lines_read.
tail leaks memory. You shall free the line pointed by buffer[....] before reassigning it.
sizeof(char) is guaranteed to be 1.


I don't remember at which point K&amp;R offer this exercise. In any case,


The line-reading loop is better expressed as fgets.
malloc/strcpy combination is a long way to say strdup.