taking string with spaces does not work in my function - c

I want to my function take input string with any spaces. But my taking input line is not working somehow and prints 1 without taking my input. I even tried fgets and gets function to avoid this but result is the same. Can anyone help me? Line 16 is taking input part.
double setup_tree(char object[20], char parentobject[20]) {
double total;
int i;
double val;
char input[100];
char answer[101];
char names[20][20];
int numcounts[20];
int objectnumber;
if (parentobject[0] == ' ') {
printf("Define %s\n", object);
} else {
printf("Define %s in %s\n", object, parentobject);
}
scanf("%[^\n]%*c", input);
printf("1");
remove_more_than_one_space(answer, input);
objectnumber = define_typeof_description(answer);
if (objectnumber == 0) {
//printf("0lalol ");
sscanf(answer, "%lf", total);
return total;
}
total = 0;
parse_the_answer(answer, names, numcounts, objectnumber);
printf("1lalol");
for (i = 0; i < objectnumber; i++) {
val = setup_tree(names[i], object);
total += (numcounts[i]) * val;
}
return total;
}

Your problem most probably comes from scanf() reading a pending newline left in stdin by a previous call to scanf().
You can avoid this with scanf(" %[^\n]%*c", input);
Also note that you should protect against invalid input with scanf(" %99[^\n]%*c", input);

Related

How to make "overloaded" scanf in C?

Friends how can I make Scanf to take 1 or 2 or 3 numbers depending on input data I give?
sample data 1: "1 2 5"
sample data 2: "1 4"
sample data 3: "4"
if(scanf("%lf",&a)==1 )
{
printf("1 input num\n");
}
else if(scanf(" %lf %lf",&a, &b)==2 )
{
printf("2 input num\n");
}
else if(scanf("%lf %lf %lf",&a, &b, &c)==3 )
{
printf("3 input num\n");
}else
{
printf("Error message.\n");
return 1;
}
You might consider this an answer:
int InputNums=0;
InputNums = scanf("%lf %lf %lf",&a, &b, &c);
if(InputNums!=0)
printf("%d input num\n");
else
printf("Error message.\n");
It works by NOT eating one number and then trying whether instead more numbers could have been read, like your shown code does.
Instead try to read three numbers and then let scanf() tell you how many worked.
But actually I am with the commenters. If you do not have guaranteed syntax in your input (which scanf() is for) then use something else.
This is nicely describing which alternative in which situation AND how to get scanf to work in the same situation:
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
Scanf already does this for you, and indeed you used the same scanf function with a variable number of arguments. You can look here: How do vararg work in C?
However you don't need to overload scanf, but rather pass to it a string telling what you need to scan. You can do this dynamically by changing the string at runtime.
The code to try is the following:
#include <stdio.h>
int main()
{
char one[] = "%d";
char two[] = "%d%d";
int o1;
int t1,t2;
scanf(one,&o1);
scanf(two,&t1,&t2);
printf("%d %d %d",o1,t1,t2);
return 0;
}
If you must use scanf() ....
"%lf" is a problem as it consumes leading white-space including '\n', so we lost where a line of input might have ended.
Instead first look for leading white-space and see if an '\n' occurs.
#define N 3
double a[N];
count = 0;
while (count < N) {
// Consume leading white-spaces except \n
unsigned char ch = 0;
while (scanf("%c", &ch) == 1 && isspace(ch) && ch != '\n') {
;
}
if (ch == '\n') {
break;
}
// put it back into stdin
ungetc(ch, stdin);
if (scanf("%lf", &a[count]) != 1)) {
break; // EOF or non-numeric text
}
count++;
}
printf("%d values read\n", count);
for (int i=0; i<count; i++) {
printf("%g\n", a[i]);
}
Alterantive to consume various multiple leading whitespaces that only uses scanf() with no ungetc():
// Consume the usual white spaces except \n
scanf("%*[ \t\r\f\v]");
char eol[2];
if (scanf("%1[\n]", eol) == 1) {
break;
}
If the line contains more than N numbers or non-numeric text, some more code needed to report and handle that.
The best solution to problems with scanf and fscanf is usually to use something other than scanf or fscanf. These are remarkably powerful functions, really, but also very difficult to use successfully to handle non-uniform data, including not only variable data but data that may be erronious. They also have numerous quirks and gotchas that, though well documented, regularly trip people up.
Although sscanf() shares many of the characteristics of the other two, it turns out often to be easier to work with in practice. In particular, combining fgets() to read one line at a time with sscanf() to scan the contents of the resulting line is often a convenient workaround for line-based inputs.
For example, if the question is about reading one, two, or three inputs appearing on the same line, then one might approach it this way:
char line[1024]; // 1024 may be overkill, but see below
if (fgets(line, sizeof line, stdin) != NULL) { // else I/O error or end-of-file
double a, b, c;
int n = sscanf(line, "%lf%lf%lf", &a, &b, &c);
if (n < 0) {
puts("Empty or invalid line");
} else {
printf("%d input num\n", n);
}
}
Beware, however, that the above may behave surprisingly if any input line is longer than 1023 characters. It is possible to deal with that, but more complicated code is required.
here is an example of using fgets, strtok and atof to achieve same:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char input[256];
double inputsf[256];
while(1) {
printf(">>> "); fflush(stdout);
char *s = fgets(input, 255, stdin);
if (!s)
break;
int count = 0;
char *t;
while (t = strtok(s, " \n")) {
s = NULL;
inputsf[count++] = atof(t);
}
printf("Found %d inputs\n", count);
for (int i = 0; i < count; i++)
printf(" %lf\n", inputsf[i]);
if (count == 0)
break;
}
return 0;
}
Bases on the #chux-ReinstateMonica comment, here is a piece of code which uses strtod. It skips leading spaces, but has an issue with the tailing spaces at the end of the string. So, some extra checking is needed there, which could be used for error checking as well. The following loop can replace the strtok loop from above.
while(*s) {
char *e;
double val = strtod(s, &e);
if (e == s)
break; // not possible to parse, break the loop
inputsf[count++] = val;
s = e;
}
You can solve your problem using those line of code
#include <stdio.h>
int main(){
int a[100];
int n;
printf("How many data you want to input: ");
scanf("%d", &n);
printf("Sample %d data Input: ", n);
for (int i=0; i <n; i++) {
scanf("%d", &a[i]);
}
printf("Sample data %d: ", n);
for (int i=0; i <n; i++) {
printf("%d ", a[i]);
}
if(n == 1){
printf("\n 1 input num\n");
}else if(n==2){
printf("2 input num\n");
}else if(n==3){
printf("3 input num\n");
}else{
printf("Error");
}
return 0;
}
if you want to take multiple input in single line use this line
int arr[100];
scanf ("%lf %lf %lf", &arr[0], &arr[1], &arr[2]);

How to set the character limit on C

I want my user to enter the input which I have set only for each and every declaration, but when I tried running the program it still proceeds, for example, name the ic_size the limit character is only 12 character input, but if I put more than 12 it just accepts it as nothing wrong. Here's the coding I tried:
void login_register()
{
const name_size = 80;
char name[name_size];
const ic_size = 12;
char ic[ic_size];
const no_size = 12;
char no[no_size];
const nationality_size = 20;
char nationality[nationality_size];
const email_size = 50;
char email[email_size];
int select;
int Day =0;
int bed_tax =0;
double RM;
double room_price=0;
double service_tax = 0;
double total = 0;
char term,check;
printf("\n Please enter your name : ");
while(gets(name))/* same as scanf ("%s",name) %s mean print the corresponding argument in string*/
{
if(!isalpha && sizeof(name) > name_size) // restrict user input can only be alphabeth and must not exceed array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your IC number : ");
while(gets(ic))
{
if(isdigit && sizeof(ic) < ic_size) // restrict user input can only be numerical and must not excedd array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your phone number : ");
while(gets(no))
{
if(isdigit && sizeof(no) < no_size)
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your nationality : ");
while(gets(nationality))/* same as scanf ("%s",nationality) %s mean print the corresponding argument in string*/
{
if(!isalpha && sizeof(nationality) > nationality_size) // restrict user input can only be alphabeth and must not exceed array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
printf(" Please enter your email : ");
while(gets(email))/* same as scanf ("%s",email) %s mean print the corresponding argument in string*/
{
if(!isalpha && sizeof(email) > email_size) // restrict user input can only be alphabeth and must not exceed array size
{
printf("\n Please enter a valid input");
}
else
{
break;
}
}
Rather than gets(), which has no limit on user input, consider fgets().
Shift design goal to:
Allow unlimited input per line, but only save up to N characters of input.
Let user know if too much entered. Try again if needed.
I recommend a helper function that prompts, reads input, and handles long lines.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// 'size' is the size of the array 'destination' points to.
int get_user_input(const char *prompt, size_t size, char *destination) {
char buf[size + 2]; // size + \n + 1 extra
do {
fputs(prompt, stdout);
if (fgets(buf, sizeof buf, stdin) == NULL) {
*destination = '\0';
return 0; // End of file
}
char *end_of_line = strchr(buf, '\n');
if (end_of_line) {
*end_of_line = '\0'; // Lop off \n
} else {
// get rest of line
scanf("%*[^\n]"); // Read everything up to a \n and toss
scanf("%*1[\n]"); // Read a \n and toss
}
} while (strlen(buf) >= size);
strcpy(destination, buf);
return 1;
}
Now read as needed. Recall that name_size = 12 means up to 11 characters are saved as 1 more is needed to save the null character. Adjust name_size as needed.
int main(void) {
const int name_size = 12;
char name[name_size];
const int nationality_size = 20;
char nationality[nationality_size];
get_user_input("Please enter your name: ", sizeof name, name);
printf("Name <%s>\n", name);
get_user_input("Please enter your nationality: ", sizeof nationality, nationality);
printf("Nationality <%s>\n", nationality);
}

Scanning different data types in C

I want to write a program, at first I input a number N, then I want to get the name (can consist of multiple words) and price of N items one by one. Example:
3
item a // the name can consist of multiple words
25.00
item b
12.50
item c
8.12
Next I want to process this data, however i got stuck on the scanning part. my code looks like this:
#include <stdio.h>
int main(){
int n;
char name[50];
int price;
scanf("%d\n", &n);
for(int i = 0; i < n; i++){
scanf("%s\n%d",name,&price);
printf("%s , %d", name, price);
}
printf("end");
}
This works for a single word item, but if the item has a space in it will not continue scanning. I tried using the gets() function, however I still don't have the right result. the code:
for(int i = 0; i < n; i++){
gets(name);
scanf("%d\n",&price);
printf("%s , %d\n", name, price);
}
printf("end");
returns:
3 // Input 3 items
item a // name of first item
1 // price of item 1
item b // name of item 2
item a , 1 // the print of the first item
2 // price of item 2
item c // name of item 3
item b , 2 // print of item 2
3 // price of item 3
word // no clue where this new input came from
end // end of scanning
My question is, how would I go about correctly scanning an input such as this? I also tried changing the scan function into while((c = getchar()) != '\n');, but got the same result...
Mixing gets(), scanf() is bad as scanf() tends to leave the trailing '\n' in stdin.
Using gets() is bad.
scanf("%s", ...) is not useful for reading a line of info with spaces meant to be saved.
how would I go about correctly scanning an input such as this?
A simple alternative is to read each line into a string and then parse the string.
#include <stdio.h>
int main() {
char line[100];
int n;
fgets(line, sizeof line, stdin);
sscanf(line, "%d", &n);
for(int i = 0; i < n; i++){
char name[50];
// int price;
double price;
fgets(line, sizeof line, stdin);
sscanf(line, " %49[^\n]", name);
fgets(line, sizeof line, stdin);
// sscanf(line, "%d", &price);
sscanf(line, "%lf", &price);
printf("%s , %.2f\n", name, price);
}
printf("end");
}
Advanced: Better code would check the return values of fgets(), sscanf(). Maybe replace sscanf(line, "%lf",... with strtod().
I think you could probably figure out what's happening here pretty easily if you added some more output. Let's try shall we?
Also, first of all you're really looking for a double input - not an integer. With an integer, your scan function won't match properly based on what you're looking for. But let's add some more output!
#include <stdio.h>
int main()
{
int n;
char name[50];
double price;
printf("Enter count: ");
scanf("%d", &n);
for (int i = 0; i < n; i++) {
printf("%s\n", "Please type a name followed by a newline followed by a number and then press enter:");
scanf("%s\n%lf", name, &price);
printf("%s , %lf", name, price);
}
return 0;
}
So I think what was happening in your initial attempt was a combination of things. Mostly that you were possibly pressing enter after the output from the first iteration? That will break the scanf call - since it isn't expecting to start with a \n but it is immediately expecting you to enter a name.
Second, I don't know the number you entered in the first iteration, because you didn't supply the output of it while still using scanf - so I have nothing other than speculation. You possibly used an integer on the first go, and subsequently on the remaining iterations you chose to use decimals? Again, this is only a guess.
Sometimes it is easier to just write your own functions with error checking. Below is a suggestion. You may also want to check that the numbers are non-negative.
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
void ReadLine(char result[], int resultLen)
{
int ch, i;
assert(resultLen > 0);
i = 0;
ch = getchar();
while ((ch != '\n') && (ch != EOF)) {
if (i < resultLen - 1) {
result[i] = ch;
i++;
}
ch = getchar();
}
result[i] = '\0';
}
void ReadInteger(int *i)
{
int ch, count;
count = scanf("%d", i);
if (count == 1) {
do {
ch = getchar();
} while (isspace(ch) && (ch != '\n'));
} else {
fprintf(stderr, "invalid input, integer expected\n");
exit(EXIT_FAILURE);
}
}
void ReadReal(double *x)
{
int ch, count;
count = scanf("%lf", x);
if (count == 1) {
do {
ch = getchar();
} while (isspace(ch) && (ch != '\n'));
} else {
fprintf(stderr, "invalid input, real number expected\n");
exit(EXIT_FAILURE);
}
}
int main(void)
{
char name[50];
int n;
double price;
ReadInteger(&n);
for (int i = 0; i < n; i++) {
ReadLine(name, sizeof name);
ReadReal(&price);
printf("%s, %.2f\n", name, price);
}
return 0;
}
As chux said in the comments of this answer: "All scan specifiers, except %c, %[, %n consumes leading white-spaces." So you don't need to account for them.
scanf("%s%d",name,&price);
And looking at your input, you should use float or double for the price.
scanf("%s%lf",name,&price);
Note that this works only if items are made of one word. If they can be of two or more words, you'd better use fgets
EDIT: for items made of more words you should use fgets
fgets(name, 50, stdin);
scanf("%lf",&price);
Replace your for loop with this:
for (int i = 0; i < n; i++) {
scanf(" %[^\n]\n%d", name, &price);
printf("%s , %d\n", name, price);
}
The first space skips leading spaces, and the [^\n] allows you to get more than one word as string input.

Unable to store any value in array

I am unable to put the value in the first element of the array. It's always asking to put the value in array second element.
#include<stdio.h>
#include<string.h>
int main(void)
{
int a, i;
char names[50][50];
printf("\nEnter the number of names you want :");
scanf("%d", &a);
for(i = 0; i < a; i++)
{
printf("\n%d name :", i);
gets(names[i]);
}
printf("\nThe required name lists :");
for(int i = 0; i < a; i++)
{
printf("\n%d name :", i+1);
puts(names[i]);
}
return 0;
}
As scanf leaves behind a dangling newline character \n it causes the gets(Use fgets) to not wait for the input from the user. Try flushing the input buffer by using getchar.
Update: Added mechanism to remove the trailing \n registered by the fgets
#include<stdio.h>
#include<string.h>
int main()
{
int a,i;
printf("Enter the number of names you want: ");
scanf("%d",&a);
//Flush the input buffer
int ch;
while ((ch = getchar()) != '\n' && ch != EOF);
char names[50][50];
for(i=0;i<a;i++)
{
printf("%d name: ",i);
fgets(names[i],50,stdin); //Use fgets instead of gets
// To remove th \n registed by the fgets
char *p;
if ((p = strchr(names[i], '\n')) != NULL)
*p = '\0';
}
printf("The required name lists: \n");
for(int i=0;i<a;i++)
{
printf("%d name: ",i+1);
puts(names[i]);
}
return 0;
}
Reference:
Remove newline skipped by scanf
Remove newline registered by fgets
Put this after line scanf("%d",&a), as a workaround,
char c;
scanf("%c",&c);
Also use fgets(names[i],50,stdin) instead of gets(names[i])
Note: You get warning when you use gets in your code, as it is always assumes a consistent input from user. More explanation over here
Why is the gets function so dangerous that it should not be used?

How to scanf multiple inputs separeted by space in C?

I am new in proggraming and i can't solve a problem. So i have to scanf and check if it is an integer (int n), and than read n floats (with checking if they are floats). Problem is that machine tests add multiple floats separeted by space in input and i don't know how to get these numbers.
I wrote something like this:
int n;
if(!scanf("%d", &n)){
printf("Invalid input");
return 1;
}
float *tab = malloc(n*sizeof(float));
printf("Enter variables: ");
for(int i=0; i<n; i++){
if(scanf("%f", (tab+i))!=1){
printf("Incorrect input data");
return 2;
}
}
I don't know if it is good and what to do if you input less or more numbers in input.
Guys, please explain me what is wrong here and how to solve it.
Thanks for your time.
How to scanf multiple inputs separated by space in C?
The "%d" and "%f" will happily handle numeric text separated by spaces, tabs, end-of-lines, etc., yet not distinguish between spaces and end-of-line. With insufficient input in one line, code will read the input of the next line. With excess input, the entire line is not read - rest of line reamins for next input function.
If OP is concerned about lines of inputs, best to read a line of input and then parse.
I don't know if it is good and what to do if you input less or more numbers in input.
Put yourself in charge: if you directed a team of coders, what would you want? Consume and ignore non-numeric input, consume input and report an error, simple end the code, etc.
Aside from the first scan, code looks reasonable as is.
For me, for robust code, I would drop all scanf() and use fgets() in a helper function to parse. Then sscanf() or strto*() to parse and complain if not as expected.
Sample
Of course this helper function is overkill for such a simple task, yet it is a helper function - one that I can use over and over for anytime I want to read a a group of float from one line. I can improve as desired (e.g. more error handle, handle overly long lines, ...)
// Read 1 line of input.
// return EOF on end-of-file or stream error,
// else return number of float read, even if more than N.
int get_floats(const char *prompt, float *dest, int N) {
if (prompt) {
fputs(prompt, stdout);
fflush(stdout);
}
char buf[BUFSIZ];
if (fgets(buf, sizeof buf, stdin) == NULL) {
return EOF;
}
char *endptr = buf;
int floats_read = 0;
// parse the line into floats
while (*endptr) {
const char *s = endptr;
float f = strtof(s, &endptr);
if (s == endptr) {
break; // no conversion
}
if (floats_read < N) {
dest[floats_read] = f;
}
floats_read++;
}
// Consume trailing white-space
while ((unsigned char) *endptr) {
endptr++;
}
if (*endptr) {
return -1; // Non-numeric junk at the end
}
return floats_read;
}
Usage:
int n;
if(get_floats("Enter variables: ", tab, n) != n) {
printf("Invalid input");
return 1;
}
The answer is really simple: put a space in front of your scanf format specifier. That tells scanf to eat all the whitespace before converting.
Like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
if (1 != scanf(" %d", &n)) {
exit(1);
}
float *tab = calloc(n, sizeof *tab);
if (!tab) {
exit(3);
}
for (int i = 0; i < n; ++i) {
if (1 != scanf(" %f", &tab[i])) {
exit(2);
}
}
const char *sep = "";
for (int i = 0; i < n; i++) {
printf("%s%f", sep, tab[i]);
sep = ", ";
}
printf("\n");
free(tab);
return 0;
}

Resources