Need help figuring out what the Problem with fgets is - c

So basically I have a file-pointer to a file that has 80 digits between 0 and 1 and I need to get them into a string to then do something with it.
The function returns NULL, and I cannot find what's wrong because if it returns NULL it just means error.
FILE *fpr = fopen(path, "r");
FILE *fpw = fopen("code.txt", "w");
char *str = calloc(81, sizeof(char));
if (fpr == NULL || fpw == NULL) {
printf("yikes");
}
if (fgets(str, 80, fpr) != NULL) { //HERE ITS NULL
int p1 = 0;
int p2 = 0;
I really thought it through and im either really dumb or there is no obvious problem.

The are a few problems in the code fragment:
if any of the files cannot be open, you still call fgets(), which has undefined behavior if fpr is NULL. Make a separate test for each FILE*, print a more explicit error message and exit the program.
you should pass the size of the array to fgets(), 81 instead of 80.
the array should be allocated to at least 82 bytes: 80 characters plus the trailing newline and a null byte terminator.
you do not test for memory allocation failure. You should not even allocate memory, a local array is OK for a small size like 82 bytes.
Here is a corrected version:
#include <errno.h>
#include <stdio.h>
...
char str[82];
FILE *fpr = fopen(path, "r");
if (fpr == NULL) {
fprintf(stderr, "cannot open input file %s: %s\n", path, strerror(errno));
exit(1);
}
FILE *fpw = fopen("code.txt", "w");
if (fpw == NULL) {
fprintf(stderr, "cannot open output file %s: %s\n", "code.txt", strerror(errno));
exit(1);
}
if (fgets(str, sizeof str, fpr)) {
int p1 = 0;
int p2 = 0;
...
Always test error conditions and print explicit error messages, you will safe yourself countless hours of debugging time.

Related

fprint doesn't work in loop

I am trying to repeatedly read a string from the command line and print it to a file. This is my code:
int main ()
{
FILE* fp=fopen("test.txt","w");
char* tofile[10];
while(1){
printf("cat: ");
scanf("%s",tofile);
fprintf(fp,"%s\n",tofile);
}
return 0;
}
It works just fine outside the loop. But inside, it just doesn't print.
The fprintf function returns the correct amount of characters it has to print.
Note: I know there's a similar question out there, but it hasn't been answered yet, and I hope my code can help in this matter since it's simpler.
Well first it doesn't seem that what you want is reading on the command line.
The command line what you write right when you execute your program such as:
./main things that are on the command line
What it seems you want to do is to read on the standard input.
What you should consider is to use the fgets function, as it has a limit of characters to be read, so that you can store them "safely" into a buffer, like your tofile.
As you want to read on the standard input you can use the stdin stream (which is a FILE* that is automatically created for every program)
The line goes
fgets(tofile, 10, stdin);
Your loop becoming :
while (fgets(tofile, 10, stdin) != NULL) {
printf("cat: ");
fprintf(fp, "%s\n", tofile);
}
meaning: as long as we can read on the standard input, print "cat :" and store what we just read in the file controlled by the stream pointer fp.
Some important stuff
When you try to open a stream it may fail and you should test it:
char filename[] = "test.txt";
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
fprintf(stderr, "Failed to open the file of name : %s", filename);
return EXIT_FAILURE;
}
Right before exiting your main, you should also close the file and check if it has succeeded, like that for example:
if (fclose(fp) != 0) {
fprintf(stderr, "Failed to close the file of name : %s", filename);
return EXIT_FAILURE;
}
The whole thing becomes:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
char filename[] = "test.txt";
FILE *fp = fopen(filename, "w");
if (fp == NULL) {
fprintf(stderr, "Failed to open the file of name : %s", filename);
return EXIT_FAILURE;
}
char tofile[10];
printf("cat: ");
while (fgets(tofile, 10, stdin) != NULL) {
printf("cat: ");
fprintf(fp, "%s\n", tofile);
}
if (fclose(fp) != 0) {
fprintf(stderr, "Failed to close the file of name : %s", filename);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Improvements
I don't know if it is just a little program or it aspires to become a greater program.
In the last case you should consider using defines and not a magical number such as
#define BUFFER_MAX_SIZE 10
char tofile[BUFFER_MAX_SIZE];
while (fgets(tofile, BUFFER_MAX_SIZE, stdin) != NULL) { ... }
This helps for readability and makes the program less apt to debug when modifying such a size. Because with the define all the part of the code needing the size will still be fully functional without modifying them.
Please also keep in mind that your tofile acts as a buffer, and it's really a small buffer that can easily be overflowed.
This will work. fgets() returns the string it reads from the specified file pointer. If this string returns only a newline ("\n"), that means nothing was entered at stdin.
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *fp = fopen("test.txt","w");
// always check if fopen() == null
if (!fp) {
fprintf(stderr, "Could not write to file\n");
return 1;
}
char tofile[30];
printf("cat: ");
while (fgets(tofile, 30, stdin)) {
if (strcmp(tofile, "\n") == 0)
break;
fprintf(fp, "%s", tofile);
printf("cat: ");
}
// always fclose()
fclose(fp);
return 0;
}
Edited code.

How to open a file using text read from a file in c

I have a file which contains the files names for every file in a directory. I am trying to open that file, read the file names from it and then open each file. However, I cannot get it to open the files. I have it printing the word it is reading and know it is reading correctly; however, it will not open the file. Any suggestions? My program is below.
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
FILE *in;
FILE *in2;
char inName[] = "inputfile.txt";
char *inName2;
inName2 = malloc(36 * sizeof (char));
char inPhrase[100];
if (( in = fopen(inName, "r")) == NULL )
{
printf("Can't open %s for reading.\n", inName);
return 2;
}
else
{
fgets(inName2, 36, in);
}
if (( in = fopen(inName2, "r")) == NULL )
{
printf("Can't open %s for reading. \n", inName2);
}
else
{
fgets(inPhrase, 100, in2);
printf("%s\n", inPhrase);
}
fclose(in);
fclose(in2);
return 0;
}
You have one outright typo and one mistake in your code. The line if (( in = fopen(inName2, "r")) == NULL ) should open in2 instead: if (( in2 = fopen(inName2, "r")) == NULL ). Your error message almost certainly reads something like this:
Can't open test_file.txt
for reading
Notice the newline that fgets always reads in for you. You should trim the line somehow. There are a few options available:
If your last line is guaranteed to be newline terminated, you can just remove the last character from each line: strchr(inName2, '\0')[-1] = '\0';.
You can trim the whitespace from the end of each line.
You can delete the last character only if it is \n (or possibly two characters, \r\n on Windows)
Final note: you should always post your error messages. If you were clever enough to interpret it properly in the first place, you would not be posting here, so don't expect us to take your word for where the program failed.
Do it this way
#include <stdio.h>
#include <stdlib.h>
int main() {
char inName[] = "inputfile.txt", * inName2;
FILE * in = fopen(inName, "r"), * in2;
char inPhrase[100];
size_t len;
// Check whether file opened correctly or display error
if (in == NULL) { perror(inName); return 1; }
// Read file line by line
while (getline(&inName2, &len, in) != -1) {
// Check if file opens otherwise go to next file
if ((in2 = fopen(inName2, "r")) == NULL) { perror(inName2); continue; }
// Read 100 chars from each file and display
fgets(inPhrase, 100, in2);
printf("%s\n", inPhrase);
fclose(in2);
}
fclose(in);
return 0;
}

How do I remove SEGFAULT here?

I created a function to print the contents of a file:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
where file is a global variable. GDB gives output as follows:
_IO_getc (fp=0x0) at getc.c:39
39 getc.c: No such file or directory.
(gdb) bt
#0 _IO_getc (fp=0x0) at getc.c:39
#1 0x000000000040075e in readFile ()
#2 0x00000000004006d4 in main ()
However, the file is present and I get the SEGFAULT after printing the contents of the file. It might be because the buffer here (c) is small but I am not sure. Also, I don't know how do I fix this even if that were the case. Can anyone suggest how do I proceed?
EDIT
I call the readFile function only once. Here is my calling function:
int main(int argc, char* argv[])
{
char * filename;
filename = argv[1];
readFile(filename);
printf("File Handler: %ld", (long)file);
fclose(file);
return 0;
}
You're passing in a filename that doesn't exist or for some other reason cannot be opened. Get rid of the segfault by checking for errors (you'll need to #include <errno.h> and <string.h> too for this:
void readFile(char* filename)
{
int c ;
file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file '%s' : %s\n", filename, strerror(errno));
return;
}
printf("The contents of the file are:\n");
while((c = fgetc(file)) != EOF)
{
printf("%c", c);
}
return;
}
Most likely your file is NULL and you are still trying to read it.
I simulated this behaviour (SEG fault) when I deleted this file.
If file exists then your code works fine.
Check what path you are passing.. If you are using single \ try with \\ and see if this works. First \ will work as escape sequence and final path will be send as D:\temp\use.dat to fopen.
readFile("D:\\temp\\user.dat");
Before you do anything with a file, you must ensure that you opened it successfully. This is done by checking that the file pointer received by calling fopen is not NULL.
Once you do this, you read using whatever function you choose until it returns a value that indicates failure to read — a NULL pointer for fgets, 0 or EOF for fscanf, or EOF for fgetc.
In any case, you challenge these return values in two ways. The first way is to check for read errors using ferror. The other way is to check whether the end of the file was reached using feof.
A complete program that should work, based upon your code:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
enum { OPEN_ERROR = 1, READ_ERROR };
enum { PARAM_EXIT = 1, OPEN_EXIT, READ_EXIT };
FILE *file = NULL;
int readFile(char* filename)
{
int c;
file = fopen(filename, "r");
if (file == NULL)
return OPEN_ERROR;
printf("The contents of file '%s' are:\n", filename);
while((c = fgetc(file)) != EOF)
printf("%c", c);
/*
* fgetc returns EOF on end of file and when an error occurs.
* feof is used to determine whether the end of the file was reached.
* Otherwise, we encountered a read error.
*/
if (feof(file))
c = 0;
else
c = READ_ERROR;
return c;
}
int main(int argc, char *argv[])
{
int status = 0;
if (argc == 1) {
fprintf(stderr, "usage: %s file\n", argv[0]);
return PARAM_ERROR;
}
/* Check that <program ""> wasn't used... */
if (argv[1][0] == '\0') {
fprintf(stderr, "error: empty filename detected, exiting. . .\n");
return PARAM_ERROR;
}
switch (readFile(argv[1])) {
case 0:
break;
case OPEN_ERROR:
fprintf(stderr, "error: file open failed - %s\n", strerror(errno));
status = OPEN_EXIT;
break;
case READ_ERROR:
fprintf(stderr, "error: file read failed - %s\n", strerror(errno));
status = READ_EXIT;
break;
default:
fprintf(stderr, "error: unknown error occurred, aborting...\n");
abort();
}
if (file != NULL)
fclose(file);
return status;
}
Of course, normally you would close the file in the same function in which it was opened (e.g. something like filep = openFile(...); readFile(filep); fclose(filep);, except error handling would be used of course).
I am completely changing my answer
Actually, the file that I was reading was open in gedit (which might explain why I was getting "NULL" even after printing the file contents. I closed the file and removed my NULL comparison code and it works perfectly fine.
Ok, from everybody's comments I got to know that you basically get a SEGFAULT when you read the contents of file that has NULL contents. I just made a simple fix in my while loop:
while((c != EOF))
{
printf("%c", c);
c = fgetc(file);
if(c == NULL)
break;
}
Problemo solved! (Although, the compiler gives me a warning of "comparison between pointer and integer".)

Looking for a string of characters copied to a buffer

I have an assignment that has asked me to copy a file using buffered i/o. It has multiple requirements:
Take one parameter and an optional second
Open the first parameter for reading
Open the second for writing
If there is no second parameter make a new file called prog1.out
Use a buffer size of 20 bytes
When copying the file, print any buffer starting with the characters "rwxr"
close all opened files before exiting.
The problem I'm having is with number six, I've looked around and can't figure this out. I've tried memchr but I don't think I'm on the right track. If anyone can help push me in the right direction I'd be grateful.
This is my code:
# include <stdlib.h>
# include <stdio.h>
int main(int argc, char *argv[])
{
FILE *readfile, *writefile;
char buffer[1024];
int fileSize;
int readResult;
int writeResult;
// making sure arguments exist
if (argc < 2|| argc > 3){
printf("This program takes either 1 or 2 arguments.\n");
exit(1);
}
//Opening file for reading
readfile = fopen(argv[1], "r");
if (!readfile) {
printf("Unable to open file %s.\n", argv[1]);
exit(1);
}
//finding the file size
fseek (readfile, 0, SEEK_END);
fileSize = ftell (readfile);
fseek (readfile, 0, SEEK_SET);
// read the file
readResult = fread(buffer, 20, fileSize/20, readfile);
if (readResult == 0) {
printf("A read error occured.\n");
exit(1);
}
//check to see if there is a second parameter (argument)
if (argc == 3) {
writefile = fopen(argv[2], "w");
if (!writefile) {
printf("Unable to open file %s.\n", argv[2]);
exit(1);
}
writeResult = fwrite(buffer, 20, fileSize/20, writefile);
if (writeResult != readResult) {
printf("A write error occured.\n");
exit(1);
}
printf("File %s successfully copied to %s.\n", argv[1], argv[2]);
}
else {
writefile = fopen("program1.out", "w");
if (!writefile) {
printf("Unable to open file program1.out\n");
exit(1);
}
writeResult = fwrite(buffer, 20, fileSize/20, writefile);
if (writeResult != readResult) {
printf("A write error occured.\n");
exit(1);
}
printf("File %s successfully copied to %s.\n", argv[1], "program1.out
}
fclose(readfile);
fclose(writefile);
exit(0);
}
There's the naive way:
if(buffer[0] == 'r' && buffer[1] == 'w'
&& buffer[2] == 'x' && buffer[3] == 'r') {
//do something
}
But take a look at strncmp(), which you can use for comparing parts of a string.
remember to first check if you have read at least 4 chars into the buffer. e.g. if the file is 21 bytes long, your 2. fread might only read 1 character, and you shouldn't compare against the other 3 chars in the buffer.
If you print out the buffer with e.g. printf or puts or any other function that expects a string, the buffer needs to end with a '\0' byte, otherwise the string functions doesn't know when to stop.
I'll first answer the question you actually asked: memcmp is a good way to compare two buffers. Some caveats:
You also have to make sure the size of the buffer is at least as large as the size of the target string
memcmp returns 0 if the two buffers match, which can be counter-intuitive.
So for example, if you wanted to see if a buffer is equal to the string "rwxw", you could write
if (readresult >= strlen("rwxw") && !memcmp(buffer, "rwxw", strlen("rwxw"))) {
// buffer match occurred!
}
Personally I would use a "#define" or const char to ensure that the three places where that string appear are actually the same string. For example:
#define MATCH_STRING "rwxw"
if (readresult >= strlen(MATCH_STRING) && !memcmp(buffer, MATCH_STRING, strlen(MATCH_STRING))) {
// buffer match occurred!
}
However there are a couple of other problems with your code. One is that you need a loop that continually reads from the input file and write from the output file until the input is exhausted. For example, along the lines of
while (true) {
readResult = fread(buffer, 20, 1, readfile);
if (readResult == 0) {
// end of file
break;
}
// put your check for the "rwxr" string here!
writeResult = fwrite(buffer, readResult, 1, writefile);
if (writeResult != readREsult) {
printf("error\n");
}
}
Finally, you have what might be called a "stylistic" bug. There are two cases in your program: a specified filename and a default filename. Those two cases share a lot of code in common, but you did a cut and paste. This makes the code harder to understand, and more prone to bugs if it's changed in the future. If you are cutting-and-pasting code you're doing something wrong! Consider instead something like this, which maximizes shared code paths:
char *outFileName;
if (argc == 3) {
outFileName = argv[2];
} else {
outFileName = "prog1.out";
}
writefile = fopen(outFileName, "w");
if (!writefile) {
printf("Unable to open file %s.\n", writeFileName);
exit(1);
}

fgets in C doesn't return a portion of an string

I'm totally new in C, and I'm trying to do a little application that searches for a string in a file. My problem is that I need to open a big file (more than 1GB) with just one line inside and fgets return me the entire file (I'm doing test with a 10KB file).
Actually this is my code:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *search = argv[argc-1];
int retro = strlen(search);
int pun = 0;
int sortida;
int limit = 10;
char ara[20];
FILE *fp;
if ((fp = fopen ("SEARCHFILE", "r")) == NULL){
sortida = -1;
exit (1);
}
while(!feof(fp)){
if (fgets(ara, 20, fp) == NULL){
break;
}
//this must be a 20 bytes line, but it gets the entyre 10Kb file
printf("%s",ara);
}
sortida = 1;
if(fclose(fp) != 0){
sortida = -2;
exit (1);
}
return 0;
}
What can I do to find an string into a file?
I've tried with GREP but it don't helps, because it returns the position:ENTIRE_STRING.
I'm open to ideas.
Try
printf("%s\n",ara);
Also consider initializing variables before you use them:
char ara[20]={0x0};
You only allocated 20 bytes for the input buffer, but told the fgets to read 20 bytes.
Make this change:
if (fgets(ara, sizeof(ara)-1, fp) == NULL){
remember, if you want 20 characters PLUS the trailing '\0' that marks the end of the string you have to allocate 21 bytes.

Resources