Why is & used before a variable? - c

Why is & used here before decks (scanf("%i", &decks))?
And if my input is any letter like 'k' then it shows an output like "1929597720". Why?
#include <stdio.h>
int main(){
int decks;
puts("enter a number of decks:");
scanf("%i", &decks);
if (decks<1) {puts("Please enter a valid deck number");
return 1;
}
printf("there are %i cards\n", (decks*52));
return 0;
}

& before a variable name means "use the address of this variable". Basically, you're passing a pointer to decks to scanf()
As for what happens when you enter "k" (or other invalid input) - scanf() is failing, and you're seeing whatever random data was already in decks (which was never initialized).
To avoid this, check the return value of scanf(), and initialize decks.
int decks = 0, scanned;
puts("enter a number of decks:");
int scanned = scanf("%i", &decks);
if ((scanned < 1) || (decks < 1)) {
puts("Please enter a valid deck number");
return 1;
}

When passing stuff to scanf(), you need to pass in a pointer to the variable, not the variable itself. The & means "Don't take the variable, take the place in memory where this variable is stored." It's a little complicated, but it's necessary so that C can change the value of the variable.
Also, change your format string to
scanf("%d", &decks);
The garbage is because you don't initialize decks. If you put in int decks = 0, you would always get 0.

As every good C tutorial will teach you, the & sign is for getting a variable's address.
In the case of scanf(), this is necessary in order to tell scanf() where to put the requested data.
If you input a letter like k, or any non-number, scanf() will be disturbed by that, and if you would check scanf()'s return value, it would tell you that 0 items are read instead of 1.
In that case, the content of the given variable is unchanged and contains random garbage. And this is as well what you output.

Related

A simple while loop to check input stuck in infinite loop

I am pretty sure this was asked before but I could not find any answers, so here I go. This is a simple line of code and I cannot get it to exit the while loop. If I change the || to && the loop just exit no matter what I press. Thank you for the answers.
#include <stdio.h>
int main()
{
int answer;
printf("Are you sure you want to exit the program? Type in 1 for yes and 2 for no.\n");
scanf("%d", answer);
//This is to check that the user inputs the right number if not error message is displayed
while(answer <1 || answer > 2)
{
printf("Please type in 1 to exit the program and yes and 0 to keep playing. \n");
scanf("%d", answer);
flushall();
}
return 0;
}
If You want to exit on 1, then You just need to check if input is equal to it, that is why I want to scan for more answers when it is not equal to 1. If it is then it will omit while loop and go directly to return 0.
Also I changed the way of usage of scanf - when you declare a variable (in Your case answer), system gives it an address in the memory. Then you use scanf to take an input from the user, and after you take the input, you write it on the address of that variable so that when you refer to it later, the system goes to the address and retrieve the value.
int main()
{
int answer;
printf("Are you sure you want to exit the program? Type in 1 for yes and 2 for no.\n");
scanf("%d", &answer);
//This is to check that the user inputs the right number if not error message is displayed
while(answer != 1)
{
printf("Please type in 1 to exit the program and yes and 0 to keep playing. \n");
scanf("%d", &answer);
}
return 0;
}
This is one the frequent cases of misunderstanding/forgetting how scanf works.
int scanf ( const char * format, ... );
reads formatted data from stdin.
It reads data from stdin and stores data according to the parameter format into the locations pointed by the additional arguments.
The additional arguments should point to already allocated objects of the type specified by their corresponding format specifier within the format string.
It means that arguments should be pointers.
In your case:
int answer;
scanf("%d", answer);
answer is not a pointer but the variable (object) of type int.
To satisfy the scanf you have to use a pointer to the answer.
You can do it using the unary or monadic operator & which gives the address of a variable.
scanf("%d", &answer);
or you could use a pointer pointing to the answer:
int answer;
int answer_ptr = & answer;
scanf("%d", answer_ptr);
which is also correct but typically there is no need to go for this construction.
Secondly the line:
while(answer <1 || answer > 2)
You may want to modify it to
while (answer != 1 && answer != 2)
if you are interested in breaking the while loop when answer is being equal to 1 or 2.

Issues with using scanf inside a while loop

I’m brand new to programming. I ‘m working on a homework assignment in order to help us understand scanf and arrays. The program is supposed to ask the user to input an unknown set of numbers. Each set of numbers should be separated by a space like below without hitting enter.
14 15 16
The user can also input numbers on a separate line instead using spaces, but again on the last number inputed the user isn’t supposed to hit enter.
12 13
44 55
5
The user should hit ctrl-d to indicate end of input. The program should display the number of elements entered by the user, along with displaying the numbers the user entered. I have been reading around and think I have a basic concept of how scanf works, but I am still having some difficulty. The code kind of works. However, if the user just enters the numbers on one line they need to hit ctrl-d three times in order for it to exit the loop and display the information.
From what I have found online and understand, I think it’s not working because the user hasn’t hit return, so the input hasn’t been flushed into the stdin. So if I'm understanding correctly, the first time I hit ctrl-d it while flush the input. Then the second time I hit ctrl-d it will finally put the EOF into the stream and the third time it will finally read the -1 produced by the EOF and exit the loop.
Is there anyway to force the input stream once ctrl-d is entered.
#include <stdio.h>
int main()
{
int numbers[20];
int i = 0, count, result, n;
int flag = 0;
printf("Please enter a seiries of numbers:\n");
while (flag == 0)
{
result = scanf("%d", &n); //scan user input into n variable along with getting scanf return value and storing in result variable
printf("result =%i \n", result); //Just printing scanf return value to insure it doing what I think it should be doing
if (result == 1)
{
numbers[i] = n; //if scanf return value is 1 places value of n into first element of array
i++; //used to increment my array
flag = 0;//keeps value of flag equal to 0 in order to stay in loop
}
if(result == -1) //checks to see if result = to -1 should be value returned if cntl +d is entered
{
flag = 1; //sets flag to 1 when cntrl +d is entered in order to exit loop.
}
}
for (count = 0 ; count < i ; count++) //loop to print I which is representing number of user inputs and the actual numbers entered by the user.
{
printf("\ni= %i numbers= %i\n", i, numbers[count]);
}
return 0;
}
I won't give you a solution directly, but will try to help you improve coding in C. The more you work with C the more you will find out that one can write pretty compact code, once the language is mastered.
You can omit flag because it depends on result.
And you could omit result because it is just the return value of scanf.
You can omit n and use numbers array directly.
And you could make use of the preprocessor to use a constant number (often for array sizes as in your case).
Have a look at this. Maybe it helps you get an idea:
#include <stdio.h>
#define COUNT 20
main() {
int numbers[COUNT];
int i;
i = 0;
while (scanf("%d", &numbers[i]) == 1 && i < COUNT)
printf("\t%d\n", numbers[i++]);
return 0;
}
P.S.:
I recommend getting acquainted with the different ways of accessing an array and reading about pointers. The have a very close relationship really.
Address of first element in array : numbers
Access ith element of array : numbers[i]
Equivalently : *(numbers + i)
Another equivalence : *(i+numbers)
Surprise, but equivalent again : i[numbers]
Address of ith element of array : &numbers[i]
K&R is a great resource of information and learning.

printf after scanf always displays 1 (same unexpected value)

Okay so I'm trying to do a basic program in VS. Enter a number then it gets printed out. 1 is always printed.
int main(){
printf("Enter an integer: ");
int n = scanf_s("%d", &n);
printf("%d", n);
}
You are assigning the returned value from scanf_s() to the variable n, that means that the program will print 1 in case a successful read happened.
What you should do is
int numberOfItemsMatched;
int readValue;
numberOfItemsMatched = scanf_s("%d", &readValue);
if (numberOfItemsMatched == 1)
printf("%d\n", readValue);
I hope the variable names are self explanatory, and it's always a good idea to use this kind of names.
return type of scanf is number of items read. so if scanf is succesful in reading an item, it returns one which is assigned to n here. hence the output is 1. So separate declaration of n and scanf.

Storing and retrieving strings in Multidimensional array

I have the following code which stores string-input from a user N times in a multidimensional array. And then print out the second element.
main()
{
// Array to store 10 strings, 20 characters long.
char strStorage[10][20];
printf("\nEnter how many strings: ");
scanf( "%d" , &num);
fflush(stdin);
for ( count = 0 ; count < num ; count++)
{
printf("Enter a string: ");
gets(strStorage[count]);
fflush(stdin);
}
printf("%s", strStorage[2]);
Last line prints out garbage. The user-input is not visible inside the garbage hence either my element access is wrong or my storage is wrong. Can anyone help me with regards to what is the problem?
Thanks in advance...
strStorage[2] is the third string, so if num is less than 3, you won't initialize it and it will contain garbage.
scanf("%d", &num); doesn't ensure that num contains a value. Perhaps it'd be wise to check the return value of scanf to ensure it read 1 value, like this: if (scanf("%d", &num) != 1) { puts("Error reading integer"); }
While we're on this topic, I presume num and count are declared as an int, and you've hidden the declarations from us. Tsssk! Do you want our help? If so, then make your code compilable! Do you really think int is suitable for storing indexes to arrays? It's possible that they might have negative values. I'd suggest using size_t, instead, and the %zu format specifier tells scanf to expect a size_t value from stdin.
... and what happens when that size_t contains a value greater than the number of elements in your array? I suggest researching variable length arrays.
fflush(stdin); is nonsense because fflush defines behaviour for files open for output, and stdin is a file open for input only. That's sort of like flushing the toilet and expecting the waste to come out of the bowl, rather than going down through the S-bend. Perhaps you mean to discard the remainder of a line, because you've read the data you need from the start of it. Something like for (int c = getchar(); c >= 0 && c != '\n'; c = getchar()); might work.
Don't use gets. Use fgets(strStorage[count], sizeof strStorage[count], stdin); instead, to ensure that no buffer overflows occur.
There, I think I covered just about every bit of undefined behaviour and nit-picky stuffs.

C - error: ignoring return value of scanf?

I'm only a few days into C programming, so I am not quite sure what's wrong with this code:
#include <stdio.h>
int main(int argc, char * argv[]) {
int sides;
printf("Please enter length of three sides :\n");
scanf("%d", &sides);
return 0;
}
The error message I receive is as follows:
ignoring return value of scanf
What am I doing wrong here, and what can I do to fix it?
You might code
if (scanf("%d", &sides) >0) {
printf("you want %d sides.\n", sides);
}
else printf("You did not enter any number.\n");
The scanf function (please follow the link) has several roles
it is expecting some input and could modify the variables you passed by address to it
it is returning the number of successfully input items
It's a warning that stops your compiler from performing it's task (too strict settings). Check the return value of the scanf() function for errors and the warning should disappear.
Return Value
On success, the function returns the number of items
successfully read. This count can match the expected number of
readings or fewer, even zero, if a matching failure happens. In the
case of an input failure before any data could be successfully read,
EOF is returned.
scanf returns the number of "items", i.e. values passed both in the format string (a single item is e.g. %d, %c and so on), and in the subsequent arguments to scanf, for example, to read two integers separated by comma and space, you would use:
int x, y;
int items = scanf("%d, %d", &x, &y);
assert(items == 2);
I've already spoiled what my suggestion will be above - instead of adding unused variables, if you just want to read it, add an assertion:
#include <assert.h>
/* ... */
assert(scanf("%d", &sides) > 0);
/* ... */
Unfortunately, assert(scanf("%d", &sides)); is not enough, because of EOF (this will return -1). It would be really elegant.
I think this is the way to go, if you don't want to continue your program with an uninitialized variable (sides) in this case.
Alternatively, you can capture scanf's result to a variable, and handle it gracefully like in the other answers.
You don't capture the return value of scanf in a variable. It's a count (as an integer) of how many characters were read, so if that's important to you, then it may be good to capture it.

Resources