I got Segmentation Fault error when I make cat -b function - c

I want to make 'cat -b' function.
This result is perfect when meet last step.
I got Segmant Fault error and I don't know how to fix it.
How can I do?
FILE *file_name = NULL;
file_name = fopen(av[2], "r");
char temp[1024], *str;
int cnt_file_number = 1;
while(!feof(file_name)){
printf("%4.d ", cnt_file_number++);
str = fgets( temp, sizeof(temp), file_name);
if(strcmp(str, "\0") == 0 ) break;
printf("%s", str);
}
fclose(file_name);

fgets returns a null pointer if it encounters an error.
You are using str right away without checking it.
A better way would be something like
while(fgets(temp, sizeof(temp), file_name) {
// your printing code but using temp instead of str
}
Since fgets returns either temp or null you don't need that extra str pointer and if it is null due to EOF the loop will terminate properly.
Also, checking feof in your loop condition won't do the job because several characters are read at once and EOF might not be the next char but among the next few chars.
Edit: oh sorry. I misread. You are actually checking if str is empty but as others pointed out in the comments there is a better way to do this. Maybe this even solves the problem.

Aside from the fact that your program does not reflect the description of what "cat -b" would do, we do not know what av[2] is; so, no telling whether that file exists or is readable. It'd be wise to check fopen() to ensure that it opens a valid file. If it is not, then it returns NULL and feof(NULL) will fail.
Also, if you read past the end of file, str == NULL and strcmp(NULL,...) will fail.

Related

Using Fgets in two ways

I looked through some "FGETS" questions before posting, and what i gathered is it may be a new line character thats causing the issue for the manual input.
int main ( int argc, char *argv[] ){
char temp[1000];
FILE *user_file;
printf("Starting....\n"); //Used for user visual.
if(argc == 2){ //open file
user_file = fopen(argv[1],"r");
if( user_file == NULL ){
printf("No file was found.");
exit(2);
}else{
fgets(temp,strlen(temp),user_file);
}
}else if( argc > 2 ){ // Will exit if arguments are greater than 2.
printf("Maximum args 2.\n");
exit(1);
}else{
printf("File was not provided, please enter the text to convert.\n"); //If the user doesnt provide a file allow manual input.
fgets(temp,strlen(temp),stdin);
}
printf("%s\n",temp);
return 0;
}//End main
Questions:
Why is fgets not opening the txt file I provide it with on the cmd line, and storing it to the temp array?
Why is Fgets being skipped over in the "else" statment if the file is not provided?
Why is print being skipped over in both instances?
Hey and by the way thank you very much for the assistance.
If you know a similar question that has been asked, can you post it in the comments so I can read it.
Your code has multiple problems.
Here's the first problem:
char temp[1000];
Your buffer declaration does not initialize the buffer's contents - so the value of each char value will be whatever was in the raw memory previously. In C most strings are "null-terminated" so having a terminating NULL (0 - zero) is important otherwise you can run into buffer-overruns.
The "best" approach is to zero-out (zero-initialize) the array/buffer before you use it, like so (in C99):
char temp[1000] = {0};
...this way temp will contain all 0 values (NULL) so anything written to it (provided it's no longer than 999 bytes) will automatically have a null-terminator (though fgets will append a terminating 0 value, but not every function in C does this).
The second problem is related to the first: you're using the runtime string-length function strlen to get the size of the strlen buffer. This is incorrect as the buffer sized is fixed at compile-time to 1000. The strlen will return the index of the first 0 (NULL) char value, which is undefined behavior at this point because you haven't zero-initialized the buffer anyway (so it could return 0 immediately if the buffer's original raw data contained a zero, or it could overrun 1000 because there was never any zero value.
...thus you need to re-use the buffer-length, like so:
#define TEMP_LENGTH 1000
char temp[ TEMP_LENGTH ];
...
fgets( temp, TEMP_LENGTH, user_file );
Finally, you're making the same mistake when you call fgets( temp, ..., stdin ).
The array temp[] is uninitialized, and you attempt to find strlen(temp). You don't even know if there is a NUL stored in the array. Try doing:
#define MAXLINE 1000
and changing your calls to fgets():
fgets(temp, MAXLINE, user_file);
...
fgets(temp, MAXLINE, stdin);
Here problem is in your code, instead of passed numerical value in second argument you passed strlen(temp).
fgets(temp,strlen(temp),user_file);
right way is :-
fgets(temp,1000,user_file);

Reading from file into array, line by line

I am trying to read from a file in C. My code is the following. It seems to read everything fine into the array, but when I try to print it, I get the error Segmentation fault (core dumped)
FILE *fp;
char * text[7][100];
int i=0;
fp = fopen("userList.txt", "r");
//Read over file contents until either EOF is reached or maximum characters is read and store in character array
while(fgets((*text)[i++],100,fp) != NULL) ;
printf("%s", &text[0]);
fclose(fp);
Can someone point me in the right direction?
I have tried reading and copying solutions from other similar cases, but they are extremely specific to the user.
So part one, you don't need a pointer to a char[][]:
char text[7][100];
Part 2, just deference your array of strings like a normal person, nothing fancy here:
while(fgets((text)[i++],100,fp) != NULL) ;
Live example: http://ideone.com/MADAAs
Some things to watch out for:
If your input file has more than 7 lines you are going to have problems.
Why is “while ( !feof (file) )” always wrong?
char * text[7][100]; //wrong - this is 2 diminutions array of char pointers, replace it with
char text[7][100];
while(fgets((*text)[i++],100,fp) != NULL) ; // replace this with
while(fgets(&text[i++][0],100,fp) != NULL) ;
NOTE: this code will work in the current scope of the function (on the stack) if you need to use it outside the scope of current scope , allocate some memory on the heap and use the pointers of the heap.

code immediately stops responding (c, pointers, file I/O)

I'm writing a code for homework that uses functions and pointers to read a file and fix the capitalization errors in it.
The goal is to read a pre-written file and fix it, adding line numbers to the beginning of each line. (i.e., tiTle -> 1. Title)
I think I've got the basic logic down, but there must be a bug that I'm not seeing, because it stops responding immediately after I compile and run it.
Here's my main() function.
FILE *casefixer;
casefixer = fopen("casefixer.txt", "r+");
char* ch;
int* char_in_word;
int* line_num;
*char_in_word = 0;
*line_num = 1;
while((fscanf(casefixer, "%c", ch)) != EOF){
fscanf(casefixer, "%c", ch);
fprintf(casefixer, "%d. ", *line_num);
if(fix_caps(ch, char_in_word, line_num))
fprintf(casefixer, "\n");
fix_caps(ch, char_in_word, line_num);
fprintf(casefixer, "%c", *ch);
}
fclose(casefixer);
char* ch; // uninitialized
int* char_in_word; // -||-
int* line_num; // -||-
*char_in_word = 0; // dereferencing uninitialized pointer - undefined behavior
*line_num = 1; // -||-
You don't have to use pointers when you see them in function declaration. If you're sure the function won't store them or try to allocate new memory for them, take an address of a regular variable:
char ch;
fscanf(casefixer, "%c", &ch) // ch is on stack longer than fscanf, everything's OK
By using "%c" you can only read a single character instead of a line. I recommend you use fgets here.
The call of fscanf in the loop should be deleted since you've already called that in the while((fscanf(casefixer, "%c", ch)) != EOF).
Writing while reading is not easy, especially when you want to rewrite what you've read before. You need to reposition your stream position indicator. So I think the better way should be you store your new file into a buffer and then write the buffer into the file.
In this two lines:
if(fix_caps(ch, char_in_word, line_num))
fprintf(casefixer, "\n");
If I understand it right, you should use "continue" in this if statement.
In your code, the variable line_num is always 1. You should do the increment at the end of loop.

strtok not going through all tokens

I'm trying to implement a shell as part of a school assignment, and I'm stuck on the file input/output redirection part.
More specifically, I've come up with a function which allows me to detect whether or not the command entered in specifies a '>' or '<' or even a '|'.
Ideally, if I enter ls -a > ls.tx', then the tokens ls -a and ls.txt should be returned.
My code doesn't do this, it only returns ls -a then stops.
My code is below:
/*commandLine is a char* taken in from the user, and is a null-terminated string */
int counter = 0;
parsedLine = strtok(commandLine, ">");
while (parsedLine != NULL)
{
if (counter == 0)
{
strncpy(parsedCpy, parsedLine, strlen(parsedLine));
parseCommand(parsedCpy, commands);
counter++;
}
else
{
redirect->re_stdout = parsedLine;
}
parsedLine = strtok(NULL, ">");
}
I've tried it in another test file just to see if there was something wrong, but this test file (code below) returns the expected result (that is, ls -a and ls.txt)
char myString[] = "ls -a > ls.txt";
char* parsed;
parsed = strtok(myString, ">");
while (parsed != NULL)
{
printf("%s\n", parsed);
parsed = strtok(NULL, ">");
}
Is there something that I'm just not understanding? I don't really see where I'm going wrong, since the code itself is nearly the same in both cases.
Note that strncpy won't zero terminate a string unless the zero termination is part of the source being copied. See man strncpy. It says:
Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
That could be horsing something else up depending upon what parseCommand does.
In this case, you should just do a strcpy. A strncpy doesn't really do anything for you if you're giving it the length of the source string, unless you're intentionally trying to avoid copying the null terminator. So you should use, strcpy(parsedCpy, parsedLine);.
I cannot see how parsedLine is declared, but it needs to be handled explicitly and carefully. i.e. make sure the pointer to that value is not changed except by strtok(), and make sure that it remains null terminated. One thing I do when using strtok() for multiple calls, is to use an intermediate value to collect results, helping to keep the target buffer pure and unchanged except by strtok()
A small code snippet to illustrate:
char a[] = {"ls -a > ls.tx"};
char *buff;
char keep[80];
buff = strtok(a, ">");
strcpy(keep, buff);
buff = strtok(NULL, ">");
strcat(keep, buff);
This usage of strtok() is clean, i.e. it does not allow buff to be affected except by another call to strtok()
By comparison, this section of your code is a little scary because I do not know the output of the strncpy() which depends so heavily on the third argument, and can corrupt (place unexpected results into) parseCommand :
if (counter == 0)
{
strncpy(parsedCpy, parsedLine, strlen(parsedLine));
parseCommand(parsedCpy, commands);
counter++;
}
else
{
redirect->re_stdout = parsedLine;
}
parsedLine = strtok(NULL, ">");
Along the lines of keeping the target buffer pure, (even though it does not appear to be an issue here), strtok() is not thread safe. If a function using strtok() is used in a multi threaded process, the target buffer is subject to any number of calls, resulting in unexpected, and perhaps even undefined behavior. In this case using strtok_r() is a better option

Find and Replace in a C File

The Problem was to find and replace a string in a C File.
I am new to C Files. I have tried the following code but I didnt get any output:
#include<stdio.h>
#include<string.h>
int main()
{
FILE *f1,*f2;
char *src,*dest,*s1,ch,ch1,ch2,ch3;
int i;
f1=fopen("input.txt","rw");
f2=fopen("dummy.txt","rw");
src="mor";
dest="even";
while(ch!=EOF)
{
ch=fgetc(f1);
if(ch==src[0]) //Finding 1st char of src
{
fgets(s1,strlen(src),f1);
if(strcmp(src+1,s1)==0) //Finding occurance of "src" in file
{
fseek(f1,strlen(src)-1,SEEK_CUR);
while(ch1!=EOF) //Copying remaining data into another file
{
ch1=fgetc(f1);
fputc(ch1,f2);
}
fseek(f1,-strlen(src),SEEK_CUR);
for(i=0;i<strlen(dest);i++) //replacing "src" with "dest"
{
ch2=dest[i];
fputc(ch2,f1);
}
fclose(f1);
f1=fopen("input.txt","a");
while(ch3!=EOF) //Appending previosly copied data into 1st file
{
ch3=fgetc(f2);
fputc(ch3,f1);
}
}
}
}
fclose(f1);
fclose(f2);
}
The Contents of input.txt is "morning".
Kindly point the ERROR in the logic and also give an efficient code for the same.
Thanks in Advance.
Reading files in C is usually a bit messy. The first problem that I see is the way ch is used in the main loop. The first time
while (ch != EOF)
is executed, ch is uninitialized, and if it happens to hold EOF, the main loop will not execute at all. I usually use the following structure for reading from files:
FILE *fInput = fopen("input.txt", "r");
int ch; /* need an int to hold EOF */
for (;;)
{
ch = fgetc(fInput);
if (ch == EOF) break;
...
}
In addition, you may need to read up on file pointer concept. For example, after reading the remainder of src, you fseek() forward, and skip some more characters before you copy data to f2. Essentially, you read m, read or (with fgets() - and into an unallocated buffer s1 that would go ka-boom on you some time in the near future), skip 2 more characters (now your pointer is at last n of "morning"), copy "ng" into f2, try to write EOF to f2 in this loop (hence the above pattern for reading until EOF), seek two characters back (which may fail once you reach EOF, my C file functions are a bit rusty these days), write "even" to f1 (which should, if I am wrong about seek after EOF, set input file to "mornieven", and not change it if I am correct). In summary, I don't think the code does what you intend it to do.
I would recommend building up your function. Each one of the following can be written as a program that you should test and finish before going to next step:
read the file safely, and print it out
detect the contents of src, and print the rest of input
save the rest of the input to second file instead of printing
replace src with dest in first file, and ignore the rest (since you open input file with 'rw', this will truncate the rest of input). You may need to do an fseek() to clear the EOF status. Also look at ftell() to record a position that you can jump back to using fseek()
finally, copy in everything you have saved to second file after replacing src with dest (no need to close f1 here. But it is better to open f2 as write, close after copy from first file, and reopen as read to perform the copy back to f1).
In addition, when you need a buffer (such as s1), just use a large enough array for now, but look into malloc() and free() functions to perform dynamic memory allocations for situations like these.
One simple way to do the replace would be to first read in the whole file into a buffer
e.g.
FILE* fpIn = fopen("file.txt","rb");
fseek(fpIn, 0L, SEEK_END);
size_t s = ftell(fpIn);
fseek(fpIn, 0L, SEEK_SET);
void* buf = malloc(s);
fread(buf,s,1,fpIn);
now while writing the file, check for your string
char src[] = "mor";
char dest[] = "even";
int lenSrc = strlen(src);
int lenDest = strlen(dest);
for (char* ch = buf; ch < buf + s; ++ch)
{
if ( !memcmp( ch, src, lenSrc ) )
{
fwrite( dest, 1,lenDest, fpOut );
ch += lenSrc;
}
else
{
fputc( *ch, fp );
}
}
disclaimer: haven't compiled this
You are printing the wrong thing in your output. Print, "ch", not the file pointer.
while(ch!=EOF)
{
ch=getc(f1);
printf("%c",ch);
}
while(ch!=EOF)
{
ch=getc(f2);
printf("%c",ch);
}
Also, f2 is closed at the end during your output. You'll have to reopen it (just like you do with f1.)
At first glance, I see that your code to call fgets is wrong. You have not allocated any memory and you are reading a string into an uninitialized pointer. Read into an array or dynamically allocated memory.
Another problem is that you are declaring ch as char. fgetc() returns an int, and for good reason. It is good to be able to return any possible character or EOF, so EOF shouldn't be a character, so ideally fgetc() returns a bigger type than char.
The upshot is that the loop may well never end, since ch can't possibly hold EOF on some standard implementation. Declare it (and ch1 and ch3) as int.

Resources