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
Related
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'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
I have a file that's storing strings from the user's input (stdin)
However there are 2 situations
If I read it normally, my file will have an empty line at its end due to the newline from the last string the user introduced.
If I remove the \n from the input string, the file stores all strings in the same line, which is not wanted.
How can I simply remove that newline from the end of the file?
I can edit and provide some of my code if required.
EDIT: Let's say the last line of a file I already have is "cards"
when the cursor is in front of "cards", if I press the down arrow it doesn't go on to the next line, while in this case it can happen once.
For my code to function perfectly I can't let that happen,
Here's an example of what I have:
f=fopen(somefile, "w");
do
{
fgets(hobby, 50, stdin);
fprintf(f, "%s", hobby)
} while(strcmp(hobby,"\n") != 0);
The newline character1 at the end of the file is part of the last line. Removing it is possible but makes the last line incomplete, which will break many programs. For example, concatenating another file at the end of this file will cause the last line to be merged with the first line of the concatenated file.
A Yuri Laguardia commented, if you later reopen this file in append mode to write more lines, the first one added would be concatenated at the end of this last incomplete line. Probably not the intended behavior.
If you do not want the file to contain empty lines, check user input before writing the line into the file:
void input_file_contents(FILE *fp) {
char userinput[80];
printf("enter file contents:\n");
while (fgets(userinput, sizeof userinput, stdin)) {
if (*userinput != '\n') {
fputs(userinput, fp);
}
}
}
EDIT:
Your code does not test for termination at the right place: you write the empty line before the test. Do not use a do / while loop:
f = fopen(somefile, "w");
if (f != NULL) {
/* read lines until end of file or empty line */
while (fgets(hobby, 50, stdin) != NULL && *hobby != '\n') {
fputs(hobby, f);
}
}
1 The newline character is actually a pair of bytes <CR><LF> on legacy systems.
I'm trying to have the program check, that, if a user inputs nothing the print statement will say it cant find the file name, but the issue I'm having is that the command line will just go to a new line after hitting enter instead of saying the print statement.
This is the code here. I was told that Null is the place holder for if nothing is put in so I thought it would work.
int main()
{
FILE *fin;
FILE *fout;
char fInName[50];
char fOutName[50];
printf("pleas type input file, and output file please type legibly\n ");
scanf("%s %s", &fInName, &fOutName);
fin = fopen(fInName, "r");
fout = fopen(fOutName, "r");
if (fInName == NULL && fOutName == NULL)
{
printf("Error: Cannot open input file %s.", fInName);
}
else if (fInName != NULL && fOutName == NULL)
{
printf("file found");
}
}
What im trying to test is if a first file name is entered and the second isnt then print the statement. If both arent entered then print file does not exist.
there is more to the code to see if the file exists or not, but thst would be a bit much, now Im just trying to understand why it wont read unentered data.
Ive tried looking at examples such as: How to detect empty string from fgets
and tried to alter the code to fit that type of style but it didnt work for me so Im giving you the code it was originally so that anything helpful wouldnt confuse me more.
Edit:
okay so I tried to do a simple code in order to see what may be the cause of this issue:
int main()
{
char firstname[50];
char lastname[50];
char nothing [0];
printf("pleas type input file, and output file please type legibly pwease\n ");
scanf("%s" "%s", firstname, lastname);
if (firstname == lastname )
{
printf("Error: Cannot open input file %s.", firstname);
}
else
{
printf("file found");
}
}
I ran the code using adam and either if I typed adam (space) adam or adam(enter) adam the program thinks that the input is not the same, I feel like that would help identify why it doesnt know why nothing is typed in.
The problem is occurring when you try to check if fInName == NULL.
The problem is that fInName is just a variable that you're using to store the name of the file that you want to open. What you actually want to check is that the user gave you a valid filename, and to do so you will want to understand what the return value of functions are.
For example, when you try to open a file using fopen(), if fopen() is unable to successfully open the file, say because the user didn't input anything or misspelled the filename, then fopen() will return NULL, storing it in whatever variable you assigned it to (in your case, *fin and *fout).
Also, scanf() is not recommended for char arrays because if the user inputs more data than you allocated for the array, which in this case is enough space for 50 characters, then scanf() will try to write data to memory that's not yours, causing a buffer overflow.
A much safer option is to use fgets() because you can choose exactly how much data is written into your char array, with the only downside being that fgets() will write newline characters \n (caused by hitting the enter key) into the array, though the simple solution is to overwrite the newline character with '\0'.
Therefore, I would propose:
int main(void)
{
char fInName[50];
char fOutName[50];
// ensure proper usage
do
{
printf("What file would you like to open? ");
// get infile from user and remove trailing newline '\n' character
fgets(fInName, 50, stdin);
fInName[strcspn(fInName, "\n")] = '\0';
}
// prompt for input until user enters something
while (strlen(fInName) < 1);
do
{
printf("What file would you like to output to? ");
// get outfile from user and remove trailing newline '\n' character
fgets(fOutName, 50, stdin);
fOutName[strcspn(fOutName, "\n")] = '\0';
}
// prompt for input until user enters something
while (strlen(fOutName) < 1);
FILE *fin = fopen(fInName, "r");
if (fin == NULL)
{
printf("Error: Cannot open input file %s.", fInName);
return 1;
}
else
{
printf("file found");
}
}
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);