C - 3rd scanf modifies a variable from 2nd scanf - c

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.

Related

for some reason my data isn't being added to my file with my c function

I'm trying to create a small book library in C so I wrote a function that insert a book by it's name, id and quantity. For some reason the program is ruining fine and the function seems to be working but the external file remain unchanged (no new data is added). I checked the path of the file but still the problem persist. how can I fix this?
here's the function and the structure:
struct library{
int id;
int qty;
char name[50];
};
void InsertBook()
{
struct library b;
FILE *books;
if((books=fopen("C:\\mybooks.txt","a+")==NULL))
{
printf("file not found\n");
}
else
{
printf("You will need to enter a name, ID, and quantity of the book.\n");
printf("please enter book name:");
fflush(stdin);
fgets(b.name,SIZE,stdin);
fputs(b.name,books);
printf("please enter book ID:");
scanf("%d",&b.id);
printf("please enter book quantity:");
scanf("%d",&b.qty);
fprintf(books,"%d %s %d\n",b.name,b.id,b.qty);
fclose(books);
}
}```
The only mistake you've done is:
fprintf(books, "%d %s %d\n", b.name, b.id, b.qty);
Just do:
fprintf(books, "%s %d %d\n", b.name, b.id, b.qty); // %s before %d
And everything's OK.
Side Tips
fputs() not required here.
books = fopen("C:\\mybooks.txt", "a+") == NULL expression won't work for most compilers because the assignment makes pointer from integer without a cast.
Instead you can assign it before comparing it to the null expression as shown:
books = fopen("C:\\mybooks.txt", "a+");
if (books == NULL) { ... }```
Important note: Ensure you have writing permission in that destination.
The program does work (but see errors below), however you are writing to the root folder of Drive C. The output file is visible from a console, but not from Windows file explorer. Normally, you should not use the root folder of C drive.
There is a parenthesis in the wrong place here
if((books=fopen("mybooks.txt","a+")==NULL))
which should be
if((books = fopen("mybooks.txt","a+")) == NULL)
There are wrong format specifications wrong in fprintf here, as complained by the compiler
fprintf(books,"%d %s %d\n",b.name,b.id,b.qty);
should be
fprintf(books, "%s %d %d\n", b.name, b.id, b.qty);
You unnecessarily duplicate writing the book title to file a few lines above with
fputs(b.name,books);
You use an incorrect buffer size for fgets here
fgets(b.name,SIZE,stdin);
which should be
fgets(b.name, sizeof b.name, stdin);
Also, you must check the return values particularly from user input functions such as fgets and scanf.
Additionally there are faults waiting to happen with the input of the book title here
fgets(b.name, sizeof b.name, stdin);
It retains the newline which will be part of the data. Please see Removing trailing newline character from fgets() input
When you make a loop to input more books, it will catch the newline left in the buffer by scanf. Please see Please see scanf() leaves the newline char in the buffer.
So I suggest you replace that line with
if(scanf("%49[^\n]", b.name) != 1)
exit(1);
It is best not to mix the input methods: stick to one.

c - scanf not storing input properly

My code looks like this:
int nameFull;
printf("What is your name?\n");
scanf("%d\n", &nameFull); \\up until here it seems to work
printf("Hello %d", nameFull);
return 0;
But my output every time I run the program is "Hello 0" no matter what I input.
Does anyone know how to fix this?
First of all scanf() doesn't emit a prompt so its not a good idea to use any trailing whitespace character in the format string like \n here , It will cause it to read and discard character until next non-whitespace character.
To read a name you can do it like :
char name[50];
scanf("%49s",name); // 49 to limit the buffer input to prevent buffer overrun , this is a security issue.
You should also check the return value of scanf to see if the operation was successful. Personally , I don't prefer using scanf() at all because of various potential problems. It takes as input only what the program author expects it to, not considering other inputs which user might accidentally input. Check out here and here. Also check the scanf() man page
A better and safer method would be use fgets(),
fgets(name,sizeof(name),stdin);
You want to read a string, but you are an integer to store the input. That's not the right approach.
A better aproach would be to use an array of characters, to store the string in it.
char nameFull[100]; // can store up to 100 characters, 99 + 1 for the null-terminator ideally
Now, you could use scanf, like this:
scanf(" %99[^\n]", nameFull);
Note that I used 99, as a guard for not overflowing your array nameFull, if the user inputs too many characters for the size of your array. I didn't use %s, which would stop at a whitespace, and you seem to want to input a full name, which is usually two words and a space in between.
An alternative would be to use fgets(), which provides more safety, like this:
fgets(nameFull, sizeof(nameFull), stdin)
It will read the whole line though and store the trailing newline, while scanf() will read a single string.
Moreover, use the string identifier to print, not the integer one (%s is for string, %d is for integers). Like this:
printf("Hello %d", nameFull);
to this:
printf("Hello %s", nameFull);
as discussed about the string format.
%s reads a string of characters.
%d reads a integer.
So, your correct code will be like following code :
#include <stdio.h>
int main(){
char nameFull[100];
printf("What is your name?\n");
scanf("%99s", nameFull); //to avoid potential buffer overflow
printf("Hello %s\n", nameFull);
return 0;
}
N.B: Check this comment for nice explanation.
Well, int stores a number, a name is not a number. A name is a set of characters (aka strings). So this program would work (no error checking and such since you are in an introductory course):
char name[1024]; // 1024 is more than enough space for a name
scanf("%s", name); // %s reads a string of characters
printf("Hello %s\n", name);
return 0;
You are trying to assign an array of character (commonly referred as string) to an integer variable.
That's not correct.
Just change your variable as such
char nameFull[1024] = {0};
And then use scanf(3) with the appropriate format specifiers for strings, which is %s
scanf("%s", nameFull);
Normally you would check for the return of scanf to know if errors occurs, and in such cases, handle them.
Anyway, I would advice you to use fgets(3) which prevents buffer overflow
char *fgets(char *s, int size, FILE *stream);
fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A terminating null byte (aq\0aq) is stored after the last character in the buffer.

Files in C, accessing pointers, reading and writing in files

I'm trying to make a program in C which tracks the books borrowed by a student. I am having a hard time in accessing pointers with files. When I use files, I don't usually you fscanf( ), instead I use the usual scanf. I have this data struct:
typedef struct{
char fName[24], mInitial, lName[16];
}nameType;
typedef struct{
unsigned long idNo;
nameType studName;
char course[8];
int yrLevel;
books borrowedBooks;
int bksCtr;
}student;
typedef struct{
student *studs;
int studCtr;
}studList;
I have created two functions as of now, which is addStudToFile(void), which adds students to the file, and displayStudsFromFile(void), which basically prints out the students that were added in the file. These are my newbie function code:
void addStudToFile(void)
{
FILE *fp;
studList myStud;
fp = fopen("students.db", "w");
if(fp!=NULL){
/* ask for student details and adds these to the file */
printf("Enter ID number: ");
fflush(stdin);
scanf(,"%lu", &myStud.studs->idNo);
printf("Enter First Name: ");
fflush(stdin);
gets(myStud.studs->studName.fName);
printf("Enter Last Name: ");
fflush(stdin);
gets(myStud.studs->studName.lName);
printf("Enter Middle Initial: ");
fflush(stdin);
scanf("%c", &(myStud.studs->studName.mInitial));
printf("Enter Course: ");
fflush(stdin);
gets(myStud.studs->course);
printf("Enter Year: ");
fflush(stdin);
scanf("%d", &(myStud.studs->yrLevel));
fwrite(&myStud, sizeof(studList),1,fp);
fclose(fp);
}
}
and
void displayStudsFromFile(void)
{
FILE *fp;
studList myStud;
fp = fopen("students.db", "r");
if(fp!=NULL){
while (fread(&myStud, sizeof(studList), 1, fp)){
printf("%lu\t %s, %s %s\t %s-%d", myStud.studs->idNo, myStud.studs->studName.lName,
myStud.studs->studName.fName, myStud.studs->studName.mInitial,
myStud.studs->course, myStud.studs->yrLevel);
printf("borrowed %d books", myStud.studs->bksCtr);
}
fclose(fp);
}
}
Now, my problem here is in accessing my List which is myStud. In my addStudToFile( ) function, everytime I input my ID number, my program stops working. Why does it stops working? Do I have to malloc something? Or is my accessing in scanf() wrong? Another situation where I encounter my program to stop working again, is when I call my display function. It displays something, but alien/garbage values.
Here is a screenshot on where I encountered my problem in my scanning function:
And here is on my display function:
I hope someone can help me with this. Thanks!
Your hunch is right, you do need to malloc something :)
typedef struct{
student *studs;
int studCtr;
}studList;
Here's your problem. You're defining studs as a pointer to a student struct, but you are not actually allocating any memory for it, so you can later reference it with the -> operator.
You can either allow for a preset number of entries, so you could then define studs like,
student studs[10];
to allow for 10 entries, or in addStudToFile() you could ask the user to input how many entries he would like to give. In this case you would leave the definition as it is and as soon as you have the user input do:
myStud.studs = (student *) malloc( sizeof(student) * how_many );
There may be more bugs along the code you have posted, but for the time being the above is what keeps you back.
edit: if you follow the malloc() route, before returning from addStudToFile() for whatever reason you should make sure you call
free(myStud.studs);
or you get a memory leak...
Update
All right, going further down, when you fwrite() everything, remember, you malloc()ed the memory for studs. sizeof(studlist) is computed at compile time and can't possibly know of the additional memory used at run time. In addition, the two memory regions are not guaranteed to be continuous, so still, one fwrite wouldn't cut it.
With your code structured as it is, you would be better off fwrite()ing the studCtr first, then the memory you malloced for studs.
For the displayStudsFromFile() since there is just a loop there and nothing is really stored for later, I'd just use
student myStud;
ie, use just one instance of student structure instead of a studlist. In this scenario you do one fread() to read in the studCtr from the disk file and then use that to loop around fread() for one student object at a time into myStud. Within that loop you print the fields of interest like so:
printf("borrowed %d books", myStud.bksCtr);
Hope this will get you going... First steps in C are a bit tough :D
myStud.studs is a pointer to a student, but I don't see where you're actually allocating that student. You need to malloc a student before you can do things like &myStud.studs->idNo.
In short, don't write pointers to files, they will be meaningless later on.
The typical approach is to write out the count of the items first, then loop over each item in the list and write them out individually.
On the reader end:
read the number of items.
Allocate enough memory to hold all the items.
Read each item in.
along with the problems mentioned already,
this function has its' own set of troubles.
I have inserted '<--' and a comment at each problem
fflush(stdin) though works on some implementations, it's still undefined behaviour.
According to the standard, fflush only works with output/update streams
( for your code, since the printf format strings do not end in '\n'
( which would have forced the actual output to occur
( change these lines to 'fflush(stdout)'
A ' ' in a scanf() format string will consume any white space found at that
point in the input. Therefore, for almost all cases, the first char in
the format string should be: ' '. Then newlines, spaces, etc
will be consumed, as if they were never there. It is even correct to
use the leading ' ' when there is no white space to consume.
gets() is depreciated and will corrupt/overrun a input buffer, so NEVER
use gets, rather, use fgets(), where the amount of input can be limited
and similar good things.
void addStudToFile(void)
{
FILE *fp;
studList myStud;
fp = fopen("students.db", "w");
if(fp!=NULL)
{
/* ask for student details and adds these to the file */
printf("Enter ID number: ");
fflush(stdin); <-- change to stdout
scanf(,"%lu", &myStud.studs->idNo);
<-- change format string to: " %lu"
<-- add check of returned value to assure operation successful
printf("Enter First Name: ");
fflush(stdin); <-- change to stdout
gets(myStud.studs->studName.fName);
<-- replace gets with fgets() +appropriate parms)
<-- add check of returned value to assure operation successful
printf("Enter Last Name: ");
fflush(stdin); <-- change to stdout
gets(myStud.studs->studName.lName);
<-- replace gets with fgets() +appropriate parms)
<-- add check of returned value to assure operation successful
printf("Enter Middle Initial: ");
fflush(stdin); <-- change to stdout
scanf("%c", &(myStud.studs->studName.mInitial));
<-- replace format string with " %c"
<-- add check of returned value to assure operation successful
printf("Enter Course: ");
fflush(stdin); <-- change to stdout
gets(myStud.studs->course);
<-- replace gets with fgets() +appropriate parms
<-- add check of returned value to assure operation successful
printf("Enter Year: ");
fflush(stdin); <-- change to stdout
scanf("%d", &(myStud.studs->yrLevel));
<-- change format string to: " %d"
<-- add check of returned value to assure operation successful
fwrite(&myStud, sizeof(studList),1,fp);
<-- add check of returned value to assure operation successful
fclose(fp);
<-- add else clause so use knows what happened. I.E.
} else { perror( "fopen failed for write"); exit(EXIT_FAILURE);
} // end if
} // end function: addStudToFile
Here are my comments, prefixed by '<--'
void displayStudsFromFile(void)
{
FILE *fp;
studList myStud;
fp = fopen("students.db", "r");
if(fp!=NULL)
{
while (fread(&myStud, sizeof(studList), 1, fp))
<-- add check of returned value to assure operation successful
{
printf("%lu\t %s, %s %s\t %s-%d",
myStud.studs->idNo,
myStud.studs->studName.lName,
myStud.studs->studName.fName,
myStud.studs->studName.mInitial,
myStud.studs->course,
myStud.studs->yrLevel);
printf("borrowed %d books", myStud.studs->bksCtr);
}
fclose(fp);
<-- to let user know about error
<-- insert: }else{ perror( "fopen failed for read"); exit(EXIT_FAILURE);
} // end if
} // end function: displayStudsFromFile

C - If else scanf not working as expected

I'm new to coding in general, and very new to C.
I'm trying to write a program in c that asks the user for input and based on that users input, prints specific text to a .txt file. Please have a look at my code and let me know what I'm doing wrong.
Please have a look at my code below. Thanks very much for your assistance.
Matt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * fptr;
int main(){
char name[32];
char partNum[32];
char desc[250];
char ans1;
char ans2;
char sn[50];
char ansRep;
fptr = fopen("C:\\Users\\mgreene\\Documents\\EmailTemplates\\QCIssue.txt", "w");
if (fptr ==0)
{
printf("Error--file could not be opened\n");
exit(1);
}
printf("What is the customer's first name?\n");
scanf("%s", name);
printf("With which Part number is the user experiencing difficulties?\n");
printf("Enter Part Number:");
scanf("%s", partNum);
printf("Please enter a brief description of the problem\n");
scanf("\n%s", desc);
printf("Does the product have a serial number?\n");
scanf("%c", &ans1);
if (!strcmp(&ans1, "y")== 0)
{
printf ("Do you know the serial number?\n");
scanf("\n%c", &ans2);
if (!strcmp(&ans2, "y")==0)
{
printf ("Please enter the SN:\n");
scanf("\n%s", sn);
fprintf(fptr, "\nHi %s,\n\nI hope this message finds you well.\n\nI write to you today as the Quality Manager at Blank. I received a report that you're experiencing difficulties with part: %s, %s; specifically, the report indicates that %s. Is that an accurate description of the problem? Firstly please accept my apologies on behalf of Blank for the difficulties you're experiencing with this part. As an ISO9001:2008 compliant organization, Blank takes all issues related to customer satisfaction very seriously. It is our intention to resolve this matter as soon as is possible.\n\n", name, partNum, sn, desc);
}
else
{
fprintf(fptr, "\nHi %s,\n\nI hope this message finds you well.\n\nI write to you today as the Quality Manager at Blank. I received a report that you're experiencing difficulties with part: %s; specifically, the report indicates that %s. Is that an accurate description of the problem? Firstly please accept my apologies on behalf of Blank for the difficulties you're experiencing with this part. As an ISO9001:2008 compliant organization, Blank takes all issues related to customer satisfaction very seriously. It is our intention to resolve this matter as soon as is possible.\n\nBefore I can begin an investigation into this problem, I'll need the serial number from that unit. Can you please forward me the serial number as soon as you're able? Once I have that, I can begin the investigation on our end. Thanks.\n\n", name, partNum, desc);
}
}
else if (strcmp(&ans2, "y")==0)
{
printf("Will Blank be sending the customer a replacement? Please enter y or n\n");
scanf("\n%c", &ansRep);
if (!strcmp(&ansRep, "y")==0)
{
fprintf(fptr, "Blank can send you a replacement product as soon as is possible. In order to ensure that the replacements are shipped to the correct address, will you please confirm you shipping address via email? Thanks.\n\n");
fprintf(fptr, "Thank you for your assistance in resolving this matter. Please let us know if you have any additional questions, comments, or concerns about this specific issue or any issues related to products distributed by Blank.\n\n");
fprintf(fptr, "Have a great day!");
}
else
{
fprintf(fptr, "Thank you for your assistance in resolving this matter. Please let us know if you have any additional questions, comments, or concerns about this specific issue or any issues related to products distributed by Blank.\n\nHave a great day!");
}
}
fclose (fptr);
return (0);
}
if (!strcmp(&ans1, "y")== 0) is wrong, which may be modified to if(ans1 != 'y'). You should do similar modifications to if (!strcmp(&ans2, "y")==0), if (strcmp(&ans2, "y")==0), if (!strcmp(&ansRep, "y")==0) in your code.
And for scanf("%c", &ans1);, you may rewrite it as follows:
scanf(" %c", &ans1);
Removing \n in scanf("\n%s" [...] and adding a space before %c in scanf("%c" and scanf("\n%c" (removing \n) may help.
you could create a simple function to catch strays from scanf
void clear_input_buffer(void)
{
char buffer[100];
fgets(buffer, 100, stdin);
}
then include it after scanf
scanf("%s", name);
clear_input_buffer();
First things first: ans1 and ans2 are chars; you are doing strcmp(&ans2, "y") - here, "y" is a string (NULL terminated array of characters) because it is in double quotes. Before anything else, you should replace all your comparisons of those variables with something like
if(ans1 == 'y')
Also, when you read a character you should add a space in front of the %c just in case there is some whitespace or a stray new line from previous input - scanf(" %c", &ans1);
Short answer: I think your strings contain garbage!
Strings in C must be terminated by a Null byte ('\0'). When you create a char array on the stack (or heap) the contents of that array may be filled with whatever junk your memory happened to have at the time. Try running this small program to see what I mean. One might predict this program will print 3 blank lines, but it should instead print 3 lines of random garbage (every time you run this program the garbage should be different).
#include <stdio.h>
int main(){
char name[32];
char partNum[32];
char desc[250];
printf("%s\n", name);
printf("%s\n", partNum);
printf("%s\n", desc);
}
There are a few things you could improve in the program you've posted, but to specifically address your string containing garbage, here is a simple solution:
Replace lines like char name[32]; to char *name = calloc(32, sizeof char); and be sure to free these memory allocations at the end of your program like this free(name).
calloc sets all the memory it allocates to NULL so your strings will no longer contain garbage.
If you are experiencing garbage in your output file, that should do the trick.
Also note
You are using fixed size char arrays. What happens if a user decides to type something in thats longer than you expected? The input will bleed into other parts of memory and can affect the values of other variables.

Address booking and writing to file

#include <stdio.h>
#define TRUE 1
#define FALSE 0
typedef struct contact {
char firstname [40];
char lastname [40];
char address [100];
char phone[10];
}contact;
int main ()
{ FILE *pFile;
contact entry = {""};
int choice, firstname_flag = TRUE, lastname_flag = TRUE, address_flag = TRUE, phone_flag = TRUE;
pFile = fopen("C:\\contacts.txt", "a+");
if(!pFile){
printf("File could not be open.");
return 1;
}
do{
printf("Choose a selection:\n\n");
printf("1. First name:\n");
printf("2. Last name:\n");
printf("3. Address:\n");
printf("4. Phone number:\n\n");
scanf( "%d", &choice);
}while((choice < 1 || choice > 4));
switch (choice){
case 1:
firstname_flag = FALSE;
printf("Please enter first name: \n");
scanf("%s", &entry.firstname);
break;
case 2:
lastname_flag = FALSE;
printf("Please enter last name: \n");
scanf("%s", &entry.lastname);
break;
case 3:
address_flag = FALSE;
printf("Please enter address: \n");
scanf("%s", &entry.address);
break;
case 4:
phone_flag = FALSE;
printf("Please enter phone number: \n");
scanf("%s", &entry.phone);
break;
default:
break;
}
printf("\nYou will now be asked to enter the other items. \n\n");
if(firstname_flag){
printf("Please enter first name: \n");
scanf("%s", &entry.firstname);
}
if(lastname_flag){
printf("Please enter last name: \n");
scanf("%s", &entry.lastname);
}
if(address_flag){
printf("Please enter address: \n");
scanf("%s", &entry.address);
}
if(phone_flag){
printf("Please enter phone number: \n");
scanf("%s", &entry.phone);
}
fwrite (here)
fclose(pFile);
getchar();
return 0;
}
Here is the code I have so far. First of all is there anything blatant that pokes out as being invalid or wrong practice etc? 2nd I want to write first name,last name,address, and Phone # to a file. I'm unsure if I need to fwrite "entry" or not. Also, I have noticed when selecting Address first that It's almost like the buffer isn't empty and what I put after the space i.e. 123 Park , Park would be used as the first name wrongly and the next entry I would put in would be Last name. Any suggestions on the code usage and anything at all would be greatly appreciated. Thanks again
1
N° 1. In response to: “invalid or wrong practice.” Some of these are more matters of taste…
If you ‘must’ use scanf, don't point it at a string buffer with %s: specify the length of the buffer with something like %32s to reduce (but perhaps not eliminate) someone from just typing too much and crashing your program (or worse…) — But, Read N°3 below for more on this question…
If you're developing something open-source, or for personal use, GNU readline is a very nice option (but it is GPL not LGPL, so it can't be used in "non-libre" works…)
Your structure initializer doesn't cover all the elements. You could use {"", "", "", ""}
Did you mean fwrite(entry)?
If you're checking for missing fields before writing the file, you might want to leave aside the bank of flags, and instead loop on the "invalid condition."
while ('\0' == entry.firstname[0]) {
printf("Please enter first name: \n");
scanf("%40[^\r\n\0\04]", &entry.firstname[0]);
}
No need to open the file so early, and leave it open while waiting for user interaction. Opening the file in a+ mode is reasonably "dangerous" (see man lockf for the skinny), because someone else might try to write to the file while you are; leaving it open in this mode for a long time increases the risk.
You should probably use strerror(errno) to provide the user the details of a failing system call, such as when checking the return codes of fopen, fwrite, and fclose. Due to the way buffered I/O works, fclose could even be reporting a problem that occurred with fwrite under some circumstances.
Print your error messages to stderr using fprintf (stderr,…); instead of the output stream …
If you are going to use flags to indicate that the data is "valid" (or, at least, that it may be), you should probably do so after the user tries to enter it, instead of before.
Functions are your friends … I would probably break up something like this by using a function to collect the user's input (something like prompt_for_field ("first name", &entry.firstname);), a function to check for missing records and prompt for them, and a function to write the record to the file, at least …
It's usually considered good form to exit from main, rather than return, for example by using exit(EXIT_SUCCESS)/exit(EXIT_FAILURE). I believe the idea is to support esoteric and possible extinct systems who might treat some value(s) other than 0 as a successful status code (VMS, perhaps?), but regardless, it's easier to read :-)
2
And N°2, yes, you can fwrite(entry), and as long as you never change the definition of struct contact, you should be able to read it back in all right. Over time, you'll probably want to switch to a more "plain text" type format (#include <json-xml-init-religious-war>), but in this small example, there isn't a pressing need to introduce such complexity.
3
Finally, N°3, you should probably use &entry.address[0] to get the address of the start of a char[] but most significantly: scanf %s does not read a string. It looks like printf %s, but it's not…
s Matches a sequence of non-white-space characters; the next
pointer must be a pointer to character
array that is long enough to hold the input sequence and the terminating null character ('\0'),
which is added automatically. The input string stops at white space or at the maximum field width,
whichever occurs first.
See that "non-white-space?" That's what's got you. The rest of your input (after the first whitespace) is left in the keyboard buffer, waiting for another scanf to read it. A good('ish) way to read from the terminal and accept whitespace is %40[^\r\n\0\04], replacing 40 with the size of your string buffer (char[]). That means, accept (up to) 40 characters, as long as they are none of: carriage return, new line, the null byte, or end-of-file code (^D).
All-in-all, you look to be on the right track, though. Good luck :-)

Resources