Implementation of unix utility tail in C
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
I've written a simple implementation of tail as part of reading The C Programming Language by Kernighan & 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 <number>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 > 0 && (*++argv)[0] == '-')
while((c = *++argv[0]))
switch(c)
case 'n':
if(argc-1 > 0)
number_of_lines = atoi(*(argv+1));
break;
char *line_buffer[number_of_lines];
if(tail(line_buffer, number_of_lines) < 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)) > 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 && c != 'n' && ++chars_read < max-1)
*line++ = c;
*line = '';
return chars_read;
void print_lines(char *buffer, int n)
for(int i=0; i < (lines_read > n ? n : lines_read); i++)
printf("%sn", buffer[lines_read > n ? lines_read++ % n : i]);
c io unix
add a comment |Â
up vote
3
down vote
favorite
I've written a simple implementation of tail as part of reading The C Programming Language by Kernighan & 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 <number>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 > 0 && (*++argv)[0] == '-')
while((c = *++argv[0]))
switch(c)
case 'n':
if(argc-1 > 0)
number_of_lines = atoi(*(argv+1));
break;
char *line_buffer[number_of_lines];
if(tail(line_buffer, number_of_lines) < 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)) > 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 && c != 'n' && ++chars_read < max-1)
*line++ = c;
*line = '';
return chars_read;
void print_lines(char *buffer, int n)
for(int i=0; i < (lines_read > n ? n : lines_read); i++)
printf("%sn", buffer[lines_read > n ? lines_read++ % n : i]);
c io unix
<limits.h>
has an implementation-definedLINE_MAX
that you can piggyback off of instead of defining your ownMAXLEN
.
â Andrew Piliser
Jan 25 at 19:47
@AndrewPiliser: Do you have a reference for<limits.h>
definingLINE_MAX
? I can't seem to find it in my copy of the standard.
â Jerry Coffin
Jan 25 at 20:06
@JerryCoffin That might be a Linux-specific thing, I found it here: pubs.opengroup.org/onlinepubs/7908799/xsh/limits.h.html.
â Andrew Piliser
Jan 25 at 22:12
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I've written a simple implementation of tail as part of reading The C Programming Language by Kernighan & 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 <number>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 > 0 && (*++argv)[0] == '-')
while((c = *++argv[0]))
switch(c)
case 'n':
if(argc-1 > 0)
number_of_lines = atoi(*(argv+1));
break;
char *line_buffer[number_of_lines];
if(tail(line_buffer, number_of_lines) < 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)) > 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 && c != 'n' && ++chars_read < max-1)
*line++ = c;
*line = '';
return chars_read;
void print_lines(char *buffer, int n)
for(int i=0; i < (lines_read > n ? n : lines_read); i++)
printf("%sn", buffer[lines_read > n ? lines_read++ % n : i]);
c io unix
I've written a simple implementation of tail as part of reading The C Programming Language by Kernighan & 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 <number>
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 > 0 && (*++argv)[0] == '-')
while((c = *++argv[0]))
switch(c)
case 'n':
if(argc-1 > 0)
number_of_lines = atoi(*(argv+1));
break;
char *line_buffer[number_of_lines];
if(tail(line_buffer, number_of_lines) < 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)) > 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 && c != 'n' && ++chars_read < max-1)
*line++ = c;
*line = '';
return chars_read;
void print_lines(char *buffer, int n)
for(int i=0; i < (lines_read > n ? n : lines_read); i++)
printf("%sn", buffer[lines_read > n ? lines_read++ % n : i]);
c io unix
edited Jan 25 at 18:39
200_success
123k14143401
123k14143401
asked Jan 25 at 18:05
bag
503
503
<limits.h>
has an implementation-definedLINE_MAX
that you can piggyback off of instead of defining your ownMAXLEN
.
â Andrew Piliser
Jan 25 at 19:47
@AndrewPiliser: Do you have a reference for<limits.h>
definingLINE_MAX
? I can't seem to find it in my copy of the standard.
â Jerry Coffin
Jan 25 at 20:06
@JerryCoffin That might be a Linux-specific thing, I found it here: pubs.opengroup.org/onlinepubs/7908799/xsh/limits.h.html.
â Andrew Piliser
Jan 25 at 22:12
add a comment |Â
<limits.h>
has an implementation-definedLINE_MAX
that you can piggyback off of instead of defining your ownMAXLEN
.
â Andrew Piliser
Jan 25 at 19:47
@AndrewPiliser: Do you have a reference for<limits.h>
definingLINE_MAX
? I can't seem to find it in my copy of the standard.
â Jerry Coffin
Jan 25 at 20:06
@JerryCoffin That might be a Linux-specific thing, I found it here: pubs.opengroup.org/onlinepubs/7908799/xsh/limits.h.html.
â Andrew Piliser
Jan 25 at 22:12
<limits.h>
has an implementation-defined LINE_MAX
that you can piggyback off of instead of defining your own MAXLEN
.â Andrew Piliser
Jan 25 at 19:47
<limits.h>
has an implementation-defined LINE_MAX
that you can piggyback off of instead of defining your own MAXLEN
.â Andrew Piliser
Jan 25 at 19:47
@AndrewPiliser: Do you have a reference for
<limits.h>
defining LINE_MAX
? I can't seem to find it in my copy of the standard.â Jerry Coffin
Jan 25 at 20:06
@AndrewPiliser: Do you have a reference for
<limits.h>
defining LINE_MAX
? I can't seem to find it in my copy of the standard.â Jerry Coffin
Jan 25 at 20:06
@JerryCoffin That might be a Linux-specific thing, I found it here: pubs.opengroup.org/onlinepubs/7908799/xsh/limits.h.html.
â Andrew Piliser
Jan 25 at 22:12
@JerryCoffin That might be a Linux-specific thing, I found it here: pubs.opengroup.org/onlinepubs/7908799/xsh/limits.h.html.
â Andrew Piliser
Jan 25 at 22:12
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
accepted
Avoid globals.
lines_read
is naturally suited to returnlines_read
.tail
leaks memory. You shallfree
the line pointed bybuffer[....]
before reassigning it.sizeof(char)
is guaranteed to be 1.
I don't remember at which point K&R offer this exercise. In any case,
The line-reading loop is better expressed as
fgets
.malloc/strcpy
combination is a long way to saystrdup
.
Is there a reason to usefgets
instead ofgetline
?
â Andrew Piliser
Jan 25 at 19:46
@AndrewPiliser: all the usual ones, such as it's already well documented, and tested, and everybody who knows C immediately recognizes what it is and what it does. There is another minor detail: hisgetline
looks like if a line is too long, it'll read a single line as multiple lines, and give no warning that it's doing so.fgets
can read partial lines, but gives you a warning when it does so (the buffer you read will have a new-line if and only if you read the entire line).
â Jerry Coffin
Jan 25 at 20:17
@AndrewPiliser I was not even sure thatfgets
is within the scope of this exercise.get line
is definitely out.
â vnp
Jan 25 at 20:46
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
accepted
Avoid globals.
lines_read
is naturally suited to returnlines_read
.tail
leaks memory. You shallfree
the line pointed bybuffer[....]
before reassigning it.sizeof(char)
is guaranteed to be 1.
I don't remember at which point K&R offer this exercise. In any case,
The line-reading loop is better expressed as
fgets
.malloc/strcpy
combination is a long way to saystrdup
.
Is there a reason to usefgets
instead ofgetline
?
â Andrew Piliser
Jan 25 at 19:46
@AndrewPiliser: all the usual ones, such as it's already well documented, and tested, and everybody who knows C immediately recognizes what it is and what it does. There is another minor detail: hisgetline
looks like if a line is too long, it'll read a single line as multiple lines, and give no warning that it's doing so.fgets
can read partial lines, but gives you a warning when it does so (the buffer you read will have a new-line if and only if you read the entire line).
â Jerry Coffin
Jan 25 at 20:17
@AndrewPiliser I was not even sure thatfgets
is within the scope of this exercise.get line
is definitely out.
â vnp
Jan 25 at 20:46
add a comment |Â
up vote
1
down vote
accepted
Avoid globals.
lines_read
is naturally suited to returnlines_read
.tail
leaks memory. You shallfree
the line pointed bybuffer[....]
before reassigning it.sizeof(char)
is guaranteed to be 1.
I don't remember at which point K&R offer this exercise. In any case,
The line-reading loop is better expressed as
fgets
.malloc/strcpy
combination is a long way to saystrdup
.
Is there a reason to usefgets
instead ofgetline
?
â Andrew Piliser
Jan 25 at 19:46
@AndrewPiliser: all the usual ones, such as it's already well documented, and tested, and everybody who knows C immediately recognizes what it is and what it does. There is another minor detail: hisgetline
looks like if a line is too long, it'll read a single line as multiple lines, and give no warning that it's doing so.fgets
can read partial lines, but gives you a warning when it does so (the buffer you read will have a new-line if and only if you read the entire line).
â Jerry Coffin
Jan 25 at 20:17
@AndrewPiliser I was not even sure thatfgets
is within the scope of this exercise.get line
is definitely out.
â vnp
Jan 25 at 20:46
add a comment |Â
up vote
1
down vote
accepted
up vote
1
down vote
accepted
Avoid globals.
lines_read
is naturally suited to returnlines_read
.tail
leaks memory. You shallfree
the line pointed bybuffer[....]
before reassigning it.sizeof(char)
is guaranteed to be 1.
I don't remember at which point K&R offer this exercise. In any case,
The line-reading loop is better expressed as
fgets
.malloc/strcpy
combination is a long way to saystrdup
.
Avoid globals.
lines_read
is naturally suited to returnlines_read
.tail
leaks memory. You shallfree
the line pointed bybuffer[....]
before reassigning it.sizeof(char)
is guaranteed to be 1.
I don't remember at which point K&R offer this exercise. In any case,
The line-reading loop is better expressed as
fgets
.malloc/strcpy
combination is a long way to saystrdup
.
answered Jan 25 at 19:33
vnp
36.6k12991
36.6k12991
Is there a reason to usefgets
instead ofgetline
?
â Andrew Piliser
Jan 25 at 19:46
@AndrewPiliser: all the usual ones, such as it's already well documented, and tested, and everybody who knows C immediately recognizes what it is and what it does. There is another minor detail: hisgetline
looks like if a line is too long, it'll read a single line as multiple lines, and give no warning that it's doing so.fgets
can read partial lines, but gives you a warning when it does so (the buffer you read will have a new-line if and only if you read the entire line).
â Jerry Coffin
Jan 25 at 20:17
@AndrewPiliser I was not even sure thatfgets
is within the scope of this exercise.get line
is definitely out.
â vnp
Jan 25 at 20:46
add a comment |Â
Is there a reason to usefgets
instead ofgetline
?
â Andrew Piliser
Jan 25 at 19:46
@AndrewPiliser: all the usual ones, such as it's already well documented, and tested, and everybody who knows C immediately recognizes what it is and what it does. There is another minor detail: hisgetline
looks like if a line is too long, it'll read a single line as multiple lines, and give no warning that it's doing so.fgets
can read partial lines, but gives you a warning when it does so (the buffer you read will have a new-line if and only if you read the entire line).
â Jerry Coffin
Jan 25 at 20:17
@AndrewPiliser I was not even sure thatfgets
is within the scope of this exercise.get line
is definitely out.
â vnp
Jan 25 at 20:46
Is there a reason to use
fgets
instead of getline
?â Andrew Piliser
Jan 25 at 19:46
Is there a reason to use
fgets
instead of getline
?â Andrew Piliser
Jan 25 at 19:46
@AndrewPiliser: all the usual ones, such as it's already well documented, and tested, and everybody who knows C immediately recognizes what it is and what it does. There is another minor detail: his
getline
looks like if a line is too long, it'll read a single line as multiple lines, and give no warning that it's doing so. fgets
can read partial lines, but gives you a warning when it does so (the buffer you read will have a new-line if and only if you read the entire line).â Jerry Coffin
Jan 25 at 20:17
@AndrewPiliser: all the usual ones, such as it's already well documented, and tested, and everybody who knows C immediately recognizes what it is and what it does. There is another minor detail: his
getline
looks like if a line is too long, it'll read a single line as multiple lines, and give no warning that it's doing so. fgets
can read partial lines, but gives you a warning when it does so (the buffer you read will have a new-line if and only if you read the entire line).â Jerry Coffin
Jan 25 at 20:17
@AndrewPiliser I was not even sure that
fgets
is within the scope of this exercise. get line
is definitely out.â vnp
Jan 25 at 20:46
@AndrewPiliser I was not even sure that
fgets
is within the scope of this exercise. get line
is definitely out.â vnp
Jan 25 at 20:46
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f185990%2fimplementation-of-unix-utility-tail-in-c%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
<limits.h>
has an implementation-definedLINE_MAX
that you can piggyback off of instead of defining your ownMAXLEN
.â Andrew Piliser
Jan 25 at 19:47
@AndrewPiliser: Do you have a reference for
<limits.h>
definingLINE_MAX
? I can't seem to find it in my copy of the standard.â Jerry Coffin
Jan 25 at 20:06
@JerryCoffin That might be a Linux-specific thing, I found it here: pubs.opengroup.org/onlinepubs/7908799/xsh/limits.h.html.
â Andrew Piliser
Jan 25 at 22:12