Having trouble understanding a program(below).
I am little bit confused about the statement fputs("\n",fp)
eg. let me type:
It doesn't matter what you are underneath
Its what you do that defines you.
If I don't mention fputs("\n",fp) the string appears in a single line. But with the code it is saved as typed.
Now the question is how the \n is inserted in the desired place, cause' normally the \n should be appended in the end of the text.
Any help would be seriously appreciated.
int main()
{
FILE *fp;
char s[80];
fp=fopen("abc.txt","w");
if(fp==NULL)
{
puts("Cannot open file");
exit(1);
}
printf("\nEnter a few lines of text:\n");
while(strlen(gets(s))>0)
{
fputs(s,fp);
fputs("\n",fp);
}
fclose(fp);
return 0;
}
gets (which shall not be used and has actually been removed from the most recent C standards) does not save the \n in its buffer (while fgets does).
And fputs, unlike puts, does not automatically insert one at the end of the string it writes. So by adding a fputs("\n", fp); (or fputc('\n', fp)) after outputting each typed line, you insert the missing newline in the file.
fputs does not automatically add a newline to the output (in contrast with puts which does).
Related
This is the basic code to a program I am writing to practise using files in C. I am trying to detect whether the output file already exists and if it does exist I want to ask the user if they would like to overwrite it or not. This is the reason that I have first opened the outfilename file in with fopen(outfilename,"r"); as opposed to fopen(outfilename,"w");.
It detects the case of the file not existing, however, if it does exist it executes the printf("Output file already exists, overwrite (y/n):"); statement but completely ignores the scanf("%c",&yn); statement!
The printf at the end of the program reads "yn=0" if the file doesn't exist and just "yn=" if it does exist. Can anybody help me?
#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <string.h>
int main(void) {
FILE *inf;
FILE *outf;
char filename[21],outfilename[21];
char yn='0';
printf("Please enter an input filename: ");
scanf("%s",&filename);
printf("Please enter an output filename: ");
scanf("%s",&outfilename);
/* Open file for reading */
inf=fopen (filename,"r");
outf=fopen(outfilename,"r");
/*check that input file exists*/
if (inf!=NULL) {
/*check that the output file doesn't already exist*/
if (outf==NULL){
fclose(outf);
/*if it doesn't already exist create file by opening in "write" mode*/
outf=fopen(outfilename,"w");
} else {
/*If the file does exist, give the option to overwrite or not*/
printf("Output file already exists, overwrite (y/n):");
scanf("%c",&yn);
}
}
printf("\n yn=%c \n",yn);
return 0;
}
printf("Please enter an output filename: ");
scanf("%s",&outfilename);
When you enter the second string and hit the ENTER key, a string and a character are placed in the input buffer, they are namely: the entered string and the newline character.The string gets consumed by the scanf but the newline remains in the input buffer.
Further,
scanf("%c",&yn);
Your next scanf for reading the character just reads/consumes the newline and hence never waits for user input.
Solution is to consume the extra newline by using:
scanf(" %c", &yn);
^^^ <------------Note the space
Or by using getchar()
You may want to check out my answer here for a detailed step by step explanation of the problem.
Use
scanf("%20s",&filename);
and remember that stdin is line buffered and on Linux is following a tty discipline
You could use GNU readline or ncurses if you want more detailed control.
scanf("%s", ...) leaves the \n terminating the line in the input. It isn't causing a problem for the next one as scanf("%s", ...) starts by skipping whites. scanf("%c", ...) doesn't and thus you read the \n.
BTW You'll probably meet other problems is you put spaces in your file name (%s doesn't read them) and if you enter too long names (%s has no input length limitations).
One solution for the problem you complained (but not the other one) is to use scanf(" %c", ...) (see the space before %c? scanf is tricky to use) which starts by skipping white spaces.
scanf("%s",&filename);
also remove the &
scanf.c:13: warning: format '%s' expects type 'char ', but argument 2 has type 'char ()[20u]'
The better way to handle this problem I found is explained here.
It recomends to use an alternative way of handle input and is very well explained.
I use always this function to get user input.
char * read_line (char * buf, size_t length) {
/**** Copyright de home.datacomm.ch/t_wolf/tw/c/getting_input.html#skip
Read at most 'length'-1 characters from the file 'f' into
'buf' and zero-terminate this character sequence. If the
line contains more characters, discard the rest.
*/
char *p;
if ((p = fgets (buf, length, stdin))) {
size_t last = strlen (buf) - 1;
if (buf[last] == '\n') {
/**** Discard the trailing newline */
buf[last] = '\0';
} else {
/**** There's no newline in the buffer, therefore there must be
more characters on that line: discard them!
*/
fscanf (stdin, "%*[^\n]");
/**** And also discard the newline... */
(void) fgetc (stdin);
} /* end if */
} /* end if */
return p;
} /* end read_line */
Old Answer
I fixed this sort of problems with this rule:
// first I get what I want.
c = getchar();
// but after any user input I clear the input buffer
// until the \n character:
while (getchar() != '\n');
// this also discard any extra (unexpected) character.
If you make this after any input, there should be not problem.
There is a text file called 1.txt like below that contains certain names, I want to add them to a linked list however the code doesn't scan only one name but the whole line, how can I make fscanf so that it only scans a single name?
Example 1.txt:
ana,bob,max,dolores
My code:
FILE *fp = fopen("1.txt", "rt");
while (!feof(fp)) {
char name_in[100];
fscanf(fp, "%s,", name_in);
printf("%s", name_in);
addnewnode(head, name_in);
}
fclose(fp);
The problem is that with the "%s" format, then scanf will not stop scanning until it hit the end of the input or a whitespace. That means you can't use scanf alone to parse your input.
Instead I suggest you read your whole line into a buffer, for example using fgets. Once you have it then you can use strtok in a loop to tokenize the line.
Not using scanf also sidesteps a big problem with your format string: Namely that it will look for a trailing comma in the input. If there's no comma at the end of the line (like in your example) then scanf will just block. It will block until there is a comma, but if you don't give it a comma then it might block forever. Either that or you will not get the last entry because scanf will fail. Checking what scanf returns is crucial.
Also, I strongly suggest you read Why is “while ( !feof (file) )” always wrong?.
What's in a name?
A name is usually thought of as containing letters, maybe spaces and some other characters. Code needs to be told what char make up a name, what are valid delimiters and handle other unexpected char.
"%s" only distinguishes between white-space and non-white-space. It treats , the same as letters.
"%width[A-Za-z' ]" will define a scanset accepting letters, ' and space. It will read/save up to width characters before appending a null character.
Always a good idea to check the return value of a input function before using the populated objects.
FILE *fp = fopen("1.txt", "rt");
if (fp == NULL) Handle_Error();
// end-of-file signal is not raised until after a read attempt.
// while (!feof(fp)) {
char name_in[100];
char delimiter[2];
int count;
while ((count = fscanf(fp, "%99[A-Za-z' ]%1[,\n]", name_in, delimiter)) == 2) {
printf("<%s>%s", name_in, delimiter);
addnewnode(head, name_in);
if (delimiter[0] == '\n') {
; // Maybe do something special at end-of-line
}
}
fclose(fp);
// Loop stopped unexpectedly
if (count != EOF || !feof(fp)) {
puts("Oops");
}
More robust code would read the line like with fgets() and then process the string. Could use similar code as above but with sscanf()
To include - in a scanset so code can handle hyphenated names, list it first. You may want to allow other characters too.
"%width[-A-Za-z' .]"
i am new in c. So in my university, i just learn about file in c. and i got a task. If i put an empty file in my project directory, and read it. The output are symbols (i dont know what symbol it is). So here is the code, please help
player dota[100];
FILE *fp;
fp = fopen("soal09.txt", "r");
if(fp == NULL)
{
printf("Error Opening The File!!\n");
return 0;
}
else
{
while(!feof(fp))
{
fscanf(fp, "%[^ ] %d %d\n", &dota[idx].name, &dota[idx].score, &dota[idx].num);
idx++;
}
}
fclose(fp);
do
{
enter();
menu();
printf("Input your choice [1..5]: ");
scanf("%d", &choose); fflush(stdin);
if(choose == 1)
{
system("cls");
enter();
printf("%-20s %-15s %s\n", "Player Name", ": Average Score", ": Number of Playing");
printf("====================================================================\n");
for(int i = 0; i < idx; i++)
{
printf("%-20s %-15d %d\n", dota[i].name, dota[i].score, dota[i].num);
}
printf("\nPress Enter to Continue...");
getchar();
}
getchar();
return 0;
}
and the output is ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ -858993460
Thank you ^^
The end-of-file indicator that is checked by feof() is only set after a previous file I/O operation has failed. You must attempt an I/O operation to find out if you have reached the end of the file. So, with an empty file, your code attempts to read the file, the end-of-file indicator is set, no values are read into the first struct, but idx is incremented, so it looks like you have added data for a player. But the fields of the first struct are uninitialized, so you are seeing garbage. Also note that dota[idx].name is presumably an array of chars, so it decays to a pointer to char when passed to fscanf(). Using &dota[idx].name, as you have, is wrong, though it might appear to work. It does cause the compiler to emit a warning, and you should have these enabled (I always use at least gcc -Wall -Wextra -pedantic).
You should not use feof() to control file I/O loops. One simple solution is to use the return value of fscanf() to control the loop:
while(fscanf(fp, "%[^ ] %d %d\n",
dota[idx].name, &dota[idx].score, &dota[idx].num) == 3) {
idx++;
}
This will only update a player struct if three assignments are made by the call to fscanf(). But, the problem with this simple solution is that it doesn't handle malformed input well. If a line of the data file is missing a field, the struct will be incorrectly filled, and the loop will terminate, even if there are more lines in the file to read. Also, since no field width is specified for the string conversion, a long name could crash your program.
A better solution uses fgets() to read the lines of the file into a buffer, and then uses sscanf() to extract the information from the buffer:
#include <string.h> // for strcpy()
...
char buffer[1000];
int line = 0;
char temp_name[100];
int temp_score, temp_num;
while(fgets(buffer, sizeof(buffer), fp)) {
++line;
if (sscanf(buffer, "%99[^ ] %d %d\n",
temp_name, &temp_score, &temp_num) == 3) {
strcpy(dota[idx].name, temp_name);
dota[idx].score = temp_score;
dota[idx].num = temp_num;
++idx;
} else if (buffer[0] != '\n') {
fprintf(stderr, "Bad input in line %d\n", line);
}
}
Here, a generous buffer is declared to accept a line of text from the file, and temporary variables are declared to hold the values to be stored in the struct fields. I have chosen a size of 100 for temp_name, but this should match the size of the string array in your actual struct. Note that the string conversion in sscanf() has a field width of 99, so that at most 99 non-space (not non-whitespace, and why aren't you just using %99s here?) characters are matched, leaving space for the '\0' to be added.
fgets() will return NULL when it reaches the end of the file, so the loop will continue until that happens. For each line that is read, a line counter is incremented. Then sscanf() is used to read data into the temporary variables. The value returned from sscanf() is checked to be sure that 3 assignments were made, and if so, then the data is copied into the struct, and idx is incremented. Note that strcpy() is needed to copy the string from temp_name to dota[idx].name.
If the value returned from sscanf() indicates that something other than 3 assignments were made, there is a check to see if buffer holds an empty line. If not, an error message is printed to stderr providing the line number of the bad input in the file.
A couple of further comments. Your do loop appears to be missing the associated while(). And you use fflush(stdin) after the scanf() inside the do loop. fflush()is meant to flush output streams. The behavior of fflush() on input streams is explicitly undefined in the C Standard (ISO/IEC 9899:2011 7.21.5.2/2), though I believe that Microsoft deviates from the Standard here. Nevertheless, you should not use fflush(stdin) in portable C code. Instead, use something like this:
int c;
...
scanf("%d", &choose);
while ((c = getchar()) != '\n' && c != EOF)
continue; // discard extra characters
This code reads characters from the input stream until either a '\n' or EOF is reached, clearing any characters left behind by the previous call to scanf() from the input stream.
I think I've tried anything (flushing stdin, scanf to consume newline etc.), but nothing works as I had hoped. For some reason a 3rd scanf modifies a variable from 2nd scanf in the following code:
#include <stdio.h>
int main()
{
char first_name[16], last_name[21];
char filename[11];
FILE *opening;
printf("The program saves your first and last name into a file.\n");
printf("Enter your first name:");
scanf("%s", first_name);
getchar();
printf("Enter your last name:");
scanf(" %s", last_name);
getchar();
printf("File where you want to save your name:");
scanf(" %s", filename);
opening = fopen(filename, "wb");
fprintf(opening, "%s %s", first_name, last_name);
printf("\nSuccessfully saved the data!");
fclose(opening);
return 0;
}
The output:
The program saves your first and last name into a file.
Enter your first name: John
Enter your last name: Doe
File where you want to save your name: filename.txt
Successfully saved the data!
All fine and dandy except that the contents of filename.txt is this:
John t
I'm guessing that the 't' character comes from 'txt' somehow, but I've just started learning C and I don't know how to fix this piece of code to work. Could you gurus help me please?
Your filename buffer is too small.
You write filename.txt, which is 12 characters, plus the zero to finish it, makes 13. You only allocate 11. Try like this:
char filename[20];
and it should work.
Be careful though with using scanf, it can lead to very nasty problems, as you are encountering right now. It is good in experimenting and learning C, as it shows you how important correct memory handling is. For any real project you should consider using different functions or frameworks.
Using scanf() on strings is dangerous, as it may read in more data into the buffer than the buffer provides memory.
If scanning in strings one shall always tell scanf() how much characters to read by adding this number to the format passed to scanf():
char file_name[11];
...
scanf("%10s", file_name); /* As file_name provides memor for 11 characters, read a
maximum of 10 characters into file_name leaving 1
character room for the necessary `0-`terminator indicating
the end of the "string". */
Also your code misses error checking on the fopen system call.
Better do something like this:
opening = fopen(filename, "wb");
if (NULL == opening)
{
perror("fopen() failed");
exit(EXIT_FAILURE);
}
If you are entering filename.txt as your file name, then you are overrunning your buffer for filename. That is undefined behaviour and is the cause of the strange results.
To fix, make char filename[11]; larger, remembering to allow 1 extra character for the NULL terminator. In your very specific case, that would be char filename[14]; allowing for the errant space before %s in your scanf call.
Otherwise, all looks fine.
I am trying to read in from a file, and I can't get the pattern of it right. Can someone tell me what I can do to get it working?
int main()
{
char name[20];
int age;
float highbp, lowbp, risk;
FILE *fp;
fp = fopen("data.dat", "r");
if(fp == NULL){
printf("cannot open file\n\n");
}
while(fscanf(fp, "name:%s\nage:%d\nbp:%f\nrisk:%f", name, &age, &highbp, &risk) != EOF){
}
printf("Name: %s\n", name);
printf("%d\n", age);
printf("%f\n", highbp);
printf("%f\n", risk);
}
data.dat:
name:tom
age:32
bp:43.00
risk:0.0
If it can't open the file it prints a message, but then continues. Instead it should return from main.
if (fp == NULL) {
printf("cannot open file\n\n");
return 1;
}
fscanf will return the number of items parsed, so it's probably safer to stop reading when the number returned < 4 (not all the items could be read).
Presumably "data.dat" contains multiple records and each line has a line ending. This means that after reading the first record the next character in the file is the line ending for the "risk:0.0" line. You should end the fscanf template with \n.
This is because the second time it tries to parse the file, fscanf will see that character, which it isn't expecting (the fscanf template starts "name:"), so it will stop reading, and you'll get only the first record.
You should change the "name" format specifier from %s to %19s to make it read at most 19 characters (+terminating '\0'). The way you have it now is a guaranteed failure in case someone gives you 20+ character name.
Can someone tell me what I can do to get it working?
I suggest you separate the functionality in different statements.
Don't try to cram all of the program functionality in 1 statement.
Your big statement is doing 3 things:
it is reading data from file
it is comparing the return value of scanf with EOF
it is controlling when to stop reading
I suggest you do (at least) 3 different statements for the 3 different actions.
Hint: comparing the return value of scanf only with EOF is a little too short