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

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;
}

Related

Incompatible pointer type pointer to array and double pointer to array

So i am new to programming and i have this program that i have to write, it has an array of integers and i have to pass it to a function with a pointer and then with a double pointer.
After i wrote the code i had this error that i couldn't find a solution to. The error is :
initialization of 'int **' from incompatible pointer type 'int *'
[-Wincompatible-pointer-type]
The code that i wrote is this:
int main(){
int i;
int arr[]={3,-15,19,0,-984};
int *p=arr;
funzione(p,sizeof(arr)/sizeof(arr[0])); //The first function
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the single pointer (p)
printf("%d\n",p[i]);
int **g=p; //the error results to be coming from p in this row
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",g[i]);
funzione2(g,sizeof(arr)/sizeof(arr[0])); //The second function
return 0;
}
My question is how can i remove this error.
The variable p has the type int * while the initialized variable g has the type int **.
int **g=p; //the error results to be
These pointer types are not compatible and there is no implicit conversion from one pointer type to another.
You need to write
int **g = &p;
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",( *g )[i]);
Pay attention to that the for loop can look the same way if you will declare the pointer g also the following way
int ( *g )[5] = &arr;
for(i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",( *g )[i]);
Also the expression sizeof(arr)/sizeof(arr[0]) has the unsigned integer type size_t. So it would be better to declare the variable i also as having the unsigned type size_t instead of the signed type int.
size_t i;
Though it is even much better to declare the variable i in the minimal scope where it is used as for example
for( size_t i=0;i<(sizeof(arr)/sizeof(arr[0]));i++) //print of the double pointer (g)
printf("%d\n",( *g )[i]);
And this called function
funzione2(g,sizeof(arr)/sizeof(arr[0])); //The first function
is not the first function as it is written in the comment.:)
Note: This is not a rigorous answer but it is enough for you to continue and solve your compiler issue.
See, p has type int* while g is of type int**. They are incompatible as the error clearly states.
p is a pointer to int while g is a point to a pointer to int.
If you do int **g=&p; the compiler will stop complaining because the types now match.
The & operator takes the address of its argument (think of it like getting a pointer out of a variable). If you apply & to a pointer than you are taking a pointer out p which is a pointer already and this is how you end up with a pointer to pointer.
I suggest you to get a good C book and study pointers properly.

Why I can't printf value of pointer in 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

format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’

Each time I submit a program on hackerrank the following error occurs.
solution.c: In function ‘main’:
solution.c:22:14: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d", &sum);
It would be very helpful if someone could tell me what this means?
I assume that you have declared sum as an int. So the correct call to printf is :
printf("%d", sum);
as %d specifier means that you are going to print an int, but you are passing the int's address, which is a pointer to int, or int *.
NOTE : Do not confuse printf with scanf, as the second does require a pointer. So, for reading variable sum, you would use :
scanf("%d", &sum);
but for printing, the correct way is without &, as written above.
If you want to print the address of sum you can use printf( "%p", &sum )
Int is a primitive, primitives are data stored in memory. each data chunck is set in a specific memory block, those blocks has "memory addresses" that refer to them.
If you define int i = 1 your computer allocates an integer in memory (in a block, with a memory address f.e. 0xF00000) and sets its value to 1.
When you refer to this integer as i, you are accessing the value stored in 0xF00000, that happen to be 1.
In C you can also get the i reference (the memory address it's allocated in) by prefixing it with & (ampersand), by doing this you will get the memory address of the variable rather than its value.
i === 1; // true
&i === 1; //false
&i === 0xF00000; //true
This memory address can be assigned to a pointer (a variable that 'points' to a memory address, thus, have no it's own value) so it can be accessed directly too dereferencing it so you can gather the value inside that memory block. This is achieved using *
int i = 1; //this allocates the
int *ptr = &i; //defines a pointer that points to i address
/* now this works cause i is a primitive */
printf("%d", i);
/* this works also cause ptr is dereferenced, returning the
value from the address it points, in this case, i's value */
printf("%d", *ptr);
In your example, you are passing a reference to printf (printf asks for a value and is receiving a memory address) so it doesnt work.
Hope this helps you understand C and pointers better
#include<stdio.h>
int main(){
int var = 10;
int* a = &var;
printf("%d", a);
return 0;
}
First i Used "%d" and it shows error that format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’
then I replace "%d" with "%p" and it Works.
#include<stdio.h>
int main(){
int var = 10;
int* a = &var;
printf("%p", a);
return 0;
}
you have to use "%p" to print address of a variable. Thank you

Why is it better to use cast when you assign an integer to a pointer?

Let's assume I have this code:
char *pointer;
unsigned int a;
pointer = a;
For me this doesn't generate any problems but I will receive the following warning:
assignment makes pointer from integer without a cast
Why is it better to use cast?
I'm using a 32 bit machine.
Edit:
By "this doesn't generate any problems", I was saying that it compiles and pointer stores the value of variable a.
Edit:
And variable a will actually store an address.
It's almost always better not to try to assign an integer value to a pointer at all. In the rare cases where such an assignment makes sense, a cast is not just better, it's required.
Pointers and integers are distinct types. In some cases it can make sense to mix them; in such cases you need a cast, because there is no implicit conversion between integers and pointers (other than the special case of 0, treated as a null pointer constant).
char *pointer;
int a; /* or unsigned int a, it's the same either way */
pointer = a;
This assignment is illegal (more precisely, a constraint violation). A conforming C compiler must at least warn about it. Many compilers, after printing a warning, will generate code that performs an implicit conversion, but that's not required by the language, and you shouldn't depend on it. My personal opinion is that compilers that do this aren't doing you any favors.
pointer = (char*)a;
This is legal; the cast tells the compiler to generate an conversion from int to char*. But the result of that conversion is implementation-defined, and very likely doesn't yield a meaningful result -- even if char* and int happen to be the same size.
(In the code in your question, a hasn't been initialized. I presume that's not the case in the real code you haven't shown us.)
What are you actually trying to accomplish?
Because in C:
pointer = a; // not valid in C: a is an int object
// pointer an object of pointer type
the statement is not valid, you need an explicit conversion (a cast) to convert a value to a pointer type.
pointer = (char *) a; // valid assignmnent
Some compilers are nice with you and will implicitly convert the int value to a pointer type (and add a warning!) but they are not required to do so and a compiler can refuse to compile your program.
% cat int-cast.c
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf("sizeof char *: %zu\n", sizeof (char *));
printf("sizeof int: %zu\n", sizeof (int));
}
Then if compiled 32 or 64 bit the size of the types differ
% cc -m32 int-cast.c && ./a.out
sizeof char *: 4
sizeof int: 4
% cc -m64 int-cast.c && ./a.out
sizeof char *: 8
sizeof int: 4
And as Keith Thompson explicitly points out, even if they were guaranteed to be the same size, a cast would still be required, and the result would be at best implementation-defined.
In C a pointer is not only an address in memory, it is also a type:
pointer = memory size + type
The best way to understand this is to think about pointer arithmetic that prevent to do some arithmetics operations. For example, you can do:
int i;
int * ptr, ptr2;
ptr = &i; // Assign the address of an int to an int pointer
ptr2 = ptr + 2; // Shift the pointer of two int size further
i = ptr - ptr2; // Compute the number of slots between ptr and ptr2
But, you cannot do:
int i;
char c;
int * ptr;
char * ptr2;
ptr = &c; // The types are not matching, the compiler will complain
ptr = 2 * ptr; // This is not allowed by pointer arithmetic
ptr = ptr + ptr; // This is not allowed by pointer arithmetic
And so on...
But, what you have always to remember is that a pointer is not only a memory address. It is the combination of a memory address and a type.

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