Why I can't printf value of pointer in C? - c

I have a simple questions. I am new in pointers in C and I don't understand why this is working and I can change value of the pointer
int main()
{
int x = 7;
int *aptr = &x;
printf("%d",*aptr);
*aptr = 21;
printf("%d",*aptr);
}
But this won't print any number
int main()
{
int x = 7;
int *aptr = 21;
printf("%d",*aptr);
}
Thanks for help!

int *aptr = 21; does not store 21 in *aptr. When = is used in a declaration, it sets the initial value for the thing being declared (which is aptr), not for the “expression picture” used for the declaration (*aptr).
In C declarations, we use pictures of a sort to describe the type. Generally, in a declaration like int declarator, declarator gives a picture of some expression we will use as an int. For example, int *foo says *foo will be an int, so it declares foo to be a pointer to an int. Another example is that int foo[3] says foo[i] will be an int, so it declares foo to be an array of int. Note that these are declaring foo, not *foo or foo[i], so, when an initial value is given, it is for initializing foo, not *foo or foo[i].
21 is not a proper value for a pointer, so the compiler complains. (Integers can be converted to pointers by using casts, but this is a special use case that requires ensuring the integers represent addresses made available in the C implementation.)

While others provided correct answers to your question, the best way to have obtained that answer was to let the compiler tell you what the problem is. When you compile your program using, say, gcc - the default compiler on most Linux machines - you get:
$ gcc -o prog prog.c
prog.c: In function ‘main’:
prog.c:6:17: warning: initialization of ‘int *’ from ‘int’ makes pointer
from integer without a cast [-Wint-conversion]
6 | int *aptr = 21;
| ^~
... and this is basically what #EricPostpischil has told you :-)
Microsoft's Visual C++ will also say something similar (godbolt.org).
So, reading the warnings your compiler generates is very important!
Also, you should consider compiling with additional compiler warning flags enabled. Read about that here:
Why should I always enable compiler warnings?

Pointer store address of variable not value.
Here , you are declaring int *aptr as an integer pointer which means that it will store the address of any integer variable not an integer.
int x = 7; // x is an integer variable.
int *aptr = 21; // aptr is an integer pointer.
you should write :
int *aptr = &x;
1X
____ ____
aptr | 1X | ----------> x | 7 |
aptr is pointing to 1X which is address of integer variable x.

So you are currently setting the address stored in aptr to 21.
This would be equivalent to setting :
int a = 7;
int *aptr = 0xFFFFFFFF //this could be a memory address
You have simply assigned what aptr points to as the memory address 7, but you don't know what is being stored at this address (or if it's in scope) so this is why you are getting an error.
To learn more about pointers try taking a look at this article : https://www.tutorialspoint.com/cprogramming/c_pointers.htm

Related

Pointers in C: why is the * needed in *address_of_x = &x when getting the address of x?

Suppose we have the following code, which takes x, stores the value 4 in it, then stores the address of x in a pointer variable:
int x = 4;
int *address_of_x = &x;
What is the purpose of the * in int *address_of_x?
I understand * to be used for dereferencing a pointer - it takes an address and tells you what's stored there. But if an address is being stored, then what are we dereferencing? Or are we not dereferencing anything at all? Why isn't it written as:
int address_of_x = &x;
* in int *address_of_x = &x; is not de-referencing #Eugene Sh.
It is part of the type declaration: pointer to int.
int x = 4;
int *address_of_x = &x;
same as
int x = 4; // declare x as int
int *address_of_x; // declare address_of_x as pointer to int
address_of_x = &x; // Assign the address of x to address_of_x
Why isn't it written as: int address_of_x = &x;
&x is not an int. &x is an int *, a pointer (or address). A pointer is not an integer.
In an expression, the * is the dereference operator. In a declaration (which you have here), it's part of the syntax of a pointer declarator. You're declaring address_of_x to be a pointer to int rather than just an int.
The idea that was behind this syntax is that declarations and usage of identifiers should look similar (you typically use a pointer by dereferencing it) for convenience.
Also note that the * is needed for every identifier declared as a pointer, even if you declare multiple identifiers in a single declaration, like this:
int *a, *b;
If you write
int *a, b;
instead, b would not be a pointer. In general, it's best practice to avoid declaring more than one identifier per declaration, though.
int *address_of_x = &x; isn't an assignment. int *address_of_x = &x; is a declaration (int *address_of_x) with initialization (= &x) (note that in pre-historic C, initializations (as opposed to assignments) were done without the =, which made them even more distinct from assignments).
Declarations in C mirror usage. int *address_of_x declares that *address_of_x is of type int, ergo address_of_x is of type pointer to int. The = &x part then initializes this pointer to int to &x (address of x).
That's the definition of a pointer, the type for address_of_x variable is int *, a pointer to int. There's no "dereference" happening there.
Why isn't it written as:
int address_of_x = &x;
Well, two things
C is a strongly typed language.
the variable names do not carry any connection with their type
Simple answer: The asterisk in a variable declaration or definition statement is NOT a dereference operator. Instead it's a modifier.
In the given context, an asterisk means "Define the mext identifier as a pointer to the base type".
You surely won't ask why [10] doesn't mean "take the 10th element of the array" in int a[10]. Well, so-so. The brackets here also aren't the bracket operator, for exactly the same reason.
Why isn't it written as:
int address_of_x = &x;
The compiler never tries to interpret the literal meaning of identifiers. It only looks for modifiers when determining the type of an iddentifier in a declaration statement.
i.e., this code will not work as what it looks like:
int *not_a_pointer, not_an_array[10];
float a_character;
int *address_of_x = &x; declares a variable of type "pointer to int" (int *address_of_x) and then initializes it with the address of x (= &x).
So this * is not the dereferencing but is part of the declaration.
These two snippets are functionally the same:
int *address_of_x = &x;
and
int *address_of_x;
address_of_x = &x;
In the first case you defined and initialised the pointer all in one statement, but it can look like the wrong syntax. In the second example the definition and the value assignment are separate statements, and the code is clearer.
There is no dereferencing (yet).

Just tried smth simple with pointers in C and it is confusing

I wanted to explore what happens, if you pass a value to the address of a pointer without declaring the address itself before. After the declaration I assigned the address of a as a value for the pointer itself. When I print now the value of a, I always get 8 as an output, no matter if I change the datatype or the value of *ptr. Why?
#include<stdio.h>
int main(){
int a, *ptr = 190;
ptr = &a;
printf(%d, a);
return 0;
}
OUTPUT:
8
Little correction: The datatype does matter, with char and short, I get always 0. With int, long int and so on, I get always 8. And with double, I get 4200624. It is still confusing.
int a, *ptr = 190; must normally throw, at least, a warning at compile time, because you tried to assign an int value to initialize a pointer. On my compiler I got:
a.c:3:11: warning: incompatible integer to pointer conversion initializing
'int *' with an expression of type 'int' [-Wint-conversion]
int a, *ptr = 190;
^ ~~~
It is probably not what you wanted, assigning a fixed value to a pointer is of very specific usage.
printf(%d, a); is an error as printf first argument must be a char *. You probably wanted to write printf("%d"...). My compiler said:
a.c:5:10: error: expected expression
printf(%d, a);
^
Even in this case the whole program as undefined behavior because you are trying to read a variable (a through the pointer ptr) that was not assigned before.
You probably wanted to write something like:
#include<stdio.h>
int main(){
int a, *ptr;// definition of two variables, one of type int, one of type pointer to int, both non initialized
ptr = &a; // ptr points to variable a (contains its address)
*ptr = 190; // assignment of the variable pointed by ptr
printf("%d\n", a); // should print 190 as the content of a has been previously assigned
return 0;
}

Different ways to assign pointer in C , using & or *?

In C , if i want a pointer reference to a variable
int c = 12 ;
int *p ;
p = &c ;
or i can do it this way
int c = 12;
int p;
p=&c;
in both case value of p is the address of c , can you please tell the problems i will be facing .
You cannot do it this way:
int c = 12;
int p;
p = &c;
This is not valid C to assign a pointer value to an integer object. Enable all your compiler warnings, the compiler has to give a diagnostic message for the invalid assignment.
In the first case, there is no problem as p is a special type of variable which can contain address. Thus here p is called a pointer variable.
In second case, p is normal scalar variable which cannot contain address. So there is a problem. Compiler implicitly will not be able to assign the address of c variable to the variable p
& and * mean different things in different contexts.
& in a variable declaration (including in a function parameter) means "reference" or "by reference" in C++, and is not allowed in C. In C++, the type of j below is "int". It doesn't modify the type, but says "this is another name for existing data" rather than "create a space for new data".
int i = 5;
int &j = i; //C++ only: j is another name for i
int f(int & x); //f is a function that takes in an int by reference
* in a variable declaration means "pointer". The type of int* is "pointer to an int", while, again, the type of int& (C++ only) is int. It modifies the type.
int *p = NULL; //p is a pointer to an int, that currently points to nothing.
int f(int & x); //f is a function that takes in an int by reference
& in front of an existing variable means "a pointer to", or "address of". It's an operator, which can be thought of as a special kind of function. It takes in anything and returns a pointer to that thing.
int i = 5;
int *p = &i; //p points to i
int **pp = &p; //pp points to p
* in front of an existing variable means "what this is pointing to", also known as the dereference operator. Like &, it's an operator. It can only be applied to a pointer, and it returns what the pointer is pointing to.
int i = 5;
int *p = &i; //p points to i
int j = *p; //j copies what p is pointing to
So if I say *&var, that is the same as var, because it means "dereference the pointer to var".
int c = 12; int p; p=&c;
introduces the risk of losing bits from the address of c.
If you really need to store an address as integer then use uintptr_t as target integer type, as it's guaranteed by the C standard to be wide enough to store an address:
int c = 12; uintptr_t p; p = (void*)&c;
uintptr_t comes in <stdint.h>.
7.18.1.4 Integer types capable of holding object pointers
1
The following type designates a signed integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
intptr_t
The following type designates an unsigned integer type with the property that any valid
pointer to void can be converted to this type, then converted back to pointer to void,
and the result will compare equal to the original pointer:
uintptr_t
These types are optional.
However to have this integer converted back to a pointer to an integer it casting needs to go via (void*):
int * pi = (void*)p;

Warnings in a very basic Pointer Program in C

I've just started with pointers in c. This program gives the desired output but I am getting the below warnings when I compile it, What am I doing wrong?
pointer.c:3: warning: initialization makes pointer from integer without a cast
pointer.c:5: warning: incompatible implicit declaration of built-in function ‘printf’
pointer.c:8: warning: assignment from incompatible pointer type
pointer.c:12: warning: assignment makes pointer from integer without a cast
And my code is:
int main (int argc, char *argv[])
{
int *x=2, *ampx, *starampx, starx;
printf("x=");
printf("%d\n",x);
ampx=&x;
printf("&x=");
printf("%d\n",&x);
starampx=*ampx;
printf("*&x=");
printf("%d\n",starampx);
return 0;
}
Here is why:
initialization makes pointer from integer without a cast - int *x = 2, ... should be int x = 2, ...
incompatible implicit declaration of built-in function ‘printf’ - You need to add an #include <stdio.h> line at the top
assignment from incompatible pointer type - This will be fixed by the #1 change
assignment makes pointer from integer without a cast - *starampx should be starampx in the declaration.
In addition, printing pointers should be done with %p specifier, not %d:
printf("%p\n",&x);
Here is your fixed program on ideone: link.
int *x=2
is actually causing your program to have undefined behavior. It tells the compiler to point at an address 2, which may or may not be valid and derferencing the pointer will causes an undefined behavior.
Whenever you are using pointers, You need to make the pointer point to a valid memory big enough to store a int before you can store anything. So you either need:
int i = 2;
int *x = &i;
or you simply use:
int x = 2;
Considering, how you use x later in the program the latter is what you need.
You need to include stdio.h which tells the compiler that printf is an standard c library function.
In your code, in this statement, you have a problem.
int *x=2, *ampx, *starampx, starx;
^ ^
| |
*x is a pointer. To store the value of 2, you would need to allocate space for the same. Instead of the current implementation, please try with
int x=2, *ampx, starampx, starx;

which definition is better?

#include<stdio.h>
int main(int argc , char *argv[])
{
int array[2][2] = {{1,100},{1000,10000}};
int *pointer = array;
int *ppointer = &array;
int *pppointer = array[0];
int *ppppointer = &array[0];
printf("%d\n",*pointer);
printf("%d\n",*ppointer);
printf("%d\n",*pppointer);
printf("%d\n",*ppppointer);
return 0;
}
Four pointers are point to the first element of array.
which definition shown above is better?
And I don't known why the same value to array and &array?
The only reason all for of your definitions compile is that your C compiler is too permitting when it comes to pointer type conversions. If you use some switches that make it more pedantic in this regard, it should immediately tell you that only the third initialization is valid, while the rest are erroneous.
In most contexts (with a few exceptions) when array of type T[N] is used in an expression, it "decays" (gets implicitly converted) to pointer type T * - a pointer that points to its first element. In other words, in such contexts for any array A, the A expression is equivalent to &A[0]. The only contexts where array type decay does not occur are unary & operator, sizeof operator and string literal used as an initializer for a char array.
In your example array is a value of int [2][2] type. When used on the right-hand side of initialization it decays to pointer type int (*)[2]. For this reason this is invalid
int *pointer = array;
The right-hand side is int (*)[2], while the left-hand side is int *. These are different pointer types. You can't initialize one with the other.
The
int *ppppointer = &array[0];
is exactly equivalent to the previous one: the right-hand side produces a value of int (*)[2] type. It is invalid for the very same reason.
The &array expression produces a pointer of int (*)[2][2] type. Again, for this reason
int *ppointer = &array;
is invalid.
The only valid initialization yo have in your example is
int *pppointer = array[0];
array[0] is an expression of int [2] type, which decays to int * type - the same type that you have on the left-hand side.
In other words there's no question of which one "better" here. Only one of your initialization is valid, others are illegal. The valid initialization can also be written as
int *pppointer = &array[0][0];
for the reasons I described above. Now, which right-hand side is "better" (array[0] or &array[0][0]) is a matter of your personal preference.
In order to make your other initializations valid, the pointers should be declared as follows
int (*pointer)[2] = array;
int (*ppointer)[2][2] = &array;
int (*ppppointer)[2] = &array[0];
but such pointers will have different semantics from an int * pointer. And you apparently need int * specifically.
Only the third actually does the right thing. All other three are invalid C++ and cause warnings in my C compiler. It is often preferable to write C that is also valid C++, because on some platforms the C++ compiler is the also recommended compiler for C also (MSVC). This also makes it easier to include C code in a C++ project without significant build-system fiddling.
Why does your compiler complain about about 1, 2 and 4? Neither of the expressions on the right hand side have the right type to be converted to int*.
array has type int[2][2] it can be converted to int(*)[2], not int*
&array is a pointer to an int[2][2]
array[x] has actually type int*
&array[x] has type int**
int *pointer = array; //Incorrect
int *ppointer = &array; //Incorrect
int *pppointer = array[0]; //Correct
int *ppppointer = &array[0]; //Incorrect
That's the short version.
Now for the reasons.
The first pointer is incorrect, because you're assigning 'array' (which is a pointer without any further specification)...but not one of int, but one of int *[]
The second pointer is incorrect, since you'd be assigning the address of the pointer...essentially the address of the variable, which holds the pointer to the data.
The third one is correct, because you get a pointer to an int array, regardless of size.
The fourth one is incorrect, since you're copying the address of the first array.
That makes it an int **, and not a int *.
Sorry for the many edits...I must be tired.
Short answer:
$ cat decls.c
int main(void)
{
int array[2][2] = {{1,100},{1000,10000}};
int *pointer = array;
int *ppointer = &array;
int *pppointer = array[0];
int *ppppointer = &array[0];
}
$ clang decls.c -Wall -o decls
decls.c:4:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int [2][2]' [-Wincompatible-pointer-types]
int *pointer = array;
^ ~~~~~
decls.c:5:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int (*)[2][2]' [-Wincompatible-pointer-types]
int *ppointer = &array;
^ ~~~~~~
decls.c:7:7: warning: incompatible pointer types initializing 'int *' with an
expression of type 'int (*)[2]' [-Wincompatible-pointer-types]
int *ppppointer = &array[0];
^ ~~~~~~~~~
So only the third declaration is correct.
Slightly long answer: when you declare something in C, you declare it using an expression which, when evaluated, gives you the type at the left.
So, if you have a char name[][], then it means that when you have name[2][3], you get a char. This works the other way around: let A = name[3]; how can you can get a char out of A? By doing A[2], so A is a char *.
This is why only the third declaration is correct: because the declaring expression at the left and the expression at the right both have the same type.
None of them are correct (third one will not give error but I don't think it will be the value the poster want).
It should be:
int ** pointer1 = array;
int ** pointer2 = &array; //This one is wrong
int ** pointer3 = array[0]; //This one is not correct in this case
int * ppointer3 = array[0];
int ** pointer4 = &array[0];
int * pointer5 = &array[0][0];
I prefer the first one and last one.
If it is a 1-dimensional array, I would prefer the first one, because it shows the fact that array is basically pointer. If it is a multi-dimensional array, I would use the last one (because it only needs dereference once to get the value, but be careful about the index: for example if you want to get 1000, you will need to use pointer5[2] instead of pointer5[1][1]
They are all equivalent.
&array is the address of the array, which start at the same position as its first element and therefor &array = &array[0]
array is an array but in some case, it can decay into a pointer to its first element, that is why array = &array = &array[0]
As for
int *pppointer = array[0];
my first impression is that this should be wrong. may be someone else can explain.
Update: My guess is that array is considered as a pointer by the compiler here giving:
int *pppointer = (&array)[0] = array[0]
So, you have an array within an array. So the variable "array" is actually a pointer to another pointer.
So if you say:
int *pointer = array;
You've got a type mismatch. *pointer is a pointer to an int, but array is a pointer to another pointer.
When you say:
int *ppointer = &array;
You've still got a type mismatch. &array gives us the address of the pointer to a pointer, which we could only assign to a pointer to a pointer to a pointer.
When you say:
int *pppointer = array[0];
This is correct. Square brackets dereference the array variable. So array[0] actually refers to a pointer to an int, which matches up with *pppointer's type.
When you say:
int *ppppointer = &array[0];
So, we're kind of back to where we started here. array[0] is a pointer to an int, so &array[0] is the address of a pointer to an int, which we could only assign to a pointer to a pointer to an int.
So in the end, the third one is the only one that is actually valid. However, I personally think a better way to accomplish this would be:
int *pointer = *array;

Resources