Scan a white space/whole line in c - 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;
}

Related

Is this a good scanf alternative?

void fill_boxes(box *boxes, int length)
{
char *n;
for (int i = 0; i < length; i++) {
printf("Enter box %d id: ", i+1);
//scanf("%d",&boxes[i].id);
fgets(n,25,stdin);
boxes[i].id = strtol(n,NULL,10);
printf("Enter box %d name: ", i+1);
//scanf(" %49[^\n]",boxes[i].name);
fgets(boxes[i].name,50,stdin);
}
}
I tried this method to replace scanf and it looks like the input() function in python where it takes the input as a string and then you convert it to whatever type you want, which is what I'm doing with fgets() then strtol().
I'm asking if this is a good alternative to scanf or are there better solutions available ?
fgets() is good, when passed valid arguments.
fgets(n,25,stdin) is bad in this code as the value of pointer n is indeterminate.
Instead of using pointer char *n;, use an ample sized array like char buffer[100];. I recommend 2x the expected max size.
Use sizeof to determine array size, not a magic number.
Check fgets() return value.
Avoid using both fgets() and scanf() in the same program. I recommend using fgets() only until your understand why scanf() is problematic.
void fill_boxes(box *boxes, int length) {
// char *n;
char buffer[100];
for (int i = 0; i < length; i++) {
printf("Enter box %d id: ", i+1);
// fgets(n,25,stdin);
if (fgets(buffer, sizeof buffer ,stdin) == NULL) {
printf("No valid input\n");
break;
}
boxes[i].id = strtol(n,NULL,10);
printf("Enter box %d name: ", i+1);
// fgets(boxes[i].name,50,stdin);
if (fgets(buffer, sizeof buffer ,stdin) == NULL) {
printf("No valid input\n");
break;
}
snprintf(boxes[i].name, sizeof boxes[i].name, "%[^\n]", buffer);
// or
buffer[strcspn(buffer, "\n")] = 0; // Lop off potential \n
snprintf(boxes[i].name, sizeof boxes[i].name, "%s", buffer);
}
}
Additional code concerns:
What should happen if the line of input is excessively long?
What should happen with errant input like "123 zxfc\n" for boxes[i].id?
fgets(boxes[i].name,50,stdin); is a problem as rarely is the trailing '\n' desired in boxes[i].name. Zeroing the '\n' after the read, limits reduces by 1, what could be stored in boxes[i].name.

Using scanf to create new struct object

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);
...
}

How to enter and scan multiple chars in c

I want to enter multiple printfs but i dont get opportunity to enter.
I can enter only 1, but after that it just ends the programme.I tried with do while but it didnt work
int main()
{
int number;
char username[30]="";
char fullName[30]="";
char password[30]="";
printf("Do you want to log in(1) or register (2)? \n");
scanf("%d",&number);
if (number==2)
{
printf("username : ");
scanf("%s",&username);
printf("Full name : ");
scanf("%s",&fullName);
printf("Password : ");
scanf("%s",&password);
printf("Repeat password : ");
scanf("%s",&password);
}
return 0;
}
Read full lines using fgets() into a suitably large buffer, then parse that.
Note that %s will stop at the first blank character, so a full name of "Mr X" will leave "X" in the input buffer, grabbing that for the password and so on. It's really not a robust way of getting input.
I can enter only 1, but after that it just ends the programme.
Of course, as the code has if (number==2) #Scadge
If you enter "2", consider the following:
scanf("%s",&fullname); will not save spaces or other white-spaces into fullname. Entering a full name like "John Doe" will save "John" into fullname and "Doe" into password.
Avoid using scanf().
Rather than use scanf() to read user input, read user input with fgets(). This is a fine opportunity for helper functions that can handle various input issues.
int read_int(const char *prompt) {
if (prompt) fputs(prompt, stdout);
fflush(stdout); // insure output is written before asking for input
char buffer[40];
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
return NULL;
}
int i;
if (sscanf(buffer, "%d", &i) == 1) {
return i;
}
// TBD - what should code do if invalid data entered. Try again?
}
char *read_line(char *dest, sizeof size, const char *prompt) {
if (prompt) fputs(prompt, stdout);
fflush(stdout); // insure output is written before asking for input
char buffer[size * 2 + 1]; // form buffer at _least 1 larger for \n
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
return NULL;
}
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') buffer[--len] = '\0';
if (len >= size) {
// input too big - how do you want to handle this?
TBD_Code();
}
return strcpy(dest, buffer);
}
Now use these 2 helper functions for clean user input
// printf("Do you want to log in(1) or register (2)? \n");
// scanf("%d",&number);
number = read_int("Do you want to log in(1) or register (2)? \n");
...
// printf("username : ");
// scanf("%s",&username);
read_line(username, sizeof username, "username : ");
// printf("Full name : ");
// scanf("%s",&fullName);
read_line(fullName, sizeof fullName, "fullName : ");
Additional code could be added to check for end-of-file, extremely long lines, int range testing, etc.
Use c library function fgets().
#include <stdio.h>
int main(){
Char username[10];
printf(“Username: “);
fgets(username,10,stdin);
}

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]);

Why does my fgets method turn out to be like this?

I cannot input my "details" because it doesn't leave any space for me to.
int addTask(NODE **head){
//IGNORE NODES
NODE *p, *temp, *ptr, *a;
DATE d;
p = *head;
a = *head;
char x[32];
char y[32];
char name[32];
char details[128];
int month;
int day;
int year;
int priority;
int intDate;
int i;
printf("\n");
printf("Enter task name: ");
scanf("%s", name);
printf("Enter task details:");
fgets(details, 128, stdin); //PROBLEM LIES HERE
printf("[mm dd yyyy] Enter task deadline: ");
scanf("%d %d %d", &month, &day, &year);
printf("Enter priority: ");
scanf("%d", &priority);
/*code conditions here*/
}
In my terminal it turns out like this:
User#Lynn /cygdrive/c/users/user/academic/c
$ gcc -o a Yago_exer11.c
User#Lynn /cygdrive/c/users/user/academic/c
$ ./a
1. Add a task
2. Remove a task
3. Search for a task
4. View all tasks
5. View tasks by priority
6. Exit
Choice: 1
Enter task name: hello
Enter task details:[mm dd yyyy] Enter task deadline: 09 09 09 //PROBLEM
Enter priority: 1
Adding...
I tried using scanf(%^[\n]) as an alternative but it turns out to have the same output. Can someone tell me what's wrong with my code?
Try to put getchar(); after scanf("%s", name);
The functions fgets and scanf work differently. It's best not to mix them.
scanf scans the input. It doesn't know about lines; it treats all new-line characters, tabs and spaces simply as "white space". It also stops after conversions, so that after reading, the next file reading operations starts directly after that input, which is usually just before a new line. (There's also the pitfall of trying to parse decimal numbers over and over when the input gets stuck in something that is not a number.)
fgets reads lines from the input. That method goes more naturally with your prompt-and-input strategy: The program asks a question, the user answers and presses enter.
I suggest a two-step approach. Read lines first, then analyse these lines and extract the data. Depending on what the data looks like, you can tokenise the line with strtok for example and convert the tokens or you can use sscanf, scanf's sister function for scanning strings, to scan the data.
Here's a version of your example that shows several strategies of parsing input with that two-step spproach:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char line[128];
char name[32];
char details[128];
int month;
int day;
int year;
int priority;
int n;
// read lines until one of them contains a word
printf("Enter task name: ");
do {
if (fgets(line, sizeof(line), stdin) == 0) return 1;
n = sscanf(line, "%s", name);
} while (n != 1);
// details may be empty, so read them directly
printf("Enter task details: ");
if (fgets(details, sizeof(details), stdin) == 0) return 1;
strtok(details, "\n");
// prompt and read lines until one of them has a valid date
do {
printf("[mm dd yyyy] Enter task deadline: ");
if (fgets(line, sizeof(line), stdin) == 0) return 1;
n = sscanf(line, "%d %d %d", &month, &day, &year);
if (n == 3) {
if (month < 1 || month > 12) n = 0;
if (day < 1 || day > 31) n = 0;
}
if (n != 3) printf("Invalid date\n");
} while (n != 3);
// read priority until a number (any number) is given
printf("Enter priority: ");
do {
if (fgets(line, sizeof(line), stdin) == 0) return 1;
n = sscanf(line, "%d", &priority);
} while (n != 1);
// echo results
printf("name: %s\n", name);
printf("details: %s\n", details);
printf("data: %02d/%02d/%04d\n", month, day, year);
printf("prio: %d\n", priority);
return 0;
}
The example is far from perfect. For example, what should happen when the user presses Ctrl-Z or Ctrl-D to end the input stream? The standard input isn't particularly suited for manual input.

Resources