How does the scanf function work in C? - c

Why do you require ampersand (&) in the scanf function. What will the output or type of error (compile or runtime) be in the following C code?
#include <stdio.h>
void main() {
int a;
printf("enter integer:");
scanf("%d", a);
}

The & in C is an operator that returns the address of the operand. Think of it this way, if you would simply give scanf the variable a without the &, it will be passed to it by-value, which means scanf will not be able to set its value for you to see. Passing it by-reference (using & actually passes a pointer to a) allows scanf to set it so that the calling functions will see the change too.
Regarding the specific error, you can't really tell. The behavior is undefined. Sometimes, it might silently continue to run, without you knowing scanf changed some value somewhere in your program. Sometimes it will cause the program to crash immediately, like in this case:
#include <stdio.h>
int main()
{
int a;
printf("enter integer: ");
scanf("%d",a);
printf("entered integer: %d\n", a);
return 0;
}
Compiling it shows this:
$ gcc -o test test.c
test.c: In function ‘main’:
test.c:6: warning: format ‘%d’ expects type ‘int *’, but argument 2 has type ‘int’
And executing shows a segmentation fault:
$ ./test
enter integer: 2
Segmentation fault

In C, all function arguments are passed by value; any changes to the function's formal parameter are not reflected in the actual parameter. For example:
void foo(int bar)
{
bar = bar + 1;
}
int main(void)
{
int x = 0;
printf("x before foo = %d\n", x);
foo(x);
printf("x after foo = %d\n", x);
return 0;
}
The output of the program will be
x before foo = 0
x after foo = 0
because bar receives the value of x (0), not a reference to x itself. Changing bar has no effect on x.
In C, the way around this is to pass a pointer to a variable:
void foo(int *bar)
{
*bar = *bar + 1;
}
int main(void)
{
int x = 0;
printf("x before foo = %d\n", x);
foo(&x);
printf("x after foo = %d\n", x);
return 0;
}
Now the output of the program is
x before foo = 0
x after foo = 1
This time, the formal parameter bar is not an int, but a pointer to int, and it receives the address of x (given by the expression &x in the call to foo), not the value contained in x. The expression *bar means "get the value in the location bar points to", so *bar = *bar + 1 corresponds to x = x + 1.
Since scanf() needs to write to its arguments, it expects those arguments to typed as pointers. The "%d" conversion specifier expects the corresponding argument to be a pointer to int (int *), the "%u" conversion specifier expects a pointer to unsigned int (unsigned *), "%s" expects a pointer to char (char *), "%f" expects a pointer to float (float *), etc. In your example, since a is typed int, you need to use the expression &a to get a pointer.
Note that if a were already a pointer type, you would not need to use the & operator in the call to scanf():
int main(void)
{
int a, *pa; // declare pa as a pointer to int
...
pa = &a; // assign address of a to pa
scanf("%d", pa); // scanf() will write to a through pa
...
}
Note also that when passing an array to a function (such as when using the "%s" conversion specifier to read a string), you don't need to use the & operator; the array expression will implicitly be converted to a pointer type:
int main(void)
{
char name[20];
...
scanf("%19s", name); // name implicitly converted from "char [20]" to "char *"
...
}

If you're asking a question like this, I would recommend just learning for now "it just does".
You will learn that you need an ampersand because scanf takes one or more pointer arguments. If a is an int variable, it is not a pointer. &a ("the address of a") is a pointer, so it will work with scanf.

This is because in C, functions parameters are passed by value. In order for the scanf() function to modify the 'a' variable in your main() function, the address of 'a' shall be given to scanf(), hence the usage of the ampersand (address of).

Because scanf requires a pointer to the variable (i.e. a reference) that the value will go into.

You don't always need to use an & with scanf. What you need to do is to pass pointers. If you're new to C, you should spend some time reading the comp.lang.c FAQ:
http://c-faq.com/
Specifically:
Why doesn't the call scanf("%d", i) work?
Why does the call scanf("%s", s) work?

The '&' in scanf is only required to get the address of a variable. You can use scanf without '&' by using pointers:
int myInt;
int * pointer_to_int;
pointer_to_int = &myInt;
scanf("%d", pointer_to_int);
In general, using '&' is often easier than creating pointer to avoid using the '&'.

Related

Basic C Pointers

For some reason when I try to compile this code in the C program it is giving me back an error. I am trying to print out the actual memory address of variable x. If anyone knows I would appreciate it!
Code:
int x = 7;
printf("x is %d\n", x);
x = 14;
printf("x is %d\n", x);
int *aptrx = malloc(sizeof(int));
aptrx = &x;
printf("aptrx is %x\n", aptrx);
Error:
*pointer.c:12:29: error: format specifies type 'unsigned int' but the argument has type* 'int \*' [-Werror,-Wformat]
You do not need to have this line in your code if you just want to print the address of x.
int *aptrx = malloc(sizeof(int));
You do not need to allocate memory whenever you create a pointer variable. If you want to point to an existing variable, which you want in this case, you can simply do
int *aptrx = &x;
Then try to print the address using below line using the format specifier %p.
printf("aptrx is %p\n", aptrx);
You are having an error because the format expects an unsigned int but the argument is an int *.
The manual for printf says about the %x conversion specifier:
The unsigned int argument is converted [...] to unsigned hexadecimal (x and X)
notation.
If you want to print a pointer, you can use the %p conversion specifier.
The void * pointer argument is printed in hexadecimal (as if by %#x
or %#lx).
Like this:
printf("aptrx is %p\n", aptrx);
It's not necessary to allocate memory dynamically to create a pointer variable.
int *aptrx = malloc(sizeof(int)); //unnecessary
Simply, create a pointer variable just like any other variable
int *aptrx = &x;
To print out the value of the pointer (i.e. address of x), use the format specifier %p or %u:
printf("aptrx is %p\n", aptrx);

cannot understand this error

As I am a beginner in C
When I run the following C code :
#include<stdio.h>
void f(int *p)
{
*p=3;
}
int main()
{
int *p;
f(&p);
return 0;
}
I get these messages after compilation:
1) warning:passing arg 1 of 'f' from incompatible pointer type f(&p)
2) note: expected 'int *' but argument is of type 'int **' void
f(int *p)
Please note:
&p is the memory address of a variable
*p is the actual value of the variable
So what you are doing is:
In main: You are generating a variable pointer p. And you are passing this pointers address to a function f.
f thinks it gets a pointer as parameter but it gets a memory address and obviusly can't handle it.
More information is here
Hope I could help!
You're passing a pointer to a pointer as an argument to a function expecting a pointer to an int. They're two different types and the compiler will complain.
There is another issue where you have the 'pointer' to the int but not the space allocated to store it. There are a couple solutions to this situation.
1)
{
int q; // add a new int, to which p points to. this allocates memory for an int
int *p = &q;
f(p); // don't pass a pointer to a pointer, just the pointer
return 0;
}
2)
{
int p; // have p be the int in the first place, not a pointer
f(&p); // your original call is unchanged and works now
return 0;
}
It's hard to think about this, because there are multiple levels of pointers.
Here's a simpler example. This is what we might call "pass by reference":
#include <stdio.h>
void f(int *ip)
{
*ip = 5;
}
int main(){
{
int i = 7;
printf("%d\n", i);
f(&i);
printf("%d\n", i);
}
Function f accepts a pointer to an int. It modifies that int. In main, we have an int variable i. We take the address of that variable using &, and pass the resulting pointer to function f. In this way, function f is able to modify i in the caller. Note that function f takes a pointer to something, and that what it takes a pointer to is the type of i in the caller -- in other words, pointer to int.
Now let's look at another example. This time, instead of manipulating an int by reference, we're going to manipulate a pointer variable, a char *. (We're going to end up dealing with pointers to pointers.)
void g(char **sp)
{
*sp = malloc(10);
strcpy(*sp, "oranges");
}
int main(){
{
char *s = "apples";
printf("%s\n", s);
g(&s);
printf("%s\n", s);
}
Again, function g accepts an argument by reference. Again, function g is able to modify a variable in its caller. Again, the pointer type accepted by g is a pointer to the type being manipulated. Since the type being manipulated is "pointer to char", function g accepts a pointer to pointer to char, or char **.
But the code you posted is sort of a mixture of the two. Your function f accepts an int pointer, just like mine, and it tries to use that int pointer to modify an int variable in the caller. But then, in your main function, the variable you're trying to modify isn't an int, it's a pointer to int, or int *.
When you call
f(&p);
you're starting with a pointer-to-int, p, and you're taking its address with &, resulting in a pointer-to-pointer-to-int. But then you;re calling function f, which expects a pointer-to-int. That's what the compiler is trying to tell you with the messages
warning: passing arg 1 of 'f' from incompatible pointer type
note: expected 'int *' but argument is of type 'int **'

array and pointer chain

As written in c books,an array name is a pointer to first element so here in names array,names points to first element which is also a pointer to string literal,then *names will print the first element,but in next line of code p points to a,and q points to q like names arr,but as u print *q u dont get a value which is 3,why?
#include <stdio.h>
int main(void){
char *names[]={"jack","philip"};
printf("%s\n",*names);
int a=3;
int *p=&a;
int *q=&p;
printf("%i\n",*q);
return 0;
}
a is an int, so p is a pointer to an int (int *), thus q is a pointer to a pointer to an int (int **). To print an int, you feed that int to printf:
printf("This is an int: %i\n", 42);
So for %i the function printf expects an argument of type int, but you pass *q to it, which is of type int *. You pass a pointer to printf, which does not expect a pointer for numbers, only for strings.
The difference is in printf(). The %s expects a pointer to a null terminated string, while %i expects to be handed the number itself, not a pointer to the number, which is what you have.
This is what the working code should look like
#include <stdio.h>
int main(void) {
char *names[]={"jack","philip"};
printf("%s\n",*names);
int a=3;
int *p=&a;
int **q=&p;
printf("%i\n",**q);
return 0;
}
%s expects a char* which as you correctly stated is what *names is, since names is of type char**. However %i expects an int. Since p points to a, p is an int pointer, since q points to p q is a pointer to an int pointer. q is just whatever p is pointing at (the address of a) so it won't print what you want. also assigning type int to the address of an int* (which is what youre doing when you do int* q = &p) will have unexpected results
printf("%i", *q);
would be like doing
printf("%c", *names);
which obviously will give strange output

What is the difference between scanf("%d", *p) and scanf("%d", p)?

Pointers are a new thing for me and I'm struggling to understand it, but I won't give in and hopefully learn it.
What would be the difference between scanf ("%d", *p) and scanf ("%d", p)?
In examples I saw that if I want to input some value in a variable, I should use scanf ("%d", p). That doesn't make sense to me. Shouldn't it be scanf ("%d", *p)?
I interpret it as: "put some integer value where the pointer is pointing" and for instance it is pointing on variable x and then it should be x = 10, but it isn't. And how then to use scanf() and pointers to set values in an array?
Where and what am I getting wrong? I'm trying to learn this using C language, since it is the one which I'm supposed to use in my class.
For example:
#include <stdio.h>
int main () {
float x[10], *p;
int i;
p = &x[0];
for (i = 0; i < 10; i++) {
scanf("%d", p + i);
}
for (i = 0; i < 10; i++) {
printf("%d", *(p + i));
}
return 0;
}
Why is only p + i in the first for () {} and *(p + i) in the second loop? I would put *(p + i) also in the first for () {}. *(p + i) to me is like: "to what the (p+i)th element is and make it equal some value".
*p means go to the place p points to
&p means take the address of p, or "get a pointer to" p
int i;
scanf("%d", &i); // gives scanf a pointer to i
int i;
int *p = &i;
scanf("%d", p); // a more contrived way to say the same thing
The obligatory visual explanation is Pointer Fun with Binky.
You can read the types from right to left:
int *p => "p has type int *" => p is a pointer to an int
int *p => "*p has type int" => *p is the int pointed to by p
One is right, the other is wrong. (Or both may be wrong, depending on what p is.)
If you call
scanf("%d", SOMETHING);
then SOMETHING must be a pointer to an int.
If you have an int object, use unary & to get its address (i.e., a pointer to the object):
int n;
scanf("%d", &n);
If p happens to be an int*, then you can use its value:
int *p;
scanf("%d", p);
But here I haven't assigned a value to p, so this compiles but has undefined behavior. This is ok:
int n;
int *p = &n;
scanf("%d", p);
As for using *p, that would be valid only if p is a pointer to a pointer to an int:
int n;
int *p0 = &n;
int **p = &p0;
scanf("%d", *p);
But it would rarely make sense to do that. The vast majority of the time, the argument is going to be simply the address of some int object, like &n.
If n is an int, then just passing n to scanf wouldn't make sense. You'd merely be passing the current value of n. The point is that you want to permit scanf to store a new value in n, and to do that, scanf need's the address of n.
Function calls in C pass arguments by value, not by reference. This means that when you call a function with arguments, the function receives copies of the arguments, and that function cannot directly modify the original arguments from the callsite. That is:
int x = 42;
foo(x);
printf("%d\n", x);
foo cannot change the variable x, and the code will always print 42.
But there are many cases where a function might want to modify the arguments from the caller. scanf is one such case. To accomplish this, these functions require using a level of indirection. Instead of passing the variable to be modified directly to the function, the caller instead passes a pointer to that variable. The function then receives a copy of the pointer, and by dereferencing it, can access and can modify the variable it's pointing to.
I recommend spending some time reading the comp.lang.c FAQ. This topic is discussed in:
12.12a Why doesn't the call scanf("%d", i) work?
12.12b Why does the call scanf("%s", s) work?
If p is the variable (say, an int), you would use &p to pass its pointer to scanf. p alone is not a pointer, and *p compounds the problem.

gcc warning: assignment makes integer from pointer without a cast

I am making this assignment in my program and I am getting the warning a titled. Here is the code snippet:
table_name[index] = NULL;
I could not understand what can be a problem in such a statement.
NULL is not a valid integer, and it is being assigned to an entry of an array made up of presumably ints, so the compiler is complaining.
NULL is used as a default pointer value that indicates "nothing" .. if you had a pointer variable and assigned NULL to it, you'd be saying that pointer variable points to "nothing".
Because of this type mismatch, the specific message is warning you that you are trying to assign one type (really a pointer value) to another (int) without trying to cast it (which is how we sometimes convert one type to another in order to avoid type mismatches).
If you had an array of pointers this assignment of NULL would be perfectly ok.
The problem is that table_name[index] is an integer value, not a pointer. NULL is meant to represent pointers.
If table_name is declared as int*, you could do table_name = NULL; without issue, but when setting a value at an index, the compiler is going to expect you to use the same type as the array.
When i try to assign a pointer value into a varriable (always the same data type) then I have the same reaction from the compiler..
example:
#include <stdio.h>
#include <stdlib.h>
int main(){
int X,Y;
int *P_1;
float Z;
float *P_2;
X=5;
Z=3.5;
P_1=&X;
printf("\n X = %d, Z = %.2f\n",X,Z);
printf(" &X = %d\n",&X);
printf(" *P_1 = %d\n",*P_1);
printf(" P_1 = %d\n",P_1);
Y=X;
printf(" Y = %d\n",Y);
X=10;
Y=P_1;
fflush(stdin);
getchar();
return 0;
}

Resources