Unix tail command using stack I'm working on a version of the Unix tail command that works by iterating over a file, pushing line by line into a stack. Finally, the number of desired lines will be popped and printed to the screen. I have used void * (void pointers) as the data field of my stack nodes (the stack is basically a linked list with limitations) and due to that I had to do a bit of work with pointer casting and successive allocations with malloc() (one chunk per line). I wonder if there isn't a better (as in simpler, more readable and less memory intensive) way of accomplishing the same goal.

Main tail.c file

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include "../utils/type_definitions.h"
#include "../stack/stack_list/stack_list.h"
#define LINE_SIZE 256

int main(int argc, char *argv[])
{

  int number_of_lines;
  if (argc == 2) {
    number_of_lines = atoi(argv[1]);
  } else {
    printf("%s\n", "Error!");
    exit(1);
  }

  FILE *f;
  if (!(f = fopen("file.txt", "r"))) {
    printf("%s\n", "Error opening file!\n");
    exit(1);
  };

  // pushing lines into stack

  int i = 0;
  char *line, *temp = (char*)malloc(LINE_SIZE);
  Node *stack = stack_new();

  while (fgets(temp, sizeof(line), f) != NULL) {
    line = (char*)malloc(LINE_SIZE);
    strcpy(line, temp);
    stack_push((void*)line, &amp;stack);
  }

  // poping and printing n lines to screen

  for (int i = 0; i &lt; number_of_lines; i++) {
    printf("%s\n",(char*)stack_top(stack));
    stack_pop(&amp;stack);
  }

  return 0;
}


Stack header file     

#ifndef __STACK_H__
#define __STACK_H__

#include &lt;stdbool.h&gt;
#include "../../utils/type_definitions.h"

Node *stack_new();
void *stack_top(Node *head);
void stack_pop(Node **head);
bool stack_is_empty(Node *head);
void stack_push(void *x, Node **head);

#endif


Implementation of stack functions

Node *stack_new() {
    return NULL;
}

bool stack_is_empty(Node *head) {
    return head == NULL;
}

void *stack_top(Node *head) {
    return head-&gt;data;
}

void stack_pop(Node **head)
{
    if (*head == NULL) return;
    Node *temp = *head;
    *head = (*head)-&gt;next;
    free(temp);
}

void stack_push(void *x, Node **head)
{
    Node *new_node = (Node*)malloc(sizeof(Node));
    new_node-&gt;data = x;
    new_node-&gt;next = *head;
    *head = new_node;
}


Edit - following are the includes missing from the file "implementations of stack functions".

#include "stack_list.h"
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdbool.h&gt;
The stack approach is dubious. It uses too much memory (the entire file is eventually collected, while you only care about its tail). Consider a ring buffer instead.
I don't see the point of #include &lt;stdbool.h&gt;
Casting is unnecessary, as in (char*)stack_top(stack) - and even dangerous, as in (Node*)malloc(sizeof(Node)). Why you shouldn't cast malloc. 
Always test that malloc doesn't return NULL.
A declaration

int i = 0;


is unnecessary.
Nitpicking. #define LINE_SIZE 256 is a very optimistic estimate. Try to manage a file with really long lines.