Using scanf to create new struct object - c

Hi I'm using to create a simple program that contains a list of Users (based on the struct below), and I'm trying to create new users based on user input, where I ask for each property seperately using scanf. But I'm having trouble with the structs limitations, for example id should be at max 10 chars and nome can have a max of 25 chars. Here's my code for more context:
struct user {
char id[10];
char name[25];
char group;
float score;
};
struct user list[25];
int registered = 0;
void createNewUser() {
struct user *userPtr, newUser;
userPtr = &newUser;
printf("\nId: ");
scanf("%10s", &(*userPtr).id);
printf("\nName: ");
scanf("%25s", &(*userPtr.name);
printf("\nGroup: ");
scanf("%c", &(*userPtr).group);
printf("\nScore: ");
scanf("%f", &(*userPtr).score);
insert(newUser);
printf("%10s\n", list[0].id);
printf("%25s\n", list[0].name);
printf("%c\n", list[0].group);
printf("%.1f\n", list[0].score);
}
void insert(struct user newUser) {
if (registered < 25){
list[registered] = newUser;
registered += 1;
}
}
With the code I presented above, if I type more than 10 chars for the first input, the next 2 are ignored. And my 3rd scanf is always ignored, the one for group. Can anyone here help me out with this?

The problem with scanf is that when it stops converting characters and there are
more in the input buffer (because the user entered more than you anticipated), then scanf will leave those characters there.
Specially the newline character (inputed when the user presses ENTER)
remains in the input buffer, which causes problems to subsequent calls of
scanf that read characters or strings. So in this case you have to "clean" the input buffer,
so that the next scanf does not consume the left overs of the previous scanf calls.
You can use this function after every scanf:
void clean_stdin(void)
{
int c;
while((c = getchar()) != '\n' && c != EOF);
}
Then you can do:
printf("\nId: ");
scanf("%10s", (*userPtr).id); // no need for &, id is char[]
clean_stdin();
printf("\nName: ");
scanf("%25s", (*userPtr).name); // same here
clean_stdin();
printf("\nGroup: ");
scanf("%c", &(*userPtr).group);
clean_stdin();
printf("\nScore: ");
scanf("%f", &(*userPtr).score);
Also note that the way you are if the maximal length of the ID is 10, then the
buffer must be of length 11, because in C you need to terminate the strings with
the '\0'-terminating byte. So change your structure to this:
struct user {
char id[11];
char name[26];
char group;
float score;
};
Also bear in mind, using a pointer like this
struct user *userPtr, newUser;
userPtr = &newUser;
printf("\nId: ");
scanf("%10s", (*userPtr).id);
...
is not necessary, it actually makes the code harder to read. You can do:
void createNewUser() {
struct user newUser;
printf("\nId: ");
scanf("%10s", newUser.id);
clean_stdin();
...
printf("\nScore: ");
scanf("%f", &newUser.score);
...
}

Related

Char parameter in function is null or empty in C

I'm currently learning c, then I'm playing with functions and data types, specifically in this case char[]'s.
The following code I've written declares a function called verifyMessage() and receives two parameters, name and gender.
When I execute the function, I pass the two parameters that the user enters through the console, but when I print the name it doesn't print anything.
#include <stdio.h>
int main() {
int i = 0;
double controlNumber = 21200164;
double number = 0;
char name[50];
char gender[1];
int attempts = 5;
int aux = 0;
do {
printf("Introduzca el numero de control: ");
scanf("%lf", &number);
if (controlNumber == number) {
printf("\nWrite your name: ");
scanf("%s", name);
printf("\nWrite your gender (M/F): ");
scanf("%s", gender);
verifyMessage(name, gender);
break;
} else {
i++;
}
} while (i < attempts);
return 0;
}
void verifyMessage(char name[50], char gender[1]) {
if ('M' == gender[0]) {
printf("\n\Name: %s", name);//Here doesn´t print the name
printf("\nMen");
} else if ('F' == gender[0]) {
printf("\nWoman");
} else {
printf("\nInvalid gender");
}
}
Using char gender[1]; with %s is dangerous because gender has room for only one element, so it can accept only strings upto zero characters (the only room will be occupied by terminating null-character)
On the other hand, %s will read positive-length strings (it cannot read strings with zero characters), so it will cause out-of-range access on successful read.
Allocate enough elements and set the maximum length to read (upto the number of elements minis one for terminating null-character) to avoid buffer overrun.
char name[50];
char gender[2];
/* ... */
printf("\nWrite your name: ");
scanf("%49s", name);
printf("\nWrite your gender (M/F): ");
scanf("%1s", gender);
Checking results (return values) of scanf() to check if they successfully read desired things will improve your code more.

Scan a white space/whole line in c

So, I know this question has been asked before, but I can't seem to make anything work. What I have right now is this:
#include<stdio.h>
struct ClothingCustomer{
char name[20];
int age;
double inseam;
};
struct ClothingCustomer createACustomer(){
struct ClothingCustomer aCustomer;
printf("Enter Customer Name: ");
scanf("%s",aCustomer.name);
printf("Age: ");
scanf("%d",&aCustomer.age);
printf("Inseam: ");
scanf("%lf",&aCustomer.inseam);
return aCustomer;
};
int main(){
FILE* customersFile = fopen("customers.txt","w");
for (int i = 0; i < 5; i++){
struct ClothingCustomer aCustomer = createACustomer();
fprintf(customersFile, "%s %d %lf\n", aCustomer.name, aCustomer.age, aCustomer.inseam);
}
fclose(customersFile);
return 0;
}
No matter what I do to try to make it scan more than one word, like a first/last name or something, it works, but here's what I get in the console while running this(with the scan options to try to get past a white space listed below; the above code functions correctly, but doesn't allow white space):
Enter Customer Name:
Age:
Inseam:
Enter Customer Name: Age:
Inseam: Enter Customer Name: Age:
Inseam:
Enter Customer Name: Age:
Inseam:
Enter Customer Name: Age:
Inseam:
How can I make it not do this? I've tried using:
[^\n]
fgets(name, sizeof(name), stdin);
and the same thing happens every time.
This Will Work
#include<stdio.h>
#include<string.h>
struct ClothingCustomer createACustomer(void);
struct ClothingCustomer{
char name[20];
int age;
double inseam;
};
struct ClothingCustomer createACustomer(void){
struct ClothingCustomer aCustomer;
{ //From Here Starts The Part in Which You Are Having Problems.
char c;
int i;
printf("Enter Customer Name: ");
scanf("%s",aCustomer.name);
i = strlen(aCustomer.name); // length of user input till first space
do{
scanf("%c", &c);
aCustomer.name[i++] = c; // reading characters after first space (including it)
}while (c != '\n'); // until user hits Enter
aCustomer.name[i - 1] = 0; // string terminating
}
printf("Age: ");
scanf("%d",&aCustomer.age);
printf("Inseam: ");
scanf("%lf",&aCustomer.inseam);
return aCustomer;
};
int main(){
FILE* customersFile = fopen("customers.txt","w");
int i = 0;
for (i = 0; i < 5; i++){
struct ClothingCustomer aCustomer = createACustomer();
fprintf(customersFile, "%s %d %lf\n", aCustomer.name, aCustomer.age,aCustomer.inseam);
}
fclose(customersFile);
return 0;
}
I Highly Recommend You To Take A Look on this answer , it will help you a lot , the method I used in here is mentioned in the above answer.Please Give That answer Credit If this method works for you.
Here is the explanation for the part which you were having problem in , how is it working now.
How this works? When user inputs characters from standard input, they will be stored in string variable until first blank space. After that, rest of entry will remain in input stream, and wait for next scanf. Next, we have a for loop that takes char by char from input stream (till \n) and appends them to end of string variable, thus forming a complete string same as user input from keyboard.
Unclear why scanf(" %19[^\n], aCustomer.name) failed for OP.
Rather than use scanf() for complex input, separate user input from parsing.
Drop use of scanf() completely and use fgets() to fetch user input. Use sscanf(), strtod(), strtol(), strtok() etc. for parsing.
Be sure to check the result of user input and success of parsing functions.
OP has not indicated how to handle troublesome input. The below returns a zero-ed ClothingCustomer in that case. Additional error codes or error messages may be useful.
struct ClothingCustomer createACustomer(void) {
// Suggest initializing
struct ClothingCustomer zero = { 0 };
struct ClothingCustomer aCustomer = { 0 };
char buffer[100];
printf("Enter Customer Name: ");
fflush(stdout); // insure prompt is seen before asking for input
if (fgets(buffer, sizeof buffer, stdin) == NULL) return zero;
buffer[strcspn(buffer, "\r\n")] = '\0'; // lop off potential line ending
if (strlen(buffer) >= sizeof aCustomer.name) return zero; // too long
strcpy(aCustomer.name, buffer);
printf("Age: ");
fflush(stdout);
if (fgets(buffer, sizeof buffer, stdin) == NULL) return zero;
if (sscanf(buffer, "%d", &aCustomer.age) != 1) return zero;
// Let us do some range checking
// https://en.wikipedia.org/wiki/List_of_the_verified_oldest_people
if (aCustomer.age < 0 || aCustomer.age > 122) return zero;
printf("Inseam: ");
fflush(stdout);
if (fgets(buffer, sizeof buffer, stdin) == NULL) return zero;
if (sscanf(buffer, "%lf", &aCustomer.inseam) != 1) return zero;
return aCustomer;
}

s expects argument of type char c but argument 2 has type 'int' warning and bad return

Yes ,I know that this question was already asked for many times ,but none of these helped me to discover the problem (duplicate...yeah). I want to read from input a series of strings into an array and then search from 'First Name'. If the name exist ,I want to display all the data stored in that element of array (I attached the code to undestand easily). When I run it ,I read from keyboard all the data ,but it returns me absolutely nothing.
#include<stdio.h>
typedef struct record {
char name[10],lname[10],phone[10],bday[10];
};
void main() {
struct record rec;
char search;
int i,nr;
printf("\nInput number of records: ");
scanf("%d",&nr);
for (i=0 ; i<nr ;i++) {
printf("First name: ");
scanf("%s",&rec.name[i]);
printf("Last name: ");
scanf("%s",&rec.lname[i]);
printf("Phone: ");
scanf("%s",&rec.phone[i]);
printf("Bday: ");
scanf("%s",&rec.bday[i]);
}
printf("Input the first name for searching: ");
scanf("%s",&search);
for (i=0 ;i<nr;i++) {
if (search == rec.name[i]) {
printf("First name: %s\nLast name: %s\nPhone: %s\nB-day: %s",rec.name[i],rec.lname[i],rec.phone[i],rec.bday[i]);
}
}
}
NOTE: I already replaced
scanf("%s",&rec.name[i]);
with
scanf("%s",rec.name[i]);
but no effect.
I believe there are a lot of problems with your code.
Firstly in this line:
scanf("%s",&search);
You have declared search as only a char, when really you want an array of chars. You also don't need & with search, as an array decays to a pointer to the first element.
It instead should be like this:
char search[10];
scanf("%9s", search); /* %9s to avoid buffer overflow */
You need to make this change to all your other scanf() calls, as this seems to be everywhere in this code.
It also seems that you want to create an array of records(structures), So you might need to make this after getting the value of nr. You can create it like this:
struct record rec[nr]; /* array of nr structures */
This also means calls like this:
rec.name[i]
Don't make sense, as you are iterating over the characters within a name, not over all the records in struct records.
This needs to be instead:
rec[i].name
Secondly, Your using == to compare strings, when you should be using strcmp instead. Using == will only compare the base address of the strings, not the actual contents of strings.
Your line should be this instead:
if (strcmp(search, rec[i].name) == 0) {
If you read the manual page for strcmp(), checking for a return value of 0 means that both strings are equal in comparison.
Lastly, in your first scanf() call:
scanf("%d",&nr);
You should really check the return value of this:
if (scanf("%d", &nr) != 1) {
/* exit program */
}
Note: For reading strings, you should really be using fgets instead. You can try upgrading to this later, but I think it is better to understand these basics first.
Here is working example of what your program should do:
#include <stdio.h>
#include <string.h>
#define STRSIZE 10
typedef struct {
char name[STRSIZE+1]; /* +1 to account for null-btye at the end */
char lname[STRSIZE+1];
char phone[STRSIZE+1];
char bday[STRSIZE+1];
} record;
int main() {
char search[STRSIZE+1];
int i,nr;
printf("\nInput number of records: ");
if (scanf("%d", &nr) != 1) {
printf("Invalid input.\n");
return 1;
}
record rec[nr]; /* array of records */
for (i = 0; i < nr ; i++) {
printf("First name: ");
scanf("%10s", rec[i].name);
printf("Last name: ");
scanf("%10s", rec[i].lname);
printf("Phone: ");
scanf("%10s", rec[i].phone);
printf("Bday: ");
scanf("%10s", rec[i].bday);
}
printf("Input the first name for searching: ");
scanf("%10s", search);
for (i = 0; i < nr; i++) {
if (strcmp(search, rec[i].name) == 0) {
printf("First name: %s\nLast name: %s\nPhone: %s\nB-day: %s\n",rec[i].name,rec[i].lname,rec[i].phone,rec[i].bday);
} else {
printf("Record not found.\n");
}
}
return 0;
}
The numeric input leaves a new line character in the input buffer, which is then picked up by the character input. when numeric input with scanf() skips leading white space, character input does not skip this leading white space.
Use a space before %c and it will help you cause if space is not used then a buffer added with value .so that use space before %c
scanf(" %c",&rec.name[i]);

scanf("%[^\n]") gets skipped

I want to write a little program to learn C; here it is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int total;
char suffix[3];
struct person {
char id[11];
char name[21];
char sex[7];
int age;
char phone[12];
};
char* number_suffix (int number) {
int mod;
mod = number % 10;
switch (mod) {
case 1:
strcpy(suffix, "st");
break;
case 2:
strcpy(suffix, "nd");
break;
case 3:
strcpy(suffix, "rd");
break;
default:
strcpy(suffix, "th");
break;
}
return suffix;
}
void input_info (struct person info[], int total_people) {
int counter;
for (counter=0; counter<total_people; counter++){
printf("%s%d%s%s\n","Please input the ID(10 digits) of ", (counter+1),
number_suffix(counter), " person: ");
scanf("%s", info[counter].id);
fflush(stdin);
printf("%s%d%s%s\n", "Please input the Name(20 chars) of ", (counter+1),
number_suffix(counter), " person: ");
scanf("%[^\n]", info[counter].name);
fflush(stdin);
printf("%s%d%s%s\n", "Please input the Sex(Male/Female) of ", (counter+1),
number_suffix(counter), " person: ");
scanf("%s", info[counter].sex);
fflush(stdin);
printf("%s%d%s%s\n", "Please input the Age(1~100) of ", (counter+1),
number_suffix(counter), " person: ");
scanf("%d", &info[counter].age);
fflush(stdin);
printf("%s%d%s%s\n", "Please input the Phone of ", (counter+1),
number_suffix(counter), " person: ");
scanf("%s", info[counter].phone);
fflush(stdin);
}
printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, &info[counter].age, info[counter].phone);
}
int main (void) {
printf("%s\n", "Please input a number that how many people you want to record:");
scanf("%d", &total);
fflush(stdin);
struct person *person_info = malloc(sizeof(struct person)*total);
input_info(person_info, total);
free(person_info);
return 0;
}
I found something weird, when I run it.
Please input a number that how many people you want to record:
1
Please input the ID(10 digits) of 1th person:
A01
Please input the Name(20 chars) of 1th person:
Please input the Sex(Male/Female) of 1th person:
Male
Please input the Age(1~100) of 1th person:
32
Please input the Phone of 1th person:
1224464
[empty line]
[empty line]
[empty line]
1926234464
[empty line]
Is that program skip scanf("%[^\n]", info[counter].name); this line when it run?
Why, and what causes it?
fflush(stdin) is undefined as per the C standard, but it works on some implementations. But it is best to avoid it as it isn't portable and may invoke Undefined Behavior.
To fix the issue, replace all fflush(stdin)s with
int c; /* Declare it once */
while((c = getchar()) != '\n' && c != EOF); /* Discards everything until a newline character or EOF */
Another problem is with
printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, &info[counter].age, info[counter].phone);
It should be
printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, info[counter].age, info[counter].phone);
and should be placed inside the for loop. Otherwise, you invoke Undefined Behavior because
You passed an int* for %d which expects an int.
You access invalid memory location beyond the allocated memory segment.
Also, as others have said, pass counter + 1 to number_suffix.
Problem is with your scanf pattern. Use " %[^\n]" instead of "%[^\n]" to not catch \n (After previous data entry)
Pass counter + 1 to number_suffix
How to understand the relation between pointers, struct, malloc, functions parameters?
Read Understanding and Using C Pointers from O'Reilly Media

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