Address booking and writing to file - c

#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 :-)

Related

How can I tell the compiler to re execute code at specific point when if statement is true

I'm trying to learn to how to code myself so there're alot of thing that I didn't know.
What I'm trying to do is tell the compiler to re execute the code at specific point when if statement is true
#include <stdio.h>
int main() {
char name[25];
char first_name[25];
char last_name[25];
printf("Please put in your first name here: ");
scanf("%s", first_name);
printf("Please put in your last name here: ");
scanf("%s", last_name);
/*If this statement below is true, I want the compiler to execute the code above */
if (strlen(first_name) > 5 || strlen(last_name) >5)
{
printf("Last name or First name is too long!\n");
}
printf("Welcome %s %s!", first_name, last_name);
return 0;
If you're designing a console application, you might want to consider taking user input from the command line arguments. i.e.
#include <stdio.h>
int main(int argc, char **argv) {
if (argc <= 2) {
fputs("insufficient arguments", stderr);
exit(EXIT_FAILURE);
}
if (strlen(argv[1]) > 5) {
fputs("first name too long", stderr);
exit(EXIT_FAILURE);
}
if (strlen(argv[2]) > 5) {
fputs("last name too long", stderr);
exit(EXIT_FAILURE);
}
printf("Welcome %s %s!", argv[1], argv[2]);
}
This form of input feels much more natural; you don't have to worry about array sizes or object lifetime... not to mention the end user gets to enjoy autocomplete and your software will blend into their ecosystem better, too. I'm sure they'd rather press the "up" arrow to fix a typo in their command than re-enter the entire entry... if you plan on having users, that is... the console doesn't have many, and those who do enjoy highly scriptable software; they'll write their own alternative if you do a poor job.
If you're not convinced, and you still want to use scanf, you need to:
check the return value
bring the input stream to a sanitary state after invalid input
(usually it's best to) read and handle errors for one field at a time
Check the return value
The return value for scanf is the number of objects successfully matched and assigned to, or EOF in the case of some read failure. If the input is not of the format described by your format string, you might get some kind of match failure, and scanf returns. This is particularly troublesome for numeric directives and %[scanset] directives, both of which commonly fail when users make some mistake, which is why it's necessary to bring the input stream to a sanitary state after invalid input.
Bring the input stream to a sanitary state after invalid input
This is done by reading and discarding characters from the stream until we reach some state where the input might successfully match the format string. We could discard one character and try again, for example, or keep discarding until a whitespace is encountered (e.g. scanf("%*[^ ]");). I tend to discard until a newline is encountered (see example below) to mimic the functionality of using fgets+sscanf (this is another option, btw, but you might still need to bring the stream to some sanitary state if you don't get a full line).
Matching multiple fields with one call increases the complexity of error handling. For each field after the first, we must perform the sanitation step and resume matching, which makes our code more bulky and repetitive, something we seek to eliminate. Nonetheless, here's a brief example of trying to read two fields with one call:
void example_1() {
int x, y;
switch (scanf("%d %d", &x, &y)) {
case EOF: exit(0);
case 0: scanf("%*[^\n]"); example();
case 1: for (;;) { // x assigned, y uninitialised
scanf("%*[ ]");
switch (scanf("%d", &y)) {
case EOF: exit(0);
case 0: continue;
}
}
}
}
The more fields, the more nested switches. It's easy to see that this is a terrible way to read two fields, let alone three. Perhaps something like this would be appropriate, per field:
do {
fputs("Please enter your first name: ", stdout);
if (scanf("%24s", first_name) != 1) {
fputs("(most probably) I/O error", stderr);
exit(EXIT_FAILURE);
}
} while (strlen(first_name) > 5 && (fputs("First name too long", stderr),
scanf("%*[^\n]") == 0));
This really only skims the surface of a topic that has dragons in a language that has dragons, which should be a red flag in a red flag to you. If you're not reading a book, or you don't have Kernighan & the late Ritchie themselves (or some professor roughly as reputable) as your professors, then you should get something like that... scanf has too many subtle nuances to just guess your way around it.
Well you can use term Loop instead of re-execute..
Here, in your problem you can use looping statements like do-while loop.
Or else we have other method using jump statements.(goto in this case).
Below is your code.
#include <stdio.h>
#include <string.h>
int main() {
char name[25];
char first_name[25];
char last_name[25];
input:
printf("Please put in your first name here: ");
scanf("%24s", first_name);
printf("Please put in your last name here: ");
scanf("%24s", last_name);
/*here %24s is used to specify the size of the buffer i.e 24
So if you give a string more than 24 characters then %24s takes only
24 characters then rest is ignored */
/*If this statement below is true, I want the compiler to execute the code above */
if (strlen(first_name) > 5 || strlen(last_name) >5)
{
printf("Last name or First name is too long!\n");
goto input;
}
printf("Welcome %s %s!", first_name, last_name);
return 0;
}
But usage of goto statements are not recommended because they make logic complex
Now, you try using do-while loop.

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

fgets printing two lines before input

So I am trying to write a program that will let me read a user input for data on an MP3 file using a doubly linked list data structure. I got most of the methods and functions to work, but when I am prompting the user to put in input it prints out two lines before the user can input for the first line. So for example
int main()
{
int user_input = 0;
while(!(user_input >= 4))
{
struct MP3_data_node* MP3_data;
MP3_data = (struct MP3_data_node*)malloc(sizeof(struct MP3_data_node));
printf("\nPlease select a number for one of the following instructions:\n");
printf("0: add to list\n1: delete from list\n2: print the list from beginning to end\n3: print the list from end to beginning\n4: exit\n");
scanf("%d", &user_input);
if(user_input == 0)
{
printf("Please provide the artist:");
fgets(MP3_data->artist,50,stdin);
printf("Please provide the album:");
fgets(MP3_data->artist,50,stdin);
printf("Please provide the song title:");
fgets(MP3_data->artist,50,stdin);
printf("Please provide the year the song was released: ");
scanf("%d", &MP3_data->yearReleased);
printf("Please provide the length of the song in seconds: ");
scanf("%d", &MP3_data->runTime);
addToList(MP3_data);
}
...
So it prints out "Please provide the artist:Please provide the album:" and then let's me put the input in, so my question is how do I make it so that it prints:
Please provide the artist: (user input)
Please provide the album: (user input)
etc.
You're doing the right thing (fgets) int the first few prompts, then you switch to scanf which is the source of your problem. Use fgets (and strtol) instead of scanf and you will be fine. (And, the first scanf which causes the problem described in your question.)
The problem is that scanf only reads the digit part of whatever you enter. That means if you type 12Enter, then the scanf reads the 1 and 2 but leaves the Enter in the input buffer for the next call to fgets or scanf. On the other hand, fgets reads everything you type including the Enter, avoiding this problem.

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

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.

how to use fgets and sscanf for integers in loop

Beginner with C here. I am trying to run a loop where strings and ints are entered into various fields of a struct. When prompted for a 'last name', the user can press enter with no other input and the loop should end.
The problem is that with this code, the loop doesnt end (last name and first name entry requests run together on the same line) and the value for salary always comes out wrong (0 or some large number)
while (employee_num <= 2)
{
printf("Enter last name ");
fgets(employee[employee_num].last_name, sizeof(employee[employee_num].last_name), stdin);
if(strlen(employee[employee_num].last_name) == 0)
break;
printf("Enter first name ");
fgets(employee[employee_num].first_name, sizeof(employee[employee_num].first_name), stdin);
printf("Enter title ");
fgets(employee[employee_num].title, sizeof(employee[employee_num].title), stdin);
printf("Enter salary ");
fgets(strng_buffer, 1, stdin);
sscanf(strng_buffer, "%d", &employee[employee_num].salary);
++employee_num;
getchar();
}
If I try this code instead, I am able to exit the loop properly after the first run through it, but cannot exit after that (by pressing enter at the last name portion - perhaps a \n I cant seem to clear?):
char strng_buffer[16];
while (employee_num <= 5)
{
printf("Enter last name ");
fgets(strng_buffer, sizeof(strng_buffer), stdin);
sscanf(strng_buffer, "%s", employee[employee_num].last_name);
if(strlen(employee[employee_num].last_name) == 0)
break;
printf("Enter first name ");
fgets(strng_buffer, sizeof(strng_buffer), stdin);
sscanf(strng_buffer, "%s", employee[employee_num].first_name);
printf("Enter title ");
fgets(strng_buffer, sizeof(strng_buffer), stdin);
sscanf(strng_buffer, "%s", employee[employee_num].title);
printf("Enter salary ");
scanf("%d", &employee[employee_num].salary);
++employee_num;
getchar();
}
I am curious as to how to make this work as intended and what best practice would be for entries like this (ie use of sscanf, fgets, etc)
Thanks in advance!
The Loop breaks prematurely when it encounters the break statement
if(strlen(strng_buffer) == 0)
break;
The uninitialized character buffer strng_buffer, coincidently has null as the first character causing strlen to return 0
I believe you may have intended
if(strlen(employee[employee_num].last_name) == 0)
break;
as the loop terminatorm, and it was a typo in your part causing premature loop exit.
Assuming the fix mentioned by Abhijit, why transform the first into the second? Are you aware that the second behaves differently to the first, because of the addition of sscanf? If your intention was to shorten the first, the second seems quite bulky. Rather than adding sscanf to the situation, why not shorten the first by declaring a struct employee *e = employee + employee_num; and using that repetitively, instead of employee[employee_num]?
One "best practise" regarding fgets is to check it's return value. What do you suppose fgets might return, if it encounters EOF? What do you suppose fgets would return if it's successful?
One "best practise" regarding scanf is to check it's return value. In regards to the return value of scanf, I suggest reading this scanf manual carefully and answering the following questions:
int x = scanf("%d", &employee[employee_num].salary); What do you suppose x will be if I enter "fubar\n" as input?
Where do you suppose the 'f' from "fubar\n" will go?
If it's ungetc'd back onto stdin, what would your next employee's last name be?
int x = scanf("%d", &employee[employee_num].salary); What do you suppose x will be if I run this code on Windows and press CTRL+Z to send EOF to stdin?
int x = scanf("%d %d", &y, &z); What would you expect x to be, presuming scanf successfully puts values into the two variables y and z?
P.S. EOF can be sent through stdin in Windows by CTRL+Z, and in Linux and friends by CTRL+D, in addition to using pipes and redirection to redirect input from other programs and files.
The problem is that fgets returns the string with the line break (\n) included. So, even the user presses return without entering info, the string won't be empty. Also, your buffer size for salary is too small.
So, either you strip out the \n on every fgets or you change your check to:
if(strlen(employee[employee_num].last_name) == 1) break;
Also, when you're getting the buffer, change 1 to something bigger, like
fgets(strng_buffer, 10, stdin);
However, if you do want to strip out the \n from each fgets, you can do something like:
employee[employee_num].last_name[strlen(employee[employee_num].last_name)-1] = 0;
You can do this for every string or, better yet, create a function that does it.
EDIT: if you can guarantee that the user will press enter after each input then you can safely assume this. However if it's not always the case it's possible that the last character is not \n and just stripping this way might cause problems.

Resources