in main
while(1){
strcpy(arr[i],read());
if (arr[i]=NULL) break;
you never go out of the loop because arr[i]=NULL
has no reason to be true from read (because of an error in read), so you write out of arr with an undefined behavior (your crash)
You do not well manage the end of file in read :
fgets(line,80,stdin);
if (line != NULL) {
you need to check the result of fgets not if line is NULL except to check malloc success
not that line[strlen(line)-1] = '\0';
is useless because fgets put a final null character, fortunately else how strlen can work ?
So read can be :
char *read(){
char *line = (char *) malloc (80 * sizeof(char));
if (line != NULL) {
if (fgets(line,80,stdin) == NULL) {
free(line);
return NULL;
}
}
return line;
}
Because read can return a NULL you need to change
strcpy(arr[i],read());
and also is why you preallocate the lines while you also allocate in read ? currently you loose the memory allocated each time in read
It seems better to replace the loop by
while((arr[i] == read()) != NULL)
//printf("%s", arr[i]); //DEBUG
i += 1;
}
and to remove the preallocations of the lines
An other problem is when the file have more that 100 lines (or may be some lines are cut before too long), in that case you write out of arr. In fact you do not need to save so many lines, you just need to save 10 lines maximum
A proposal :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *read() {
char line[80];
if (fgets(line, 80, stdin) == NULL)
return NULL;
return strdup(line);
}
int main()
{
char * arr[10] = { NULL };
char * p;
int i = 0, n = 0;
while((p = read()) != NULL) {
n += 1;
free(arr[i]);
arr[i] = p;
if (++i == 10)
i = 0;
}
/* get older line index and line count to print */
if (n <= 10)
i = 0;
else
n = 10;
while (n-- != 0) {
puts(arr[i]);
free(arr[i]);
if (++i == 10)
i = 0;
}
return 0;
}
Compilation and execution :
pi@raspberrypi:/tmp/d $ gcc -g -pedantic -Wextra q.c
pi@raspberrypi:/tmp/d $ ./a.out < q.c
n = 10;
while (n-- != 0) {
puts(arr[i]);
if (++i == 10)
i = 0;
}
return 0;
}
Note I do not removed the \n is the read lines and I use puts so there are empty lines printed while the read line are not cut because too long
If the file is shorter that 10 lines :
pi@raspberrypi:/tmp/d $ tail -n 5 q.c | ./a.out
i = 0;
}
return 0;
}
Under valgrind :
pi@raspberrypi:/tmp/d $ valgrind ./a.out < q.c
==18496== Memcheck, a memory error detector
==18496== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==18496== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==18496== Command: ./a.out
==18496==
while (n-- != 0) {
puts(arr[i]);
free(arr[i]);
if (++i == 10)
i = 0;
}
return 0;
}
==18496==
==18496== HEAP SUMMARY:
==18496== in use at exit: 0 bytes in 0 blocks
==18496== total heap usage: 43 allocs, 43 frees, 5,699 bytes allocated
==18496==
==18496== All heap blocks were freed -- no leaks are possible
==18496==
==18496== For counts of detected and suppressed errors, rerun with: -v
==18496== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)