Application crashes with segmentation fault - c

I know what this error means, but I can't see what I did wrong here. I implemented a function to delete files and directories, and I also want to implement the "-i" functionality for a "rm" command. Command used: rm -i filename.
I get asked if I want to remove it, I type "y", the file I want to remove gets deteleted, but the program crashes afterwards and I don't know why.
int has_args(char * argv[], char arg[])
{
int i = 0;
while(argv[i] != NULL) {
if(strcmp(argv[i], arg) == 0) {
return 1;
}
i++;
}
return 0;
}
void print_error(char *this, char *filename)
{
fprintf(stderr, "%s: Could not delete file: %s;\n%s\n", this, filename, strerror(errno));
}
int cmd_rm(int argc, char *argv[])
{
errno = 0;
if(argc > 1) {
if(has_args(argv, "-r")) {
remove_directory(argv[2]);
}
else if(has_args(argv, "-i")) {
char ans[2];
fprintf(stdout, "Delete file: '%s'?\n", argv[2]);
scanf("%s", ans);
trim(ans);
if((ans[0] == 'Y') || (ans[0] == 'y')) {
if(remove(argv[2])) {
print_error(argv[0], argv[2]);
}
}
}
else {
if(remove(argv[1])) {
print_error(argv[0], argv[1]);
}
}
}
else {
puts("ERROR: ");
print_usage(argv[0]);
}
return 0;
}

Why don't you try scanf("%c",&ch); as the answer if user can input only y or n, however if you like to support yes or no you may write the following code :
scanf("%1,3s",ans); /* Points out that the minimum length is 1 and the maximum length is 3 */
and as others have pointed out in some case cmd_rm() function should return 1 or any other value to indicate success in the deletion of file. However I can't see any success case in your function cmd_rm() and it would be better if you enclose your trim function.
But generally Segmentation faults are because of pointers not pointing to a correct position ( tricky pointers ). Debuggers come handy in finding these pointers.

Related

Writing to CSV from another CSV with fgets() and skipping lines

FULL DISCLOSURE: SCHOOL ASSIGNMENT
I've been working on some code to pull data from a CSV and move it to another CSV, however I keep encountering this error I can't seem to overcome.
For the part I'm working on, the user supplies a command line argument with 'DELETE OPT1' where OPT1 is the ID of an entry in the CSV. The deleteStuff() function should go through the database.csv and delete the first entry/row of a matching ID. It should achieve this by creating a database.tmp, then copying the database.csv over to the tmp, excluding the first matching entry. The csv is then deleted and then the tmp is renamed to database.csv, as if nothing happened.
However, the source code (database.csv) seems to be doing something wrong and deleting everything but the ID's. Below, I've posted the source code and the starting database.csv, as well as what the code outputs after running DELETE 10. Any help would be appreciated, especially in understanding how to the next line of a fgets().
Note that the noSpaces() function just removes any empty spaces since it is possible for them to be included in the input according to our prof.
database.c:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char show[] = "SHOW";
char delete[] = "DELETE";
char add[] = "ADD";
void noSpaces(char* s) {
const char* d = s;
do {
while (*d == ' ') {
++d;
}
} while (*s++ = *d++);
}
void showStuff() {
FILE* csv = fopen("database.csv", "rt");
if (csv == NULL) {
printf("\n File opening failed");
exit(1);
}
char buffer[800];
char *Gptr, *ID, *name, *cAge, *cGPA;
int counter = 1;
while (fgets(buffer, sizeof(buffer), csv)) {
ID = strtok(buffer, ",");
noSpaces(ID);
name = (strtok(NULL, ","));
noSpaces(name);
cAge = (strtok(NULL, ","));
noSpaces(cAge);
int age = atoi(cAge);
cGPA = (strtok(NULL, ","));
noSpaces(cGPA);
double GPA = strtod(cGPA, &Gptr);
printf("Record %d: ID=%-5s NAME:%-5s AGE:%-5d GPA:%.1f\n", counter, ID, name, age, GPA);
counter++;
}
fclose(csv);
}
void deleteStuff(char givenID[]) {
FILE* csvread = fopen("database.csv", "rt");
if (csvread == NULL) {
printf("\n File opening failed");
exit(1);
}
FILE* csvwrite = fopen("database.tmp", "wt");
char buffer[800];
char* ID;
int oneAndDone = 0;
while (fgets(buffer,sizeof(buffer),csvread)) {
ID = strtok(buffer, ",");
noSpaces(ID);
if ((strcmp(ID, givenID) == 0) && (oneAndDone == 0)) {
oneAndDone++;
continue;
}
fprintf(csvwrite, "%s", buffer);
}
system("rm database.csv");
system("mv database.tmp database.csv");
fclose(csvread);
fclose(csvwrite);
if (oneAndDone == 0) {
printf("Sorry, the user was not found. Nothing was deleted.\n\n");
exit(1);
}
}
void addStuff(char gID[], char gName[], char gAge[], char gGPA[]) {
char* Gptr;
int age = atoi(gAge);
double GPA = strtod(gGPA, &Gptr);
FILE* csvappend = fopen("database.csv", "at");
if (csvappend == NULL) {
printf("\n File opening failed");
exit(1);
}
fprintf(csvappend, "%s,%s,%d,%.1f", gID, gName, age, GPA);
fclose(csvappend);
}
void main(int argc, char* argv[]) {
if (argc == 1) {
printf("Your did not provide any arguments. Please enter: ./database CMD OPT1 OPT2 OPT3 OPT4 \n\n");
exit(1);
}
if (strcmp(argv[1], show) == 0) showStuff();
else if (strcmp(argv[1], delete) == 0) {
if (argc <= 2) {
printf("Name of record to delete is missing\n\n");
exit(1);
}
deleteStuff(argv[2]);
}
else if (strcmp(argv[1], add) == 0) {
if (argc <= 5) {
printf("Missing ID, Name, AGE, and GPA Arguments\n\n");
exit(1);
}
addStuff(argv[2], argv[3], argv[4], argv[5]);
}
else printf("The command you requested in invalid. Please select from one of these: SHOW, DELETE, ADD\n\n");
}
Original database.csv:
10,bob,18, 3.5
15,mary,20,4.0
5,tom, 17, 3.8
After database.csv:
155
When using strtok you must understand it modifies the string that you are tokenizing. If you will need to use the string after calling strtok, you should make a copy of the string first. Always check the man page for any function you are using if you are unsure exactly how it works, e.g. man 3 strtok
Be cautious when using these functions. If you do use them, note
that:
* These functions modify their first argument.
Unless you are programming for a microcontroller of some other device without an operating system (a "freestanding" system) the use of void main() is wrong. See: C11 Standard - §5.1.2.2.1 Program startup(p1). See also: What should main() return in C and C++?
You make use of the flag int oneAndDone = 0; -- which is fine. However, after you have found the ID provided on the command line and incremented oneAndDone++; (or just set oneAndDone = 1;), there is no longer a need to call strtok at all. Wouldn't it make more sense to completely skip the strtok call after oneAndDone is no longer 0? Something like:
char buffer[800];
char* ID;
int oneAndDone = 0;
while (fgets(buffer,sizeof(buffer),csvread)) {
if (oneAndDone == 0) {
char bcopy[800];
strcpy (bcopy, buffer);
ID = strtok(bcopy, ",");
noSpaces(ID);
if (strcmp(ID, givenID) == 0) {
oneAndDone = 1;
continue;
}
}
fprintf(csvwrite, "%s", buffer);
}
You have done a good job Not Skimping On Buffer Size with char buffer[800]; -- but don't use Magic-Numbers in your code either. Better:
...
#include <string.h>
#define MAXC 800 /* if you need a constant, #define one (or more) */
...
char buffer[MAXC];
char* ID;
int oneAndDone = 0;
while (fgets(buffer,sizeof(buffer),csvread)) {
if (oneAndDone == 0) {
char bcopy[MAXC];
...
You certainly want to close the files you are reading and writing from before you make system calls to rm and mv. For example:
fclose(csvread);
fclose(csvwrite);
system("rm database.csv");
system("mv database.tmp database.csv");
You always want to check the return fclose after-write to catch any stream error or problem with the file that may not be caught by checking only the write itself, e.g.
if (fclose(csvwrite) == EOF)
perror ("fclose-csvwrite");
That way you at least have an indication on whether the stream was flushed successfully and there were no errors on close.
Lastly, Enable Compiler Warnings and do not accept code until it compiles without warning. For gcc/clang use as minimum -Wall -Wextra -pedantic (consider adding -Wshadow as well). For VS use /W3. For any other compiler, check the documentation and enable comparable warnings. That would point you to add enclosing parenthesis around:
} while ((*s++ = *d++));
in void noSpaces(char* s).
That should get you going. Think through and make the changes and let me know if you have further problem.

Get the user to enter a name but using file stream *fp

I am a beginner in c so I have a problem with get the user to input last name, a comma & then first name. However it will pass to the function call
int get_name(FILE *fp)
in my main function. I have a problem either if I have to use the arguments parameters.
Example, main (int argc, char *argv[])) or just main (void))
and from what I have been searching so far, FILE*fp cannot get the user to enter from stdin it only use to open the file(?) BUT I am required to get the user to input from keyboard and pass to the function. I have written some codes. but they don't seem to work but I am going to put down on here the one I am sure that I need a few changes most.
#define LINESIZE1024
int main(void){
FILE *fp;
char line[LINESIZE];
char first;
char last;
char comma;
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(fp = (sscanf(line,"%s %s %s",&last,&comma,&first)==3))
get_name(fp);
if(get_last_first(fp)== -1)
break;
printf("Please enter first name a comma and then last name");
}
BUT I got an error saying I can't use pass it from pointer to an integer. and many MORE but I accidentally closed my concolse and all the errors that appeared while I was trying to fix are gone. So please give me some ideas.
What about seconde code
while(1){
if(!fgets(line,LINESIZE,fp)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s %s %s",last,comma,first)==3)
get_last_first(fp);
return 0;
}
It gave me errors too. fp,last,first,comma used uninitialized in this function
OK so I think I have fixed the previous problem now. However it doesn't print the name back if the name is given correctly. Here is my fixed main code.
int main(void){
FILE *fp = stdin;
char line[LINESIZE];
char first[16];
char last[16];
while(1){
if(!fgets(line,LINESIZE,stdin)){
clearerr(stdin);
break;
}
if(sscanf(line,"%s ,%s",last,first)==2)
if(get_name(fp)==2)
printf("Your name is: %s %s\n", first, last);
}
return 0;
}
here is my function.
int get_name(FILE *fp){
char line[LINESIZE];
char last[16], first[16];
int n;
/* returns -1 if the input is not in the correct format
or the name is not valid */
if(fgets(line, LINESIZE, fp) == NULL) {
return -1;
}
/* returns 0 on EOF */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == EOF) {
return 0;
}
/* prints the name if it's valid */
if((n = sscanf(line, " %[a-zA-Z-] , %[a-zA-Z-]", last, first)) == 2) {
return 2;
}
return 1;
}
I thank you people so much for taking time to read and help me. Please don't be mean :)
Seems that you are making it more complicated than needed. Don't call fgets and scanf in main. Only do that in the function get_name.
It can be something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINESIZE 1024
int get_name(FILE *fp)
{
char line[LINESIZE];
char* t;
if(!fgets(line, LINESIZE,fp))
{
printf("Error reading input\n");
return 0;
}
t = strstr(line, ",");
if (t)
{
*t = '\0';
++t;
printf("First: %s - Last: %s\n", line, t);
return 2;
}
printf("Illegal input\n");
return 0;
}
int main(int argc, char **argv)
{
get_name(stdin);
return 0;
}
If you later decide that you want to read from a file, you can reuse the function get_name without changing it at all. All you need is to change main. Like:
int main(int argc, char **argv)
{
FILE* f = fopen("test.txt", "r");
if (f)
{
get_name(f);
fclose(f);
}
else
{
printf("Open file failed\n");
}
return 0;
}
If you want to read from the keyboard, read from stdin or use scanf, which internally reads from stdin. If you want to read from a file instead, use FILE *fp, but don't forget to open the file and check if it was successful (you'll find lots of tutorials for this).
Further, when reading in strings, you need an array of characters, not a single one. Note further, that scanf can already deal with formats like "everything that is not a ',' then a ',' then a string. Note that format "[^,]" means "any character except a ',':
So you could adapt the code as follows:
#define LINESIZE 1024
int main(void){
char line[LINESIZE];
char first[LINESIZE];
char last[LINESIZE];
while(fgets(line,LINESIZE,stdin)) {
if(sscanf(line,"%[^,],%s",last,first)==2) {
printf("Read in %s ... %s\n",last,first);
}
else {
printf("Please enter first name a comma and then last name");
}
}
return 0;
}
And if your professor is picky concerning the "use FILE*", you could write:
FILE *fp = stdin;
...
while(fgets(line,LINESIZE,fp)) {
...

stdout buffering problems

I have written up this code
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
char *list[20],*story[100];
FILE*listfile;
FILE*infile;
FILE*outfile;
int check(char*string)
{
int i=0;
while(list[i]!=NULL)
{
if(strcmp(string,list[i])==0){return 1;};
i++;
};
return 0;
};
void print_d(int d){ printf(" debug %d ",d);};
int main(int argc,char**argv){
assert(argc==4);
printf("hello \n");
//assigning the file pointers in their respective modes
printf("%s %s %s ",argv[1],argv[2],argv[3]);
listfile=fopen(argv[1],"r");
print_d(12);
infile=fopen(argv[2],"r");
outfile=fopen(argv[3],"w");
print_d(0);
int i=0; /* the infamous 'i' */
while(1)
{
if(feof(listfile)!=0)
{ break;};
list[i]=malloc(sizeof(char [15]));
fscanf(listfile,"%s[^\n]",list[i]);
i++;
}
i=0;
print_d(1);
while(1)
{
if(feof(infile)!=0)
{ break;};
story[i]=malloc(sizeof(char [25]));
fscanf(infile,"%s",story[i]);
i++;
}
fclose(infile);
fclose(listfile);
i=0;
print_d(2);
while(1)
{
if(check(story[i])==1)
{ fprintf(outfile,"%s","censored");}
else
{
fprintf(outfile,"%s",story[i]);
};
};
print_d(3);
fclose(outfile);
i=0;
while(list[i]!=NULL)
{ free(list[i]);};
return 0;
}
The following problem ensues
[1] THe output is a hello followed by a seg fault
and here is where things get interesting
if I modify
printf("%s %s %s ",argv[1],argv[2],argv[3]);
to
printf("%s %s %s\n ",argv[1],argv[2],argv[3]);
the ouput is a 'hello' followed with the three names of the files and then a segfault.
After user danfuzz pointed out I should change the print_d debug to print to stderr (which I did) ..the debug prints work fine now.SO I suppose a better question would be why did that happen in the first place and steps to prevent such things from happening?
It may seem trivial a problem for seasoned programmers but mind you, the earlier version(the one in the code above) failed to print out any message before a seg fault , leading me to conclude that something happened in the commandline part of things /opening of the file.
Some observations,
You should read about fflush(stdout), as it will help you with your debug statements,
void print_d(int d)
{
printf(" debug %d ",d); fflush(stdout);
};
You allocate to arrays of char pointers, list[20], and story[100], but you have loops (indexed by the notorious 'i'), which could easily walk off the end of list or story.
You attempt to open files for filenames argv[2] and argv[3], one as read the other as write, change these lines to the following,
printf("%s %s %s ",argv[1],argv[2],argv[3]); fflush(stdout);
if( !(listfile=fopen(argv[1],"r")) )
{
printf("cannot open %s\n",argv[1]); fflush(stdout);
return(1);
}
print_d(1);
if( !(infile=fopen(argv[2],"r")) )
{
printf("cannot open %s\n",argv[2]); fflush(stdout);
return(2);
}
print_d(2);
if( !(outfh=fopen(argv[3],"w+")) ) //notice the "w+" to create missing file
{
printf("cannot open %s\n",argv[3]); fflush(stdout);
return(3);
}
print_d(3);
Now the files are opening properly, so change the debug print_d arguments to increasing numerical order, so you can spot sequentially which, and since you are using counters, a for(;;) loop works,
int check(char*string)
{
int i;
for(i=0; list[i]!=NULL; i++)
{
if(strcmp(string,list[i])==0){return 1;};
};
return 0;
};
Changing the loops to read both files successfully,
for(i=0; i<20; ++i)
{
if(feof(listfh)!=0) { break; };
list[i]=malloc(sizeof(char [15]));
fscanf(listfh,"%s[^\n]",list[i]);
}
fclose(listfh);
debug(4);
And,
for(i=0; i<20; ++i)
{
if(feof(infh)!=0) { break; };
story[i]=malloc(sizeof(char [25]));
fscanf(infh,"%s",story[i]);
}
fclose(infh);
debug(5);
And now a simple change to the loop to scan the story, to check for censorship (eek!), so we avoid comparing and printing null pointers (another problem you had),
for(i=0; i<100 && (story[i]); ++i)
{
if(check(story[i])==1)
{
fprintf(outfh,"%s","censored"); fflush(outfh);
}
else
{
fprintf(outfh,"%s",story[i]); fflush(outfh);
};
};
But hey, note that you really don't need to read the story into an array, you could read a line at a time, and print combine those two loops, and you can scan arbitrarily large files, without allocating lots of space,
for(i=0; 1; ++i)
{
if(feof(infh)!=0) { break; };
story[0]=malloc(sizeof(char [25]));
fscanf(infh,"%s",story[0]);
if(check(story[0])==1)
{
fprintf(outfh,"%s","censored"); fflush(outfh);
}
else
{
fprintf(outfh,"%s",story[0]); fflush(outfh);
};
}
fclose(infh);
fclose(outfh);
You also need to make sure you only free the lines you allocated,
for(i=0; list[i] && list<20; i++)
{
free(list[i]);
}
This should fix your problems.
Add a usage() function,
void usage(char*progname)
{
printf("need 3 files\n");
printf("%s <restricted> <story> <censorted>\n",progname);
}
And call it,
if( argc < 4 )
{
usage(argv[0]);
return 0;
}
Instead of guessing or asking in forums, just run a debugger. If working on linux, gdb will take you straight to the location of the segmentation fault.
Lets say you app is called "foo":
> gdb foo
# run
And when it crashes:
# bt

I tried decomposing my function, but I'm not sure if I did it right

Originally, this function was embedded into the main function, creating a very cluttered main function. The program replaces tabs with the number of spaces. I'm still confused as to what goes inside the argument lists for my functions and how to pass argc/argv from main into these functions. Did I do this right?
There are some defined variables at the top of the file:
#define OUTFILE_NAME "detabbed"
#define TAB_STOP_SIZE 8
#define NUM_ARGS 2
#define FILE_ARG_IDX 1
Here's my second attempt at it:
void open_file(FILE *inf, FILE *outf, char *in[]) /*I feel like the arguments aren't right
{ and this function is just opening
and reading files*/
inf = fopen(in[1], "r");
outf = fopen(OUTFILE_NAME, "w");
if (inf == NULL)
{
perror(in[1]);
exit(1);
}
else if (outf == NULL)
{
perror(OUTFILE_NAME);
exit(1);
}
fclose(inf);
fclose(outf);
}
void detab(FILE *infile, FILE *outfile, char *argument[]) /* Confused about argument list
{ and this function actually
char c; does the detabbing */
int character_count = 0, i, num_spaces;
open_file(infile, outfile, argument); /* I want to call the previous
function but again, confused
while (fscanf(infile, "%c", &c) != EOF) about the argument list */
{
if (c == '\t')
{
num_spaces = TAB_STOP_SIZE - (character_count % TAB_STOP_SIZE);
for (i = 0; i < num_spaces; i++)
{
fprintf(outfile, " ");
}
character_count += num_spaces;
}
else if (c == '\n')
{
fprintf(outfile, "\n");
character_count = 0;
}
else
{
fprintf(outfile, "%c", c);
character_count++;
}
}
}
int main(int argc, char *argv[])
{
if (argc < 1)
{
fprintf(stderr, "usage: prog file\n");
exit(1);
}
else if (argc < NUM_ARGS)
{
fprintf(stderr, "usage: %s file\n", argv[0]);
exit(1);
}
detab(argc, argv); /* I want to pass argc and argv to the detab function, but I'm
having trouble with the argument list */
return 0;
}
What I need help with, is figuring out what goes in the argument lists of the functions. I think what confuses me is how to get my argument types to match, so that I can pass variables from one function to the other.
Decomposition is not your biggest problem here. Rather careless error checking, the use of old overweighted fscanf() and fprintf() and global variables are. Furthermore, the lack of const correctness in the input filenames, the overly long and verbose variable names and your unawareness of the += and ++ operators are just the bonus. I suppose that's why your code looks like it's bloated (and it is, in fact).
I'd rewrite the function like this:
void detab(const char *in, const char *out, int tabstop)
{
FILE *inf = fopen(in, "r");
if (!inf) return;
FILE *outf = fopen(out, "w");
if (!outf) {
fclose(inf);
return;
}
int n = 0;
int c;
while ((c = fgetc(inf)) != EOF) {
if (c == '\t') {
int pad = tabstop - n % tabstop;
for (int i = 0; i < pad; i++)
fputc(' ', outf);
n += pad;
} else if (c == '\n') {
fputc('\n', outf);
n = 0;
} else {
fputc(c, outf);
n++;
}
}
fclose(inf);
fclose(outf);
}
If you want to decompose this even further, then you may write a function taking two FILE * and the tab stop as its arguments and it shall contain the while loop only - doing that is left to you as an exercise.
Note: This answer was given to an earlier edit of the question. It has changed in the meantime, so this answer may no longer seem relevant.
Coming from an OOP background, I will focus on one single issue that is there known as Single Responsibility Principle (SRP). I argue that detab (and every other function) should do only one specific thing, but do that thing well.
But it doesn't just "detab", as its name suggests; it also has to extract its actual arguments from the command-line variables argc and argv, which were forced upon it by main:
detab(argc, argv);
main has done some validation before that, but because the command-line is then simply passed to the function, you obviously felt like continuing validation in detab (I also make some additional remarks about violating the SRP below):
void detab(int arg_list, char *array[]) // why ask for arg_list if you don't need it?
{
…
infile = fopen(array[1], "r"); // not obvious to caller that only array[1] is relevant
…
if (infile == NULL)
{
perror(array[1]);
exit(1); // should your function really have the power to terminate the program?
}
…
}
It would seem much more reasonable to concentrate all the command-line validation and value extraction logic in one place, and the detabbing in another; that is, draw clear boundaries of responsibility. Don't let logic of one function spill over into another!
To me, detab's signature should look more like e.g. this:
void detab(FILE *in, FILE *out);

Trying to simulate grep command

I am getting segmentation fault when i compile my code.
I am not getting what is wrong with my code will be happy if someone can help me.
#include<stdio.h>
#include<string.h>
int main(int argc,char *argv[])
{
FILE *fp;
char fline[100];
char *newline;
int i,count=0,occ=0;
fp=fopen(argv[1],"r");
while(fgets(fline,100,fp)!=NULL)
{
count++;
if(newline=strchr(fline,'\n'))
*newline='\0';
if(strstr(fline,argv[2])!=NULL)
{
printf("%s %d %s",argv[1],count,fline);
occ++;
}
}
printf("\n Occurence= %d",occ);
return 1;
}
See man open and man fopen:
FILE *fp;
...
fp=open(argv[1],"r");
open returns an integer, not a file pointer. Just change that line to
fp=fopen(argv[1],"r");
Note: OP edited this error out of the code in the question, for those who wonder what this is about
Which leads us to (some other minor issues addressed as well - see comments):
+EDIT: point to places where error checking should be done:
#include<stdio.h>
#include<string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
FILE *fp;
char fline[100];
char *newline;
int i, count = 0, occ = 0;
// for starters, ensure that enough arguments were passed:
if (argc < 3) {
printf("Not enough command line parameters given!\n");
return 3;
}
fp = fopen(argv[1], "r");
// fopen will return if something goes wrong. In that case errno will
// contain the error code describing the problem (could be used with
// strerror to produce a user friendly error message
if (fp == NULL) {
printf("File could not be opened, found or whatever, errno is %d\n",errno);
return 3;
}
while (fgets(fline, 100, fp) != NULL) {
count++;
if (newline = strchr(fline, '\n'))
*newline = '\0';
if (strstr(fline, argv[2]) != NULL) {
// you probably want each found line on a separate line,
// so I added \n
printf("%s %d %s\n", argv[1], count, fline);
occ++;
}
}
// it's good practice to end your last print in \n
// that way at least your command prompt stars in the left column
printf("\n Occurence= %d", occ);
return 1;
}
ps: so the error occurs during runtime and not during compile time - this distinction is quite crucial, because hunting down a compiler failure and solving a library usage error require rather different techniques...

Resources