I'm currently practicing File I/O in C. I created a program where I get a file and extract data from it and I would like an option to change the file that is being read. The problem that I'm encountering is that for example I have two files: sample1.txt and sample2.txt. If I chose sample1.txt as the first file to be read and then I wanted to change the file to sample2.txt what ends up happening is that the filename does not change to sample2.txt but instead always stays what ever filename the first file has.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <assert.h>
#include <time.h>
#include <ctype.h>
int main()
{
char file_location[100]={0};
char new_location[100]={0};
FILE* fPointer=NULL;
int choice;
printf("Enter the filename that you wish to open.\n");
scanf("%[^\n]s",file_location); // I enter sample1.txt//
printf("%s\n",file_location);
fPointer=fopen(file_location,"r"); // success,sample1.txt is currently being read.//
if (fPointer==NULL)
{
printf("File error!,invalid file name! program will now exit.\n");
exit(0);
}
else
{
printf("Success!\n");
}
printf("Do you want to change the file being read\n); //Now I want to change the file,from sample1.txt to sample2.txt//
prinft("Enter 1 to change, 0 to exit the program\n);
do{
scanf("%d",&choice);
printf("You entered %d\n",choice);
if(choice<0||choice>1)
{
printf("Error,please choose between 1 and 0\n");
}
}while(choice!=1||choice!=0);
switch(choice) // I enter 1,go to case1//
{
case 0:
printf("Exiting program now\n");
exit(0);
break;
case 1:
fclose(fPointer);
printf("Enter the filename that you wish to open.\n");
scanf("%[^\n]s",new_location); //scanf does not even prompt me to enter a string.//
printf("%s\n",new_location); //nothing prints//
fPointer=fopen(new_location,"r"); // fpointer still points to sample1.txt//
break;
}
return 0;
}
Could anyone explain to me why my code keeps failing?
Any constructive criticism ,notes about File I/O is appreciated.
The fundamental problem is that your code mishandles newlines. This method of obtaining input probably does not do what you think it does:
scanf("%[^\n]s",new_location);
First, there is no reason for the trailing s here. Second, this will leave a trailing newline behind in the input stream. This newline is ignored when you call scanf("%d",&choice);, since the %d conversion specifier skips over leading whitespace characters. But, this second call to scanf() also leaves a newline character behind, and this is not ignored by the final call to scanf(), since %[^\n] tells scanf() to read characters until a newline is encountered.
One fix is to simply remove the scanset from your scanf() statements:
scanf("%s", new_location);
This will ignore leading whitespace characters, so the newline left behind from the previous call to scanf() will be ignored.
Also, when you open the new file, you are using file_location instead of new_location.
You will need to change your do loop condition to:
while(choice != 1 && choice != 0);
since you want to repeat the loop only if the user enters a number that is both not 0 and not 1.
If you want to read lines that include spaces, which is what [^\n] is sometimes used for, a better alternative is to use fgets(). This function keeps the newline, so you will need to remove it from the filenames. Also, if you are using fgets() to get the strings, it is best to use fgets() to get the numeric input, by reading the user input into a buffer and using sscanf() to parse it. Then your input code would look like:
/* Get first filename, and remove the newline */
printf("Enter the filename that you wish to open.\n");
fgets(file_location, sizeof file_location, stdin);
file_location[strcspn(file_location, "\r\n")] = '\0'; // remove newline
...
/* Get numeric input; this keeps the newline, so it does not interfere
* with the next call to `fgets()` */
char buffer[100];
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%d", &choice);
...
/* Get the new filename, and remove the newline */
printf("Enter the filename that you wish to open.\n");
fgets(new_location, sizeof new_location, stdin);
new_location[strcspn(new_location, "\r\n")] = '\0'; // remove newline
Related
I am trying to make it so you can write a multi line message and it will store it in a file of your choosing and to be done you enter ` but when I do this at the top there is a blank line printed. How can I prevent this?
#include <stdio.h>
char filename[BUFSIZ];
char input[BUFSIZ];
FILE *file;
int main() {
printf("What do you want to name the file?\n");
scanf("%s", filename);
printf("Enter the contents. Once you are done enter `\n");
scanf("%[^`]s", input);
file = fopen(filename, "w");
fprintf(file, "%s", input);
fclose(file);
}
Code:
/* multi.c
*/
#include <stdio.h>
#define BUFSIZE 1024
int main(void)
{
char filename[BUFSIZE];
char input[BUFSIZE];
FILE *fp;
/* using fprintf(stderr... is better because of output buffering.
* This way, we don't need the '\n' at the end for the string to
* appear in the console. You could also use:
*
* printf("Filename: "); fflush(stdout);
*/
fprintf(stderr, "Filename: ");
/* When you press ENTER, a '\n' will be created at the stdin buffer.
* However, this scanf() will NOT read it into #filename. So the '\n'
* is left in the buffer...
*/
scanf("%s", filename);
fprintf(stderr, "Contents: ");
/* when you call scanf() again, the old '\n' is the first character
* it reads into #input. So, to discard that, simply add a space
* before the % - this ignores whitespaces (tabs, newlines, spaces)
*/
scanf(" %[^`]", input);
/* open the file, check for errors */
if(!(fp = fopen(filename, "w"))) {
perror("fopen");
return -1;
}
/* print the contents to the file */
fprintf(fp, "%s", input);
/* clean up */
fclose(fp);
return 0;
}
This is the execution:
$ ./multi
Filename: hello.txt
Contents: My name is Enzo
I am writing some multiline content to a file
And then I'm posting it to
Stack Overflow.`
And this is hello.txt
$ cat hello.txt
My name is Enzo
I am writing some multiline content to a file
And then I'm posting it to
Stack Overflow.$
Notice that after the last line my terminal character $ is there. This is because we end the input with a ` character, and not with a new line. Therefore, there's no new-line at the end of the file.
int main() {
printf("What do you want to name the file?\n");
scanf(" %s", filename);
printf("Enter the contents. Once you are done enter `\n");
scanf(" %[^`]s", input); //do not forget to put a space in scanf
file = fopen(filename, "w");
fprintf(file, " %s", input); //try to make a space in there or if it doesn't work
fclose(file); //than try " %[^\n] but this is a little risky depends in the way you want use the code.
//if none of these works than try this other way "\b %s"
}
always put a white space before " %s" or other text format specificators because, you may have problems...
The reason is that when you add a scanf() directely after a printf() sometimes it scanf takes as part of the string that it has to read even the last character printed by printf(), depending in what kind of characters they are (mostly white spaces, \n, \t). It's a little bit weird but it happened me a lot of times in the past.
I think that the problem is in there
scanf(" %[^`]s", input); //put that white space
first try to make that space here and I think it will work, but if it doesn't try the others left in comments. One of them will definitively work.
I am trying to write user input to a txt file using a while loop.
But for some reason that I don't know, the while loop doesn't stop by clicking 'enter'.
when I click 'enter', I see "while loop executed" so I know the while loop iterated again even though I wanted to stop the while loop.
How to do it in a right way?
P.S: I use Microsoft Visual Studio recommended by my professor.
#include <stdio.h>
#include <string.h>
void main()
{
//writing to file
char write[100];
char fileName[100];
printf("give a name for file: ");
gets_s(fileName,99);
strcat(fileName,".txt");
FILE* pF = fopen(fileName, "w");
printf("what needs to be written?\n: ");
while(gets_s(write,99) != NULL)
{
printf("whileloop executed\n");
fprintf(pF,"%s\n", write);
}
fclose(pF);
}
Per Microsoft's gets_s() documentation, gets_s() returns NULL on end-of-file and error conditions:
Return Value
Returns buffer if successful. A NULL pointer indicates an error or
end-of-file condition. Use ferror or feof to determine which one
has occurred.
Hitting the enter key does not close the input stream and cause an end-of-file condition. It just places a zero-length line terminated with a newline in the input stream.
To do that on Windows from a terminal, one usually has to enter the CTRL-Z key combination.
You need to do some handling there as gets_s() will return and empty string when enter is hit. You can write an extra function to handle that:
size_t my_gets(char *buf,size_t len)
{
size_t ret=0;
if(gets_s(buf,len))
ret = strlen(buf);
return ret;
}
Then change your loop to:
while(my_gets(write,99))
{
...
P.S.- You should avoid calling variables with the same name of system functions (i.e. write).
I am trying to make a program which will store the data entered by the user in a text file whose name is provided by the user. Program will terminate when the user enters exit. strcmp function of string.h is used for string comparison and fgets() is used to read data from stdin.
Here is my code.
#include<stdio.h>
#include<string.h>
void main()
{
char file[60]; // will store file name
printf("Enter file name: ");
fgets(file, 59, stdin);
FILE *fp = fopen(file, "a+"); // open file in append mode
if(fp == NULL){
printf("File not found !");
return;
}
char data[100];
printf("Enter some data to add to file(exit to terminate): ");
fgets(data, 99, stdin);
int flag = strcmp(data, "exit");
while(flag != 0){
fputs(data, fp);
fgets(data, 59, stdin);
flag = strcmp(data, "exit");
printf("%d\n", flag); // for checking whether string are correctly comapred or not
}
printf("Bye");
}
Program does not terminate even if i enter exit. I have also tried concatenating "\n" at the end of string input by user but that also doesn't help. Although, gets() function works fine, but i know it is not preferred to use to I shifted to fgets() but it doesn't work for me.
Check the man page for fgets(), it reads and stores the newline (caused by pressing ENTER) after the entered input. Thus, the strcmp() fails.
You have to manually strip the input buffer off the newline, before you can compare the input. A simple yet elegant way of doing that would be
data[strcspn(data, "\n")] = 0;
fgets reads in a complete "line", i.e. a sequence of characters until (and including!) a new line character. Hence, when a user presses "Enter", the new line will be part of the string read in and a strcmp(data,"exit") will evaluate to "not equal".
So either strip off the new line before comparison, or compare with a string literal including a new line. Since you write the data as is(i.e. including the new lines) to a file, it seems cumbersome to first strip the new line off and add it then in the output manually. So I'd actually suggest the second approach:
fgets(data, 100, stdin);
flag = strcmp(data, "exit\n");
An alternative would be to use strstr if excess characters do not matter (i.e. your program would exit if the user types "exit" or "asdfexitasdf". - both of which contain "exit".)
So
int flag = strstr(data, "exit");
if(flag != NULL)
//exit the program
else
//stay in the program
This question already has answers here:
Removing trailing newline character from fgets() input
(14 answers)
Closed 8 years ago.
I'm prompting the user for the file name, but once the user presses enter, it takes that into the file name as well. so the file is never found.
int main (){
char file[100];
FILE *fp;
printf("Please enter a valid filename:\n");
fgets(file,100,stdin);
fp=fopen(file, "r");
if(!fp){
printf("File not found.\n"); \\This will always happen because a new line is added to the user's input.
return 1;}
If I use
scanf("%s", file);
The issue doesn't happen, but I heard scanf is not a good function to use and would introduce new issues. How can I solve the new line problem with fgets?
After fgets(file,100,stdin);, do this file[strlen(file)-1]='\0';, it will remove \n from the code. To use strlen() function you need to include string.h in your code.
Try this modified code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (){
char file[100];
FILE *fp;
printf("Please enter a valid filename:\n");
fgets(file,100,stdin);
file[strlen(file)-1]='\0'; //Removing \n from input
fp=fopen(file, "r");
if(fp==NULL)
{
printf("File not found.\n");
return 1;
}
else
{
printf("File found!\n");
fclose(fp);
return 0;
}
}
fgets() returns the \n new line code.... that's what it does. You must wipe out that character.
Given that overflowing, or at least totally filling, incoming buffers is a popular attack vector I prefer code that defends against such.
char *cp;
file[(sizeof file)-1)] = '\0'; /* assure \0 termination on buffer fill attack */
cp = strchr( file, '\n' ); /* find expected \n, but allow for none */
if ( cp ) *cp = '\0'; /* safely clear closing \n */
After succesfully reading a re-directed file to my program from the console, I ask a user to enter a word, then use scanf() to read in the word.
The problem i'm having is that scanf() is immediately reading in junk characters and then the program continues. It doesn't even pause to let the user enter anything in the console. It doesn't happen when I don't open a file. EVERYTHING else works perfectly. What could be the issue:
**I tried everything suggested, still can't get it to work. I've made a new project that is just for getting this part to work, here it is. Ignore that scanf is only looking for a single character, even though I ask for a word. I did this just to see if the program would actually pause and allow me to enter something, but it doesn't. Just enters some garbage and program ends.
main(){
int n,i;
char ch;
char line[80];
while(fgets(line, 80, stdin) != NULL){
for(i=0;i<80;i++){
ch=line[i];
if(ch=='\n'){
printf("%c",ch);
break;
}
else{
printf("%c",ch);
}
}
}
printf("Please enter a word: ");
scanf("%c",&ch);
}
You can't re-direct stdin from a file and then also use the keyboard for input (that I know of). If you want to do that, it's simpler to have the program take the input file as a command-line argument and then run it like so: prog myfile.txt. Also, leave yourself a pad with fgets() -- use one less than the allocated array for maxlen. It's always safest with C char arrays to use one less than the allocated length for anything requiring a maximum length in case the maximum length is not including the '\0' terminating character.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc,char *argv[])
{
FILE *f;
int i;
char line[80];
if (argc<2)
{
printf("Usage: %s <inputfile>\n",argv[0]);
exit(10);
}
/* Open file and echo to stdout */
f=fopen(argv[1],"r");
if (f==NULL)
{
printf("Cannot open file %s for input.\n",argv[1]);
exit(20);
}
while (fgets(line, 79, f) != NULL)
printf("%s",line);
fclose(f);
/* Get user input from stdin */
printf("Please enter a word: ");
if (fgets(line,79,stdin)==NULL)
{
printf("Nothing entered. Program aborted.\n");
exit(30);
}
/* Remove CR/LF from end of line */
for (i=strlen(line)-1;i>=0 && (line[i]=='\n' || line[i]=='\r');i--)
;
line[i+1]='\0';
printf("The word entered is: '%s'\n",line);
return(0);
}
sscanf is used to input from a stream or a buffer, and in unix stdin is considered as file so u are supposed to use fscanf which inputs from a file so use fscanf(stdin,"%s",testword);