Issue using struct in for-loop - c

This is a homework question. My compiler is CodeBlocks.
Here is my code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Address{
char number[5];
char street[30];
char city[30];
};
struct Employee{
char ID[7];
char name[31];
struct Address *addr;
};
int main(){
int n,i;
char temp[7];
printf("Enter number of Employee : ");
scanf("%d",&n);
struct Employee **p=(struct Employee **)malloc(n*sizeof(struct Employee *));
for (i=0; i<n; i++)
{
p[i]=(struct Employee *)malloc(sizeof(struct Employee));
p[i]->addr=(struct Address *)malloc(sizeof(struct Address));
}
for(i=0; i<n; i++)
{
printf("Employee #%d\n",i+1);
printf("Enter ID : ");
gets(p[i]->ID);
printf("Enter Name : ");
gets(p[i]->name);
printf("Enter Home number : ");
gets(p[i]->addr->number);
printf("Enter Street : ");
gets(p[i]->addr->street);
printf("Enter City : ");
gets(p[i]->addr->city);
}
}
My problem is that when I run this code, I cannot enter the ID for the #1 employee; however, I can enter in the ID for employee #2 and #3.
Where is my problem?

There seems to be some issue with gets() reading something from the console before the first pass of the loop.
Adding gets(temp); right before the loop seems to fix it. A better solution would be to use something other than gets().

The initial scanf("%d", &n); doesn't consume the trailing newline, so it's left available for the gets() call.
Incidentally, never use gets(). It cannot be used safely. For example, if you're reading into a 6-byte array, and the user enters 10 characters, you have a buffer overflow. Consider using fgets() instead (but note that, unlike gets(), it leaves the '\n' character in the buffer).

You should ever explicit clear the input buffer after any user-input. And you should make your inputs safe with size limiter. And you should use the return value from scanf.
scanf("%d",&n);while(getchar()!='\n');
...
scanf("%6[^\n]",p[i]->ID);while(getchar()!='\n');
...
scanf("%30[^\n]",p[i]->name);while(getchar()!='\n');
...
scanf("%4[^\n]",p[i]->addr->number);while(getchar()!='\n');
...
scanf("%29[^\n]",p[i]->addr->street);while(getchar()!='\n');
...
scanf("%29[^\n]",p[i]->addr->city);while(getchar()!='\n');

Related

printf will not print output of %d correctly for an int

Can't figure out why my printf output won't print the int data.age or addr.zip correctly. They're defined as int, so %d should work...but it doesn't. I get gibberish numbers for the output. All other fields work perfectly.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct BillingAddress {
char *street[50];
char *city[25];
char *state[3];
int *zip[6];
}address;
address addr;
typedef struct ContactInfo {
char *name[30];
int *age[3];
char *phone[15];
struct BillingAddress PersonalData;
}personaldata;
personaldata data;
int main()
{
printf("Enter your full name: ");
scanf(" %49[^\n]", &data.name);
printf("Enter your age: ");
scanf("%d", &data.age);
printf("Enter your Phone Number (xxx) xxx-xxxx: ");
scanf(" %14[^\n]", &data.phone);
printf("Enter your street address: ");
scanf(" %49[^\n]", &addr.street);
printf("Enter your city: ");
scanf(" %24[^\n]", &addr.city);
printf("Enter your state abbreviation: ");
scanf("%s", &addr.state);
printf("Enter your zip code: ");
scanf("%d", &addr.zip);
printf("Personal Data: \n %s\n %d\n %s\n %s\n %s\n %s\n %d\n", data.name, data.age, data.phone, addr.street, addr.city, addr.state, addr.zip);
}
Let's go step by step. In your BillingAddress struct definition, you intend to store the street, city, and state. It seems logical that you could represent all of those parameters as strings (which are character arrays in C). I believe that is what you tried to do, but the declaration:
char *street[50];
represents give you an array of 50 char * (i.e., char pointers) NOT 50 chars, which is what you actually want. So, the struct definition should instead be:
typedef struct BillingAddress {
char street[50];
char city[25];
char state[3];
int zip;
} address;
You also intend to store the zip. Note how I changed the type of zip to an int array rather than an int array. You could do an int array, but you would have to do more work to properly accept the user's input (simply using scan("%d", &addr.zip) will not work).
Now, let's take a looked at a different way to define your definition for ContactInfo struct:
typedef struct ContactInfo {
char name[30];
int age;
char phone[15];
address addr;
} personaldata;
You can see that I've removed the *'s and changed age to be a single int for the similar reasoning as what I mentioned above. I've also replaced struct BillingAddress with the simpler address. Why? Because you created a typedef linking the keyword address to struct BillingAddress. So, by using address alone, the code looks a bit cleaner and you are putting that typedef to good use :D (Note that there's nothing incorrect about using struct BillingAddress, I just think it looks cleaner to utilize the typedef).
Also, you'll see that I renamed the variable of type address (i.e., of type struct BillingAddress -- remember the typedef means these two are the same) to addr. This makes more sense than naming it PersonalData as you did, because well, it's an address, not arbitrary personal data.
Now moving onto your main() method. You should be aware of some of the pitfalls of using scanf(). Since it reads from the default input stream stdin (i.e., most likely your terminal), any characters not gulped up by scanf() will be left in the input stream. So, any subsequent calls to scanf() will also read in those unwanted characters. See this post for more info. You might not have run into this if you supplied the less than the max number of desired characters, but it is important to take care of this error case. So, after each scanf(), you should clear the input stream, which can be done using a method like:
void clear_input_stream()
{
int c;
while ((c = fgetc(stdin)) != '\n' && c != EOF);
}
You can call this method after each one of your scanf() calls.
You want to make sure that if you are writing into a char array you should not add the & in front of the variable you are writing to -- check this answer for an explanation (your compiler should warn you about that).
The last thing I want to mention is that you could also add a length to the %d specifier to limit reading an integer of a certain length. Your main() could look something like this:
int main()
{
printf("Enter your full name: ");
scanf(" %49[^\n]", data.name);
clear_input_stream();
printf("Enter your age: ");
scanf(" %3d", &data.age);
clear_input_stream();
printf("Enter your Phone Number (xxx) xxx-xxxx: ");
scanf(" %14[^\n]", data.phone);
clear_input_stream();
printf("Enter your street address: ");
scanf(" %49[^\n]", addr.street);
clear_input_stream();
printf("Enter your city: ");
scanf(" %24[^\n]", addr.city);
clear_input_stream();
printf("Enter your state abbreviation: ");
scanf(" %2[^\n]", addr.state);
clear_input_stream();
printf("Enter your zip code: ");
scanf(" %5d", &addr.zip);
clear_input_stream();
printf("Personal Data: \n %s\n %d\n %s\n %s\n %s\n %s\n %d\n", data.name, data.age, data.phone, addr.street, addr.city, addr.state, addr.zip);
return 0;
}

C compiler error: undefined reference to function

After I execute the exe I get this error :
undefined reference to `StudentScan'
error: ld returned 1 exit status|
Note: I'm bad and new to coding so don't mind my bad coding please^^
Note2: I'm just messing with random functions.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main() {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
return 0;
}
The posted code has defined StudentScan() within main(). But nested function definitions are not allowed in C. This should generate a compiler warning, such as:
warning: ISO C forbids nested functions [-Wpedantic]
void StudentScan(int i, struct student list[])
Pay attention to all compiler warnings and fix them. If no warning is seen when compiling this code, turn up the level of compiler warnings. On gcc, I suggest to always use at least gcc -Wall -Wextra, and I always add -Wpedantic. The -Wpedantic is needed with gcc to see a warning for this. Some compilers, and gcc is one of these, do support nested function definitions as a compiler extension. Still, this feature is nonstandard, and it is best to not rely on it.
The fix is simple: move the definition of StudentScan() out of main():
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
struct student *studentp;
printf ("\nEnter the host of students: ");
scanf ("%d ", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
StudentScan(i,studentp);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{ printf("\nEnter first name : ");
scanf("%s", list[i].firstName);
printf("\nEnter average number: ");
scanf("%s", list[i].AverageNum);
}
Also note that you should always specify maximum widths when reading strings using scanf() family functions with %s or %[] to avoid buffer overflow. For example:
scanf("%19s", list[i].firstName);
Note that 19 is used, even though the firstName field is an array of 20 char values. Remember that one space must be reserved for the \0 terminator. And since you are using %s to read a string into the AverageNum field, you should also have:
scanf("%1s", list[i].AverageNum);
That is, this field can only hold one digit. If the intention is to hold two digits, this field must be changed within the struct to: char AverageNum[3].
And while we are discussing scanf(), note that this function returns the number of successful assignments made during the function call. If no assignments are made, 0 is returned. This return value should always be checked. Consider: if the user mistakenly enters a letter when a digit is expected, nothing is stored in the intended variable. This may lead to undefined behavior. You may try something like this to validate numeric input:
printf ("\nEnter the host of students: ");
while (scanf ("%d ", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
This code asks the user to enter input again if a number is not entered when expected. Note that if the user does enter a non-digit, this character remains in the input stream and must be cleared before attempting to process more user input. The while loop is a typical construction which accomplishes this task.
Edit
Based on comments made by the OP, here is a modified version of the posted code. This version uses a float value instead of a character array for the AverageNum field of the struct. A floating-point type may be more useful than an integer type for storing averages. It is usually best to use double for floating-point values, but in this case it looks like AverageNum has little need for precision (the char array was intended to hold only two digits); float is probably sufficient for this use. If a different type is desired, it is simple enough to modify the code below.
Some input validation is implemented, but note that more could be done. The user is prompted to enter a number when non-numeric input is found where numeric input is expected. The input stream is cleaned with the while loop construction after such an input mistake; it would be good to remove this code to a separate function called clear_input(), for example.
If the user signals end-of-file from the keyboard, scanf() will return EOF; the code below chooses to exit with an error message rather than continue with malformed input in this case. This could also occur with input redirected from a file, and this condition may need to be handled differently if such input is expected.
The loop that populated the list[] array seemed to be operating inefficiently, asking for AverageNum twice in each pass. This has been streamlined.
Note that the call to malloc() can be rewritten as:
studentp = malloc(length * sizeof *studentp);
This is a very idiomatic way of writing such an allocation. Here, instead of using an explicit type as the operand of sizeof, that is, instead of sizeof (struct student), the variable which holds the address of the allocation is used. sizeof only uses the type of the expression *studentp, so this variable is not dereferenced here. Coding this way is less error-prone and easier to maintain when types change during the maintenance life of the code.
Yet, it is unclear why memory is allocated for studentp in the first place. In the posted code, both the firstName and AverageNum fields are filled for members of the dynamically allocated studentp in calls to StudentScan() in a loop; the same loop fills the AverageNum field of the members of list[] (a different array of structs) with different input. There seems to be no need for one of these arrays of student structs; I have commented-out the dynamically allocated array in favor of the statically allocated version.
Here is the modified code:
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
float AverageNum;
};
void StudentScan(int, struct student[]);
void StudentPrint(int, struct student[]);
int main(void) {
int i;
int length;
// struct student *studentp;
printf ("\nEnter the host of students: ");
while (scanf ("%d", &length) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
struct student list[length];
/* This is fine */
// studentp = malloc(length * sizeof (struct student));
/* But this is better */
// studentp = malloc(length * sizeof *studentp);
// if (studentp == NULL)
// {
/* Not wrong, but... */
// printf("Out of memory!");
// return 0;
// fprintf(stderr, "Allocation failure\n");
// exit(EXIT_FAILURE);
// }
for(i = 0; i < length; i++) {
StudentScan(i, list);
}
/* Code to display results here */
// free (studentp);
return 0;
}
void StudentScan(int i, struct student list[])
{
putchar('\n');
printf("Enter first name: ");
if (scanf("%19s", list[i].firstName) != 1) {
puts("Input error");
exit(EXIT_FAILURE);
}
printf("Enter average number: ");
while (scanf("%f", &list[i].AverageNum) < 1) {
puts("Please enter a number");
int c;
while ((c = getchar()) != '\n' && c != EOF) {
continue;
}
}
}
You have to remove the scan function from the main. Also there is not a printstudent function you are declaring. You must remove /n from the printf and the scanf functions and place them accordingly. You can then test if your data are being added correctly in your struct with a simple loop.
#include <stdio.h>
#include <stdlib.h>
struct student {
char firstName[20];
char AverageNum[2];
};
int main() {
int i=0;
int length;
struct student *studentp;
printf ("Enter the host of students:");
scanf ("%d", &length);
struct student list[length];
studentp=malloc(length*sizeof(struct student));
if (studentp==NULL)
{
printf("Out of memory!");
return 0;
}
for(i = 0; i < length; i++) {
printf("Enter first name :");
scanf("%s", list[i].firstName);
printf("Enter average number: ");
scanf("%1s", list[i].AverageNum);
}
for(i = 0; i< length; i++){
printf("number of host is: %d , his/her first name: %s , his/her avg number: %s \n", i, list[i].firstName, list[i].AverageNum);
}
free (studentp);
return 0;
}

An access violation (segmentation fault) was raised in your program

how many students : 2 (it works fine)
how many students : 4 (it gives error "An access violation (segmentation fault) was raised in your program."
why it is happening with me, i have spent 4 hours but could not figure it out.
#include <stdio.h>
struct student
{
int rollno;
char name[20];
};
int main()
{
int n,i,j;
struct student detail[n];
printf("how many students: ");
scanf("%d",&n);
fflush(stdin);
for(i=0; i<n; i++)
{
printf("enter student no.%d\n",(i));
printf("Name: ");
gets(detail[i].name);
printf("Roll No: ");
scanf("%d",&detail[i].rollno);
fflush(stdin);
}
for(i=0; i<n; i++)
{
printf("Student no. %d Detail\n",(i+1));
printf("Name:\t\t%s \nRoll No: \t%d\n",detail[i].name,detail[i].rollno);
}
getch();
}
In your code, the primary issue is
int n,i,j;
struct student detail[n];
you're using n uninitialized. It invokes undefined behavior. You need to move the definition of detail[n]; after you have scanned the value from the user.
That said,
Check for the return value of scanf() to ensure success.
gets() is dangerous because it can cause buffer overflow. Use fgets() instead.
As per the standard, fflush(stdin) is UB, remove that.
getch() should be getchar(), if only stdio.h is included.

Printing an int value obtained from user

The problem is at the age part, the compiler does not give me any errors but when I run it it prints a random number for int age
printf("Enter your name:");
scanf(" %s",&name1);
int age;
printf("\n\nHow old are you?");
scanf(" %d",&age);
char gender;
printf("\n\nEnter your gender[Male/Female]:");
scanf(" %s",&gender);
char confirmation;
printf("Confirmation: Your name is %s , you are %d years old , and you are a %s.\n\nAnswer[Y/N]:",&name1,age,&gender);
Here is your problem.
char gender;
scanf(" %s",&gender);
gender is a char. That is, it only has memory for a 1 byte character. But you are using it as a string. You probably have the same problem for name1 since you are using & for that as well but can't be sure as you don't show that.
Change that to be something like:
char gender[8] // Enough to fit "Female" and terminating NULL
scanf("%7s", gender);
Extra note: scanf is a bit awkward to use to prevent buffer safety. May consider something like fgets with sscanf instead.
There is also dynamic allocation, where you now do not have to specify the amount of storage to use. Using the length modifier %m with the string type modifier s:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *name = NULL
char *gender = NULL;
int age;
printf("Enter your name: ");
scanf("%ms", &name);
printf("\nHow old are you? ");
scanf("%d", &age);
printf("\nEnter gender: ");
scanf(" %ms", &gender);
printf("\n%s %d %s\n", name, age, gender);
free(name); // free the memory
free(gender); //
return 0;
}
In the last couple of lines you will notice a several calls to free. This is because you are left with the responsiblility to free the memory allocated by scanf.
As pointed out by #Matt McNabb if you are on a non-posix compliant system, this will not work. You can use a in place of m, while including #define _GNU_SOURCE on the first line.

Why doesn't scanf() take inputs from the user while dealing with strings?

My code is as follows
typedef struct
{
char name[15];
char country[10];
}place_t;
int main()
{
int d;
char c;
place_t place;
printf("\nEnter the place name : ");
scanf("%s",place.name);
printf("\nEnter the coutry name : ");
scanf("%s",place.country);
printf("\nEnter the type of the place : Metropolitan/Tourist (M/T)?");
scanf("%c",&c);
printf("You entered %c",c);
return 0;
}
If I run the program, it prompts for place name and country name, but never waits for the character input from user.
I tried
fflush(stdin);
fflush(stdout);
Neither work.
Note : Instead of a character, if I write a similar code to get an integer or a float, it prompts for values and the code works just fine.
int d;
printf("\nEnter the type of the place : Metropolitan/Tourist (M/T)?");
scanf("%d",&d);
Why does this happen? Is there anything wrong in the code?
The problem is that scanf leaves the whitespace following entered non-whitespace characters in the stream buffer, which is what the scanf(%c...) then reads. But wait a second...
In addition to being tricky to get right, such code using scanf is horribly unsafe. You're much better off using fgets and parsing the string later:
char buf[256];
fgets(buf, sizeof buf, stdin);
// .. now parse buf
fgets always gets a full line from the input, including the newline (assuming the buffer is large enough) and you thus avoid the problem you're having with scanf.
You can use string instead of character for scanf.
printf("\nEnter the place name : ");
scanf("%s%*c",place.name);
printf("\nEnter the coutry name : ");
scanf("%s%*c",place.country);
printf("\nEnter the type of the place : Metropolitan/Tourist (M/T)?");
scanf("%c",&c);
printf("You entered %c",c);
Try adding spaces before the % sign in scanf().
I have provided the modified code below.
#include <stdio.h>
#include <string.h>
typedef struct
{
char name[15];
char country[10];
} place_t;
int main()
{
int d;
char c;
place_t place;
printf("\nEnter the place name : ");
scanf(" %s",place.name);
printf("\nEnter the coutry name : ");
scanf(" %s",place.country);
printf("\nEnter the type of the place : Metropolitan/Tourist (M/T)?");
scanf(" %c",&c);
printf("You entered %c",c);
return 0;
}

Resources