Why do we feed an adress to scanf? - c

So in the following snippet, we ask the user to assign some value to our integer x.
int x;
scanf("%d", &x);
What I'm confused about is why we're saying "put the value of the input into the adress of x", instead of just "let x be equal to the value of the input"? What would be the problem with scanf("%d", x)?

In C, parameters are passed by value. So if you use x as a parameter to scanf, it just gets a copy of the value of x, it doesn't get a reference to the actual variable x.
By passing a pointer, you're giving it the address of the memory that the x variable's value is stored in. That allows scanf to modify the value of x by storing into that memory.

All function calls take their arguments by value. Passing x would just give scanf a copy of x, and it still wouldn't have access to our x.
Taking the address of a variable produces a pointer, which when copied, still points to the same variable. Thus scanf can dereference its copy of the pointer and gain access to x.

Short answer: because you have to. The specification of scanf says that for the format specifier %d it expects the corresponding argument to have the type int *, which means &x, not x.
C doesn't have pass-by-reference. scanf is a function like any other and when you pass a variable to it, you don't pass the variable itself, but its value. So when you call scanf("%d", x); you give it the (uninitialized) value of x, which is useless to scanf. When you pass the address of x, scanf can put the value it scanned into x by dereferencing it.
As n.m. commented, calling scanf("%d", x); is (somewhat) equivalent to calling scanf("%d", 5); (or more accurately: scanf("%d", <garbage>);). It can't assign to a constant, or an ordinary number, but it can assign to the place that a (valid) address points to.

I'm just going to take a slightly different approach and try and make you answer the question for yourself.
Consider the following code (that won't compile but supposes that you only need to do as you suggest and call scanf("%d", x)):
int w = 5;
int x = 5;
int y = 5;
int z = 5;
scanf("%d", x);
When you make the call to scanf, scanf doesn't know that you have passed the value of x, all it knows is that you have given it a value of 5, just as if you had written the line scanf("%d", 5)
Assuming you were the programmer who was coding scanf, if you've been given the parameters "%d" and 5, which of the variables w, x, y or z would you update? How would you even know that the variables w, x, y, z exist? How would you know that there aren't any other variables in the code with the value of 5? How would you know that the value of 5 you have received actually came from the variable x?

Related

I am not quite understanding the output of the following function

I wrote a simple sum() function in C with two arguments of integer type. But, while calling the function in main, I passed char type variables. The problem is I am not able to understand the output of the program. Following is the code.:
void sum(int x,int y)
{
printf(" x=%d y=%d\n",x,y);
printf("%d",x+y);
}
void main()
{
char a,b,add;
printf("Enter two values: ");
scanf("%c%c",&a,&b);
sum(a,b); //calling
}
If I input a=A and b=A then it should give me the addition of ASCII values of A, i.e. 130, but it is giving me 97.
When I try to print the value of x and y, it prints x=65 y=32. I don't understand why it stores 32 in y? Can someone please explain this.
This is because your input was A A, which is A<spacebar>A. The scanf("%c%c",&a,&b) read exactly two characters, A and <spacebar>, which resulted x = 65(A), y= 32(<spacebar>). If you want to get the intended output, your input should be AA.
It seems that you are giving input as A A instead of AA. For the former, x stores 65 and y stores 32 as the ASCII value of space is 32.
If you want to store 124abc in a integer variable then it will store only 124.
And in the definition of character constant/variable it can save all ASCII 255 character's which include also space(spacebar),tab(tab key),newline(enter key).
so when you run code and the screen show "Enter two values: ". You type 'A' which store in variable 'a'. Now you press space bar which is also a character constant which have value of ASCII 32 store into variable 'b'. so avoid this situation you should put a space before %c so it never read enter key or space bar.
Or use fflush(stdin) function.

What does scanf do when passing a char and an integer specifier?

For the purposes of an exercise, I was given a snippet of code and told to find the bug. I removed a bunch of noise and the part that is tripping me up is the following:
int main() {
char *p;
char n;
scanf("%i", n);
if (n < get_int()) {
p = malloc(n);
}
}
Here, if I enter a number for n, I get a seg fault. If I enter a character, n is set to 0. What is scanf doing that makes this so?
Edit: the exercise I'm trying to figure out is Exercise 2 from this page
It is simply UB.
C does not specify any specific behavior here. "%i" expect a int *, not an uninitialized char converted to an int.
"What is scanf doing that makes this so?" implies defined behavior. There is no specified UB.
"If I enter a character, n is set to 0. " --> scanf() does not attempt to change n, it uses a copy of n (passed by value).
The usual scanf() usages is like the below where the address of nn is passed, not nn itself.
int nn;
if (scanf("%i", &nn) == 1) Success();
else Failure();
You aren't just passing the wrong kind of variable to scanf, you are also passing it's value instead of the pointer to it. The scanf have no way of knowing this value isn't an actual pointer to store the scanned data into, so thats exactly what its going to try and do, scan the input and place it into whatever memory address the n, treated as pointer value, happened to point to. In the absolute most of the cases this will attempt to access unmapped/protected/etc memory, and cause segfault/access violation.
Entering a character simply terminates the scan prematurely, avoiding the segfault, and leaving the n intact. Bit since the value of n isn't initialized, it can happen to be just about anything, any junk that happened to be on the stack at that point of time.

printf %f address error

I got a problem with printf the pointer address. I was confused with printf.Here is the code:
#include<stdio.h>
int main() {
float aa[3] = {1.0, 2.0, 3.0};
printf("%f, %f\n", aa, aa[1]);
return 0;
}
When I compiled it and got the results like this:
2.000000, 1.000000
if you want to printf the address,you should use the type of argument that is %p, not %f.
What you do is basically lying (or at least cheating) to your library. If that's intented or by accident doesn't matter.
You tell the library that you want to print a double value.
Without knowing the real type, printf fetches content for a double from the variable parameter list.
But then you put an address into parameter list which is of wrong type and wrong size.
This does not only mean that the value for this parameter is printed incorrectly, but also that a wrong number of bytes is consumed from the input.
Therefore also the second parameter can be printed incorrectly because printf is reading from the wrong address.
You can use %p for printing the address,
Here aa and &aa[0] are both same, which holds the base address of the array.
try this:
printf("%p %p",&aa[0],aa); /*Which will give you the base address of array*/
You will get the o/p in Hex format.

Why does the strange value come out with an unnecessary % conversion in the code in C language?

I started learning programming only few days ago, so basically I have no knowledge.
I'm starting with C, and I wrote a very simple code which is:
int main (int argc, const char * argv[])
{
printf("%d + %d", 1 + 3);
return 0;
}
with the code above, I got the value of 4 + 1606416608 and later found that the return value is wrong because I put more %d than necessary. Then my question is, how did that strange value actually come out? If anyone knows, please help me. Thank you!!
You know what you did wrong already, so to explain what your particular implementation of C probably did:
When you call printf, a new stack frame is pushed to the call stack. The call stack is a last in first out structure with one 'frame' per called function. So if main called logStuff which called printf then three consecutive frames would be for main, then logStuff, then printf. When printf returns, it's frame is removed from the structure and execution continues with logStuff.
So a frame usually contains at least the parameters passed to the function and storage for local variables. Those things may be one and the same, it's implementation dependant.
With a variadic function like printf there's a stream of unnamed parameters. The bit patterns will be put into an appropriate place in the frame. But C is not a reflective language. Each bit patten doesn't inherently have a meaning: any one could be an integer, a float, or anything else. It also isn't a language that invests in bounds checking. You're trusted to write code that acts correctly.
printf determines the types and number of unnamed parameters from the string. So if you've given it false information, it will interpret the bit patterns with something other than their correct meaning and it may think there are fewer or more than are really there.
You told it there were more. So what probably happened was that the parameters were in the equivalent of an array and it read a value from beyond the end of the array. As it's all implementation dependent, that value may have been meant to represent anything. It could be the address of the caller. It could be uninitialised storage for another local variable. It could be bookkeeping. It could be the format string, incorrectly interpreted as an integer.
What it isn't is any reliable value. It may not even always be safe to read.
You are in undefined behavior land... you are telling a variadic function that you have 2 int sized params, then you only supply one, you are leaking something from the stack.
1) %d is a format specifier, it tells the compiler how you want to access the value stored at a particular location.(here as an integer)
2) For every format specifier you need to provide a corresponding variable or a value, otherwise at runtime you will get "garbage" i.e. some random value.
Example :
int main()
{
int a = 65;
printf("\na = %d", a); // here the value stored in a is accessed as an integer.
printf("\na = %c", a); // the value inside a is accessed as a character.
return 0;
}
In the above example '%d' in the first printf statement tells the compiler that the value stored in the variable a is to be accessed as an integer. (o/p - 65)
In the second printf statement '%c' is used to access the same variable as a character.(o/p - A)
Your code expects two numerical parameters to be printed, and you're giving it one.
Expected:
printf("%d + %d", <some_num>, <another_num>);
You're giving it:
printf("%d + %d", <some_num>);
Where <some_num> is what 1+3 evaluates to. The function expects another argument, but receives garbage instead.
What you should do is
printf("%d + %d = %d", 1, 3, 1+3);

scanf crashes when trying to read a float into an array

This is my code:
double values[8], cumulative[8];
printf("Enter first decimal number: ");
scanf("%f", values[0]);
printf("values[0] = %g", values[0]);
My problem is that the scanf statement crashes the program, and the second printf is never executed. My original attempt was to fill each slot of the array with a double, but since that didn't work I simplified the program to this, but this doesn't work either.
I'm a beginner learning C, so I probably made a stupid mistake I just can't see. Any help would be appreciated, thanks!
Edit:
Okay, so apparently I need to add an ampersand to the scanf statement. But I thought an array was just a pointer to the first element of the array? Why do I have to use the ampersand?
scanf("%f", values[0]); - Here address of first element should be passed to scanf. You are passing value of first element which is a garbage value so that it crashed.
values[0] is *(values + 0), so this will give value of the first element not the address of the first element.
Do scanf("%lf", &values[0]); or scanf("%lf", (values + 0)); or scanf("%lf", values);
As it is double use %lf instead of %f.
One more problem in your program is uninitlized variables. Try to initialize the variable to zero while declaring.
double values[8] = {0};
double cumulative[8] = {0};
Acessing some wrong pointer in some place of your code will leads to 100% crash if its initiliazed to zero. Otherwise it will try to access some garbage value pointer which will leads to memory corruption, this sometimes will not crash instead will give unexpected output. But this also has a 50% chance of getting crash, which you are getting now.
scanf("%f", values[0]);
You need to pass the address of a location to store in to scanf(). It needs to be:
scanf("%f", &values[0]);
Otherwise, you're just telling scanf() to store the input value to whatever memory location is pointed at by the integer representation of the initialized value of values[0] -- which is most definitely not what you want.
The format for scanning a double is %lf; %f is for float. This is different from printf(), which confuses people — me too. You also need to pass a pointer to the variable.
If you use GCC, it should be warning you about a format mismatch. If it doesn't, you aren't compiling with enough warning options enabled (-Wall is a good start point; add -Wextra and -Werror if you can). The explicit option for checking printf() and scanf() formats is -Wformat, but it is included with -Wall.
#include <stdio.h>
int main(void)
{
double values[8];
printf("Enter first decimal number: ");
if (scanf("%lf", &values[0]) != 1)
printf("Scan failed!\n");
else
printf("values[0] = %g\n", values[0]);
return(0);
}
Note that this includes a newline at the end of the output, and also diagnoses when there is a problem (such as no data, or invalid data) on the input.
I thought an array was just a pointer to the first element of the array? Why do I have to use the ampersand?
An array is not just a pointer to the first element of the array, but when an array name is used in an expression other than as an argument of sizeof(), it changes to the pointer to the first element of the array.
You have to use the ampersand because values[0] is the value of the first element of the array, not the address of the first element of the array, and scanf() needs the address, not the value. Remember: a[i] == *(a + i) for an array name or pointer a and an index i, and note the * to dereference the pointer. If you wrote scanf("%lf", values) or scanf("%lf", values + 0), you are passing a pointer. Note that passing scanf("%lf", &values) would be a type mismatch (though the value passed as the address is the same — so it coincidentally 'works'). The type passed would be 'pointer to array of 8 double', which is not the same as 'pointer to double'.

Resources