Basic C Questions. fprintf and fgets failures - c

I've got some basic c questions that are driving me insane. Let me post my code, and I'll tell you about what's going wrong.
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
static int GetLine();
int main() {
char* sourceFile;
char* destinationFile;
int error, bytesRead;
char* sourceFD;
char* destinationFD;
char buffer[100];
error = GetLine("Please enter a source file name: \n", sourceFile, 100);
if (error == 1) {
printf("A source file was not inputted.\n");
return 0;
}
else if (error == 2) {
printf("Source file is too long.\n");
return 0;
}
error = GetLine("Please enter a destination file name: \n", destinationFile, 100);
if (error == 1) {
printf("A destination file was not inputted.\n");
return 0;
}
else if (error == 2) {
printf("Destination file is too long.\n");
return 0;
}
}
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int GetLine (char *prmpt, char *buff, unsigned int sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf("%s", prmpt);
fflush(stdout);
}
}
if (fgets (buff, sz, stdin) == NULL) {
fprintf(stderr, "fgets returned NULL");
return NO_INPUT;
}
printf("logging input: %s", buff);
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
The errors are occurring in the the GetLine function, which was largely provided by another StackOverflow post. Here are my issues.
No matter what I do, I cannot get debug print statements to work properly. basic printf will often fail. Calling fflush(stdout) immediately after does not help, nor does setbuf(stdout, NULL). Right now I am trying fprintf(stderr), also to no avail. The LOC that continually fails (regardless of the method I try) is fprintf(stderr, "fgets returned NULL"). Note that the application still gives me the error that "A source file was not inputted." It doesn't matter if I target stdout or stderr.
fgets is returning NULL every time. I have no idea why. No, the input I'm providing is not large.
EDIT: I just noticed the missing brackets on that if statement (the fgets one). let me see what that fixes.

if (fgets (buff, sz, stdin) == NULL)
fprintf(stderr, "fgets returned NULL");
return NO_INPUT;
Here return NO_INPUT; is always executed no matter what fgets() returns. Use {} to enclose the two statements.

if (prmpt != NULL) {
printf("%s", prmpt);
fflush(stdout);
}
}
Here you are closing GetLine but your code continues

Related

using EOF instead of feof

#include <stdio.h>
int main() {
FILE *fp1, *fp2, *fp3;
int n, i, num, flag = 0;
/* open files to write even, odd seperately */
fp1 = fopen("data.txt", "r");
fp2 = fopen("even.txt", "w");
fp3 = fopen("odd.txt", "w");
fprintf(fp2, "Even Numbers:\n");
fprintf(fp3, "Odd Numbers:\n");
/* print even, odd and prime numbers in separate files */
while (!feof(fp1)) {
fscanf(fp1, "%d", &num);
if (num % 2 == 0) {
fprintf(fp2, "%d ", num);
} else {
if (num > 1) {
for (i = 2; i < num; i++) {
if (num % i == 0) {
flag = 1;
break;
}
}
}
fprintf(fp3, "%d ", num);
flag = 0;
}
}
fprintf(fp2, "\n");
fprintf(fp3, "\n");
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}
I want to use EOF instead of feof. I have tried !EOF = fp1 but it doesn't work and gives an error. I just want to replace feof with EOF. can anyone indicate what is the problem in my code?
fscanf returns EOF when the end-of-file is reached:
man fscanf
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
[...]
The scanf() function reads input from the standard input stream stdin, fscanf() reads input from the stream pointer stream, and
sscanf() reads its input from the character string pointed to by str.
[...]
RETURN VALUE
On success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or
even zero, in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set
to indicate the error.
A solution would be to read save the return value of fscanf in a int
variable and check it agains 0 and EOF, like this:
If you want to keep using fscanf:
int ret;
while((ret = fscanf(fp1, "%d, &num)) != EOF)
{
if(ret == 0)
{
// fscanf failed to convert the input
// let it consume a charatcer and try again.
getc(fp1);
continue;
}
if(num % 2 == 0)
...
}
edit
Avoid using feof to control looping on a file like this while(!feof(fp), see Why is “while ( !feof (file) )” always wrong? for more
information about that.
edit 2
This was my original idea, but as Jonathan Leffler pointed out in the comments:
Jonathan Leffler wrote:
Your first solution demands a single number per line, which the code in the question does not
He's right, I didn't see that.
me from the past
One option would be to read the input line by line using fgets and then use
sscanf to parse the line:
char buffer[1024];
while(fgets(buffer, sizeof buffer, fp1))
{
if(sscanf(buffer, "%d", &num) != 1)
{
fprintf(stderr, "Could not read an integer, ignoring line\n");
continue;
}
if (num % 2 == 0)
...
}
Your condition for the while loop should be the fscanf() statement itself. EOF is always an integer. See the manual page for fscanf():
Return Value
The fscanf() function returns the number of fields that it successfully converted and assigned. The return value does not include fields that the fscanf() function read but did not assign.
The return value is EOF if an input failure occurs before any conversion, or the number of input items assigned if successful.
And, like everyone else I will refer you to Why is while ( !feof (file) ) always wrong?. This is essential reading on Stack Overflow for new C programmers.
#include <stdio.h>
int main(void) {
FILE *fp1, *fp2, *fp3;
int n, i, num, flag = 0, ret;
/* fopen files */
while ((ret = fscanf(fp1, "%d", &num)) != EOF) {
if (ret == 0) {
getc(fp1);
continue;
}
if (num % 2 == 0) {
fprintf(fp2, "%d ", num);
}
/* rest of the loop here */
}
/* fclose files */
}
If fscanf() fails to read a character, but does not return EOF, it can often solve things to getc(), to advance the buffer by one character. This method also works when using getchar() to advance stdin, after getting user input from scanf().

Reading and writing to a file at the same time in C

Supposed to swap every two lines in a file until just one line remains or all lines are exhausted. I don't want to use another file in doing so.
Here's my code:
#include <stdio.h>
int main() {
FILE *fp = fopen("this.txt", "r+");
int i = 0;
char line1[100], line2[100];
fpos_t pos;
fgetpos(fp, &pos);
//to get the total line count
while (!feof(fp)) {
fgets(line1, 100, fp);
i++;
}
i /= 2; //no. of times to run the loop
rewind(fp);
while (i-- > 0) { //trying to use !feof(fp) condition to break the loop results in an infinite loop
fgets(line1, 100, fp);
fgets(line2, 100, fp);
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fgetpos(fp, &pos);
}
fclose(fp);
return 0;
}
content in this.txt:
aaa
b
cc
ddd
ee
ffff
gg
hhhh
i
jj
content after running the program
b
aaa
ddd
cc
ddd
c
c
c
i
jj
I've even tried using fseek in place of fgetpos just to get the same wrong result.
From what I figured, after the second while loop has run two times (i.e the first four lines have been processed), the cursor is rightfully at 17th byte where it is supposed to be (as returned by the call to ftell(fp)) and even the file contents after the 4th line are unchanged and somehow for some reason when fgets is called when the loop is running for the third time, the contents read into arrays line1 and line2 are "c\n" and "ddd\n" respectively.
AGAIN, I don't want to use another file to accomplish this, I just need to figure out what exactly is going wrong behind the screen
Any leads would be appreciated. Thank you.
There are multiple problems in your code:
You do not check if fopen() succeeds, risking undefined behavior.
The loop to determine the total number of lines is incorrect.Learn why here: Why is “while ( !feof (file) )” always wrong?
You do not actually need to compute the total number of lines.
You should call fflush() to write the contents back to the file before changing from writing back to reading.
The C Standard specifies this restriction for files open in update mode:
7.21.5.3 The fopen function
[...] output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
This explains why just reading the file position after writing the lines in reverse order causes problems. Calling fflush() should solve this issue.
Here is a corrected version:
#include <stdio.h>
int main(void) {
FILE *fp;
char line1[100], line2[100];
fpos_t pos;
fp = fopen("this.txt", "r+");
if (fp == NULL) {
fprintf(stderr, "cannot open this.txt\n");
return 1;
}
while (fgetpos(fp, &pos) == 0 &&
fgets(line1, sizeof line1, fp) != NULL &&
fgets(line2, sizeof line2, fp) != NULL) {
fsetpos(fp, &pos);
fputs(line2, fp);
fputs(line1, fp);
fflush(fp);
}
fclose(fp);
return 0;
}
The buffer may not necessarily be flushed when changing the current position of the file. So it must be explicitly flushed.
E.g Use fflush(fp);
Change
fputs(line2,fp);
fputs(line1,fp);
to
fputs(line2,fp);
fputs(line1,fp);
fflush(fp);
Why not use two file pointers, both pointing to the same file, one to read and one to write? No need to keep track of the file position, no need to seek around, no need to flush then.
This approach spares you a lot of complicated stuff. Those unnecessary efforts are better invested in some sophisticated error checking/logging like below ;-):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
int result = EXIT_SUCCESS;
size_t blocks = 0;
int l1_done = 0;
int l2_done = 0;
FILE *fpin = fopen("this.txt", "r");
FILE *fpout = fopen("this.txt", "r+");
if (NULL == fpin)
{
result = EXIT_FAILURE;
perror("fopen() to for reading failed");
}
if (NULL == fpout)
{
result = EXIT_FAILURE;
perror("fopen() for writing failed");
}
while (EXIT_SUCCESS == result && !l1_done && !l2_done)
{
result = EXIT_FAILURE;
char line1[100];
char line2[100];
if ((l1_done = (NULL == fgets(line1, sizeof line1, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks);
break;
}
}
if ((l2_done = (NULL == fgets(line2, sizeof line2, fpin))))
{
if (ferror(fpin))
{
fprintf(stderr, "Reading line %zu failed.\n", 2*blocks + 1);
break;
}
}
{
size_t len = strlen(line1);
if (((sizeof line1 - 1) == len) && ('\n' != line1[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks);
break;
}
}
{
size_t len = strlen(line2);
if (((sizeof line2 - 1) == len) && ('\n' != line2[len]))
{
fprintf(stderr, "Line %zu too long or new-line missing.\n", 2*blocks + 1);
break;
}
}
if (!l2_done)
{
if (EOF == fputs(line2, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks + 1, 2*blocks);
break;
}
}
if (!l1_done)
{
if (EOF == fputs(line1, fpout))
{
fprintf(stderr, "Writing line %zu as line %zu failed.\n", 2*blocks, 2*blocks + 1);
break;
}
}
++blocks;
result = EXIT_SUCCESS;
}
if (EXIT_SUCCESS == result && !ll_done && l2_done)
{
fprintf(stderr, "Odd number of lines.\n");
}
fclose(fpin); /* Perhaps add error checking here as well ... */
fclose(fpout); /* Perhaps add error checking here as well ... */
return result;
}

Segmentation fault (core dumped) due to fgets - I think

but I keep getting this error when I run this program. I think it's because of the fgets function. I tried initializing the input variable to NULL to see if that'll help, but it didn't. I also have a hunch that I might need to malloc to solve the problem. But your help is highly appreciated.
int main(int argc, char* argv[])
{
char* input = NULL;
// ensure one and only one command line argument
if (argc != 2)
{
printf("Usage: %s [name of document]\n", argv[0]);
return 1;
}
// open a new document for writing
FILE* fp = fopen(argv[1], "w");
// check for successful open
if(fp == NULL)
{
printf("Could not create %s\n", argv[1]);
return 2;
}
// get text from user and save to file
while(true)
{
// get text from user
printf("Enter a new line of text (or \"quit\"):\n");
fgets(input, 50, stdin);
// if user wants to quit
if (input != NULL && strcmp(input, "quit") == 0)
{
free(input);
break;
}
// if user wants to enter text
else if (input != NULL)
{
fputs(input, fp);
fputs("\n", fp);
printf("CHA-CHING!\n\n");
free(input);
}
}
// close the file and end successfuly
fclose(fp);
return 0;
}
You never malloc-ed input, so yeah, fgets is dereferencing the NULL pointer as its buffer, and that's going to die. Either change input to a stack array (and remove the free for it) or actually call malloc to allocate memory so input isn't pointing to NULL.
Their are some problems in your code.
You have not allocated memory to input character pointer. Hence you can't store characters in it, hence you get segmentation fault.
Also you are freeing more than once, which is incorrect.
So, a code, with the above modification would be something like this:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* input = malloc(sizeof(char) * 50);
// ensure one and only one command line argument
if (argc != 2)
{
printf("Usage: %s [name of document]\n", argv[0]);
return 1;
}
// open a new document for writing
FILE* fp = fopen(argv[1], "w");
// check for successful open
if(fp == NULL)
{
printf("Could not create %s\n", argv[1]);
return 2;
}
// get text from user and save to file
while(1)
{
// get text from user
printf("Enter a new line of text (or \"quit\"):\n");
fgets(input, 50, stdin);
// if user wants to quit
if (input != NULL && strcmp(input, "quit\n") == 0)
{
free(input);
break;
}
// if user wants to enter text
else if (input != NULL)
{
fputs(input, fp);
fputs("\n", fp);
printf("CHA-CHING!\n\n");
// free(input);
}
}
// close the file and end successfuly
fclose(fp);
return 0;
}
Hope it helps your problem.
Cheers.
While you can use malloc() here, it is not really necessary. You can #define a reasonable maximum line length, and declare a character array to hold the input. If you do this, you can remove the frees from your code.
You also have an issue with the way that you are using fgets(). The trailing \n is kept by fgets(), but your comparisons are ignoring this. Consequently, input is never equal to "quit", and is certainly never NULL. I have included some code that removes the trailing newline after reading into input; the code also clears any remaining characters from the input stream, which is possible in the event that the user enters more than MAXLINE - 1 characters. The test for text input is then simply if (input[0]). Alternatively, you could change your tests to take into account the extra '\n' character.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define MAXLINE 1000
int main(int argc, char* argv[])
{
char input[MAXLINE];
char *ch; // used to remove newline
char c; // used to clear input stream
// ensure one and only one command line argument
if (argc != 2)
{
printf("Usage: %s [name of document]\n", argv[0]);
return 1;
}
// open a new document for writing
FILE* fp = fopen(argv[1], "w");
// check for successful open
if(fp == NULL)
{
printf("Could not create %s\n", argv[1]);
return 2;
}
// get text from user and save to file
while(true)
{
// get text from user
printf("Enter a new line of text (or \"quit\"):\n");
fgets(input, MAXLINE, stdin);
// remove trailing newline
ch = input;
while (*ch != '\n' && *ch != '\0') {
++ch;
}
if (*ch) {
*ch = '\0';
} else { // remove any extra characters in input stream
while ((c = getchar()) != '\n' && c != EOF)
continue;
}
// if user wants to quit
if (strcmp(input, "quit") == 0)
{
break;
}
// if user wants to enter text
else if (input[0])
{
fputs(input, fp);
fputs("\n", fp);
printf("CHA-CHING!\n\n");
}
}
// close the file and end successfuly
fclose(fp);
return 0;
}
I think it's because of the fgets function.
Yes: passing NULL pointer to fgets makes no sense, isn't allowed, and will cause a crash.
I might need to malloc to solve the problem.
You need to pass a pointer to a suitable buffer for fgets to read input into. Whether that buffer is malloced, a local or a global array, is irrelevant.
TL;DR: think about what you are doing.

fscanf and printf stop working

I tried to read and print words from a text file, but the program somehow closed itself.
int main(){
FILE * test= fopen("book.txt","r");
char *wp;
while(!feof(test))
{
wp=(char*)malloc(sizeof(char));
fscanf(test,"%s",wp);
printf("%s",(char)wp);
}
return;
}
There are so many errors in your code that I'm just going to show you a proper way to do it.
// Include needed header files.
#include <stdio.h> // fopen, fprintf, fgets, printf, fclose
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // strchr
int main(){
// Allocate more than enough space to hold a line.
char line[256];
FILE *file = fopen("book.txt","r");
// Ensure that file has opened.
if (file == NULL) {
fprintf(stderr, "Can't open file.\n");
exit(EXIT_FAILURE); // Return an integer indicating failure.
}
// Use fgets to avoid buffer overflow.
// Test for end-of-file directly with the input function.
while (fgets(line, sizeof(line), file)) {
// Remove newline if present
char *p = strchr(line, '\n');
if (p != NULL) *p = '\0';
printf("%s\n", line);
}
// Explicitly close file.
fclose(file);
return 0; // Return an integer (0 or EXIT_SUCCESS indicates success)
}

How to read a line from stdin, blocking until the newline is found?

I'm trying to read one line at a time, of arbitrary length, from stdin at the command line. I'm not sure if I'll be able to include GNU readline and would prefer to use a library function.
The documentation I've read suggests that getline ought to work, but in my experiments it doesn't block. My sample program:
#include <stdio.h>
int main()
{
char *line = NULL;
if (getline(&line, NULL, stdin) == -1) {
printf("No line\n");
} else {
printf("%s\n", line);
}
return 0;
}
produces No line, which makes it unsuitable for accepting user input.
How do I do this? I know it should be trivial, but I haven't been able to figure it out.
Try this patch
char *line = NULL;
+size_t size;
+if (getline(&line, &size, stdin) == -1) {
-if (getline(&line, 0, stdin) == -1) {
printf("No line\n");
} else {
I have been able to reproduce a "nonblocking" behaviour on getline:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *buffer;
size_t n = 1024;
buffer = malloc(n);
return getline(&buffer, &n, stdin);
}
getline(&buffer... blocks. If I assign NULL to buffer, again it blocks (as advertised), and stores the line in a newly allocated buffer.
But if I write
getline(NULL, &n, stdin);
then getline fails, and seems not to block. Probably also an invalid n or file pointer could cause the same behaviour. Might this be the problem?

Resources