Is stdin incompatible input stream when working with fopen();? - c

I have some demo code that wants the user to input a filename and the mode. The book is suggesting the dreaded gets(); function for input, which I refuse to use, so I tried to grab my input with fgets(). When I used fgets() I specified my input stream as 'stdin', however the code will not work. The code WILL work with gets(), however. I assume that the problem with my implementation of fgets() is the 'stdin' stream type. Is that why my fgets() will not work with this program? If so, what input stream type should I use? Here is the program:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char ch, filename[40], mode[4];
while(1)
{
printf("\nEnter a filename: "); //This is where fgets/gets conflict is
//fgets(filename, 30, stdin); //I commented out the fgets()
gets(filename);
printf("\nEnter a mode (max 3 characters):");
//fgets(mode, 4, stdin); //fgets again
gets(mode);
//Try to open the file
if((fp = fopen(filename, mode)) != NULL)
{
printf("\nSuccessful opening %s in mode %s.\n",
filename, mode);
fclose(fp);
puts("Enter x to exit, any other to continue.");
if((ch = getc(stdin)) == 'x')
{
break;
}else{
continue;
}
}else
{
fprintf(stderr, "\nError opening file %s in mode %s.\n",
filename, mode);
puts("Enter x to exit, any other to try again.");
if((ch = getc(stdin)) == 'x')
{
break;
}else{
continue;
}
}
}
return 0;
}
Thanks in advance all. This program was from "Teach Yourself C in 21 Days" by B. Jones.

Well done on not wanting to use gets(); that is absolutely the correct way to go.
The error opening the file arises from the fact that fgets() keeps the newline and gets() does not. When you try to open the file name with the newline, the file is not found.

Related

Cannot write in file using loop in C

I a trying to take file name as argument and write strings using loop until user enter "-1".
problem 1: writing is not happening in text file and always shows empty
problem 2: cannot compare input -1 and "-1" . Always runs the else statements.
Note: I also tried fputs but it did not work that time either.
FILE *fp = fopen(argv[1], "a");
//fseek(fp, 0, SEEK_END);
char str[100];
printf("enter string\n");
bool flag = true;
while (flag == true) {
//printf("\nEnter data to append: ");
fflush(stdin);
fgets(str, 100, stdin);
if (strcmp(str, "-1") == 0) {
break;
} else {
fprintf(fp, "%s", str);
printf("Text written in file: %s\n", str);
}
}
fclose(fp);
Writing don't happen because of strcmp, I'm showing you my version of this with atoi.
#include <stdio.h>
#include <stdlib.h>
#define buffer 128
int main(int argc, char *argv[])
{
char str[buffer];
int flag = 1;
FILE *fp = fopen(argv[1], "w+"); //I prefer using write mode and not append
if(fp==NULL)
{
printf("Error opening file.\n"); //here you control if the file is opening correctly
exit(EXIT_FAILURE);
}
while(flag) //you don't need to write while(flag==true) (that's not wrong)
{
printf("Insert string: ");
scanf("%s", str);
if(atoi(str)==1) //the function strcmp as you wrote it will break after the
break; //first cicle, use atoi, it returns 1 if the string is a number
fprintf(fp, "%s\n", str); //the \n is to get the next string on the next row
}
fclose(fp);
return 0;
}
If you want to make it work with strcmp your if statement should be if(strcmp(str, "-1\n")) because fgets reads also the \n character.
Because fget() reads new line character.
So once you do comparation, It looks like:
strcmp("-1\n", "-1");
or
strcmp("-1\n\r", "-1");
You will never break the loop.
To remove newline character, let try:
strtok(str, "\n");
or
strtok(str, "\r\n");

fscanf not returning EOF or fscanf going to infinite loop in C

I am trying to write a few lines to a file. After the line are written, when I try to read those lines from file using fscanf it is going into infinite loop. fprintf is working but fscanf is going to an infinite loop.
#include<stdio.h>
#include<stdlib.h>
void main()
{
FILE *fp;
int roll;
char name[25];
float marks;
char ch;
fp = fopen("file.txt","w");
if(fp == NULL)
{
printf("\nCan't open file or file doesn't exist.");
exit(0);
}
do
{
printf("\nEnter Roll : ");
scanf("%d",&roll);
printf("\nEnter Name : ");
scanf("%s",name);
printf("\nEnter Marks : ");
scanf("%f",&marks);
fprintf(fp,"%d%s%f",roll,name,marks);
printf("\nDo you want to add another data (y/n) : ");
ch = getche();
}while(ch=='y' || ch=='Y');
printf("\nData written successfully...");
printf("\nData in file...\n");
while((fscanf(fp,"%d%s%f",&roll,name,&marks))!=EOF)
printf("\n%d\t%s\t%f",roll,name,marks);
fclose(fp);
}
You have opened the file for writing (mode "w"), so your scanf calls are almost certainly failing. Even if you fix the mode, it is not at all surprising that:
while((fscanf(fp,"%d%s%f",&roll,name,&marks))!=EOF)
goes into an infinite loop. If the next character in the stream is not a valid character in an integer, then scanf will return zero and not consume it. It will repeatedly attempt to read that character as an integer and repeatedly fail. The correct approach here is probably to stop using scanf entirely, but a quick work-around may be something like:
int rv;
while( (rv = fscanf(fp,"%d%s%f",&roll,name,&marks)) != EOF ){
if( rv == 3 ){
printf(...);
} else {
/* probably the right thing to do is break out of
the loop and emit an error message, but maybe
you just want to consume one character to progress
in the stream. */
if( fgetc(fp) == EOF ){
break;
}
}
}
it would be more common to write while( 3 == fscanf(...)) and just emit an error message on bad input, but something like the above kludge might be useful (depending on your use case).
But you need to fix the open mode. Probably you just want to close the file after the write loop (you certainly need to flush it before you can expect to read from the file) and re-open in with mode "r".

C: writing/reading files using do while loop

I'm writing a simple exercise app in C, which should ask user if he want write something to file or read the file. I want give name to the file and then input some text in console. I want use that text to save it to the file.
The problem is that, when I already give name to the file, I can't input data to the console and by this I can't save these datas to the text file. In addition, the while loop ignores my 'y' to restart the program again. Furthermore, when I want use reading file then it really does, program works, but it also adds instruction from default (printing just error) but I don't want that, just only read from file and print it to the console.
Can someone explain me what I'm doing wrong and how to solve this? I'd be grateful.
Here's my code:
int main()
{
FILE *file;
char nameFile[32];
char string[500];
char ans[2];
int choice;
do{
printf("What do you want to do?\n");
printf("1. Write text to file\n");
printf("2. Read text file\n");
scanf("%d", &choice);
switch (choice) {
case 1:
printf("Give name to the file (*.txt).\n");
scanf("%s", nameFile); //This line skips me to line where program ask user if restart the program (I have no idea why :()
system("clear");
file=fopen(nameFile, "w");
if(file!=NULL){
printf("Input text:\n");
scanf("%[^\n]", string); //<--- HERE I'cant input text to console, seems like scanf doesn't work.
fprintf(file, "%s", string);
printf("\n\t\t\t-----------Ended writing.------------\n");
fclose(file);
}
else
{
printf("Could not open the file.");
return -1;
}
break;
case 2:
printf("Give name to the file (*.txt)");
scanf("%s", nameFile);
system("clear");
file=fopen(nameFile, "r");
if(file!=NULL){
while (!feof(file)) {
fscanf(file, "%s", string);
printf("%s\n",string); //After printing data from text file, adds instruction from line , and that is printing Error. How to get rid of it?
}
}
else{
printf("Could not open the file.");
return -1;
}
default:
printf("Error.");
break;
}
printf("Do you want to restart the program? (y/*)"); //Even if I write 'y', program ends anyway :(
scanf("%s", ans);
}
while(ans=='y');
return 0;
}
https://ideone.com/aCYJR5
scanf("%[^\n]", string); doesn't work unless the input buffer is clear. Use instead scanf("%499s", string) where 499 is the size of the string minus 1.
Don't use while (!feof(file)){...}, use instead while(fscanf(file, "%500s", string) == 1){...}
Use while(ans[0]=='y') as suggested earlier. Or use
char ans;
scanf(" %c", &ans);//note the blank space before `%c`
while(ans == 'y')
You also forgot to break a switch statement. Try the following:
char c;
char ans;
do {
printf("What do you want to do?\n");
printf("1. Write text to file\n");
printf("2. Read text file\n");
scanf("%d", &choice);
switch(choice) {
case 1:
printf("Give name to the file (*.txt).\n");
scanf("%s", nameFile);
file = fopen(nameFile, "w");
if(file == NULL) { printf("Could not open the file."); return -1; }
printf("Input text:\n");
while((c = getchar()) != '\n' && c != EOF);
fgets(string, sizeof(string), stdin);
string[strcspn(string, "\r\n")]=0;
fprintf(file, "%s", string);
printf("\n\t\t\t-----------Ended writing.------------\n");
fclose(file);
break;
case 2:
printf("Give name to the file (*.txt)");
scanf("%s", nameFile);
file = fopen(nameFile, "r");
if(file == NULL) { printf("Could not open the file."); return -1; }
while(fgets(string, sizeof(string),file))
printf("%s\n", string);
fclose(file);
break;
}
printf("Do you want to restart the program? (y/*)");
scanf(" %c", &ans);
} while(ans == 'y');
See also
Why is “while ( !feof (file) )” always wrong?
How to clear input buffer in C?
your while should be
while(ans[0]=='n');
A char array is a string, you are trying to compare a whole string to the character 'y'. Also, it should "Loop while ans[0] is equal to 'n'" meaning keep going if the user specifies n.

Console not waiting for input. (C language)

When I execute my code below. It waits for my input for entering a file name. But it doesn't wait for me to enter a filename, but rather just skips it to the _getch() part of it. I'm unable to add a sentence.
Code not working:
#include <stdio.h>
main() {
FILE *fp;
char fnamer[100] = ""; //Storing File Path/Name of Image to Display
printf("\n\nPlease Enter the Full Path of the Image file you want to view: \n");
scanf("%s", &fnamer);
fp = fopen(fnamer, "w");
if (fp == NULL)
{
printf("\n%s\" File NOT FOUND!", fnamer);
}
char c[1000];
printf("Enter a sentence:\n");
gets(c);
fprintf(fp, "%s", c);
fclose(fp);
_getch();
}
Code that works and waits for entering a sentence:
#include <stdio.h>
#include <stdlib.h> /* For exit() function */
int main()
{
char c[1000];
FILE *fptr;
fptr = fopen("program.txt", "w");
if (fptr == NULL){
printf("Error!");
exit(1);
}
printf("Enter a sentence:\n");
gets(c);
fprintf(fptr, "%s", c);
fclose(fptr);
return 0;
}
Both are so similar right there in the end for the prompt asking for a sentence. It doesn't make sense.
you have to flush your input after using scanf.
put a getchar() after every scanf
You are encountering a very common problem when using stdin to receive input, which is after your first scanf call there is a dangling \n character which gets stuck in the buffer from the enter key. To clear this buffer in a portable easy way, add something like
char c;
while ( (c = getchar()) != '\n' && c != EOF ) { }
This simply initializes a character, and then calls get char as many times as needed until it reaches '\n' or 'EOF', which is immediately in your case.
tl;dr :
Your buffer looks like this
hello.txt\n <-- "comes from the enter key"
and when you try to use get(c) it takes the \n as the next enter key.
The rule is never mix scanf and [f]gets. scanf stops before the next unused character, generaly a blank, and the end of line is composed of blank characters.
You could try to put a dummy fgets between the last scanf and the first real fgets. That will ensure that you are now positionned on a beginning of line before reading. Alternatively, you could read everything in lines with fgets, and parse the lines with sscanf. That is what I prefere as soon as I want my input to be line oriented. And always control return values of input functions, it will avoid a progam suddenly going mad without any indication simply because one input gave an ignored error.
And last and not least: never use gets but only fgets, the former is for decades in the hall of shame as the cause of uncountable buffer overflows
Code could become:
#include <stdio.h>
#include <string.h>
main() {
FILE *fp;
char fnamer[100] = ""; //Storing File Path/Name of Image to Display
char c[1000], *ix;
int cr;
printf("\n\nPlease Enter the Full Path of the Image file you want to view: \n");
cr = scanf("%s", &fnamer);
if (cr != 1) {
// process error or abort with message
}
fp = fopen(fnamer, "w");
if (fp == NULL)
{
printf("\n%s\" File NOT FOUND!", fnamer);
return 1; // do not proceed after a fatal error!
}
for(;;) { // read until a newline in input
ix = fgets(c, sizeof(c), stdin);
if (ix == NULL) {
// end of input: abort
}
if (strcspn(c, "\n") < strlen(c)) break;
}
printf("Enter a sentence:\n");
ix = fgets(c, sizeof(c), stdin);
c[strcspn(c, "\n")] = '\0'; // remove end of line to get same data as gets
fprintf(fp, "%s", c);
fclose(fp);
_getch();
}
main() {
FILE *fp;
char fnamer[100]=""; //Storing File Path/Name of Image to Display
printf("\n\nPlease Enter the Full Path of the Image file you want to view: \n");
fgets ( fnamer,100,stdin); //fgets(name, sizeof(name), stdin);
fp=fopen(fnamer,"w");
if(fp==NULL)
{
printf("\n%s\" File NOT FOUND!",fnamer);
getch();
exit(1);
}
}
I Think best way to do,use fgets insted of scanf,Because
fgets() can read any open file, but scanf() only reads standard input(user given).
fgets() reads a line of text from a file; scanf() can be used for that but also handles conversions
from string to built in numeric types

C code missing getchar() command in while loop first time round

I am writing a menu system in C, the code works correctly but for some reason the first first time the while loop is entered for the menu it skips the getchar() command and runs through the while loop again, but the second time round it works?
Any ideas as to why it does this?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "structs.h"
int main(void)
{
FILE *fp = NULL;
char fileName[25], line[200], userInput = ' ';
int len;
while (fp == NULL)
{
printf("Enter The File To Load In: \n");
scanf("%s", fileName); // Ask User For File Name
fp = fopen(fileName, "r"); // Open File To Read
if (fp == NULL)
{
perror("Error While Loading File\n");
}
}
while (userInput != 'g')
{
printf(" |User System|\n");
printf("A) Save Current Data To A File\n");
printf("B) Enter Details\n");
printf("C) View Details\n");
printf("D) Amend Details\n");
printf("E) Search by Award Title\n");
printf("F) Search by Surname\n");
printf("G) Shut Down\n");
userInput = getchar();
if (userInput == 'c')
{
fgets(line, 200, fp);
len = strlen(line);
printf("%s", line);
userInput = getchar();
}
}
}
After 'scanf' use
getchar();
to consume extra newline. As 'scanf' can not discard newline, first iteration of 'getchar();' take the newline.
So you shold place getchar() after scanf as to consume extra newline('\n')
scanf("%s", fileName);
getchar();
It's better to use 'fgets' instead of scanf as file name may have space.
You can use 'fgets()' as
fgets(fileName, sizeof(fileName), stdin);
fileName[strlen(fileName)-1] = 0; //Replace newline with '\0' character

Resources