Can someone explain why this program behaves like this? - c

I have the following program in C:
void main() {
int x[3];
int* p = &x;
printf("%d %d \n", p, x);
}
those values for p and x seem to be the same, but i dont understand why, since p is the address of pointer x, shouldn't there be something like *p = x instead of p = x ?

Your code produce some warning at compilation time :
warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘int *’ [-Wformat=]
and your compiled code cause an undefined behaviour and the equal result is due to the Undefined behaviour.
Tips:
Your code is wrong conceptually, please read more on pointer, array e type in C language.

The big problem is that p and &x are different types.
The pointer given by &x is a pointer to the whole array x, not to a single element, and its type is int (*)[3], not int *.
If you want to get a pointer to the first element of x then use &x[0], or plain x (as that decays to &x[0]).
And even while the types of &x and &x[0] are different, they both point to the same location (as your (invalid) printouts indicates). This can be seen if you attempt to visualize the array x in memory:
+------+------+------+
| x[0] | x[1] | x[2] |
+------+------+------+
^
|
&x
|
&x[0]
As I already mentioned in a comment, to print pointers you need to use the %p format specifier. Mismatching formatting specifier and argument type leads to undefined behavior.
What's more, the %p format specifier is for void * pointers, so you need to cast the pointers (unless they are already void * of course):
printf("%p %p \n", (void *) p, (void *) x);

There are several issues in your program leading to undefined behaviour.
First, array x is not initialized, and accessing it later leads to UB.
Second, x when used as pointer is already the address of the first element of array x (equivalent to &x[0]); Hence &x would be a pointer to that pointer.
Third, %d requires an integral value, not a pointer to one; so you need to dereference p and x.
The following program should behave as you expect:
int main() {
int x[3] = { 1,2,3 };
int* p = x;
printf("%d %d \n", *p, x[0]);
}

Related

C Pointer Question 'int', but argument 2 has type 'int **'

I am currently doing pointers. I have been programming for a long time, but not in C/C++. With that being said, my pointer knowledge is abysmal.
Currently, I am following a guide on YouTube and he prints the code below.
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", p);
}
This prints successfully for him, and he sees a memory location. For me, I see the error
warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *'
From this, I expect I need to put an & in front of the p to make it print the value. But then I receive this error,
int main() {
int a = 5;
int *p;
p = &a;
printf("%d\n", &p);
}
'int', but argument 2 has type 'int **'
Where is the hole in my knowledge? Any key tips or strategies when working with this, I don't know why I find this so abstract.
Thanks,
I was expecting the value to print as expected, but instead am greeted with the error.
%d is the wrong format specifier for pointers. That may work on a more lenient or noncompliant implementation, but you should use %p to print pointer values.
Warnings are not errors. You're receiving a warning, which is not stopping your program from working, because the print specifier %d (ie printf("%d")) is for displaying integers, and you're giving it a non-integer argument of type int*.
The problem here is not with the argument, it's with the print specifier. Your attempt at a fix just changes the int* to an int**, which still does not match the format specifier %d. Use %p instead, which is the specifier for pointers, and will fix the warning, and print the address in hexadecimal notation.
You could also suppress the warning with a series of explicit casts from int* to int, but integer representations of memory addresses are generally much less used than hexadecimal representations in the first place.
Note that using wrong format specifier in printf() lead to undefined behaviour1).
The correct format specifier to print a pointer is %p format specifier.
Remember, format specifier %p expect that the argument shall be a pointer to void, so you should type cast pointer argument to void *. The correct statement to print pointer p would be:
printf("%p\n", (void *)p);
C11#7.21.6.1p9 [emphasis added]
9 If a conversion specification is invalid, the behavior is undefined.282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

Printing pointed value from passed pointer

I am confused as to why this code succesfully gives me back the right input.
#include <stdio.h>
#include <stdlib.h>
int bintest();
int main()
{
int* x = malloc(sizeof(int));
printf("\n\n*****\nEnter value of x\n*****\n");
scanf("\n%d", &x);
bintest(x);
}
int bintest(int* y)
{
printf("\ny: %d", y);
}
Why doesnt it work when I print **y, I assume pointer x is passed to bintest and stored in pointer y, which then should be called **y to print the value of the input?
You should start turning on compiler warnings and paying attention to them. Your short snippet yields 3! warnings.
$ gcc main.c -Wall -Wextra
main.c: In function ‘main’:
main.c:12:19: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int **’ [-Wformat=]
scanf("\n%d", &x);
~^ ~~
main.c: In function ‘bintest’:
main.c:18:23: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("\ny: %d", y);
~^ ~
%ls
main.c:19:5: warning: control reaches end of non-void function [-Wreturn-type]
}
^
You program has undefined behavior, and this can manifest itself by working as it should.
The correct code should be
scanf("\n%d", x);
...
printf("\ny: %d", *y);
And declare bintest as a void function if you don't want to return anything.
I am confused as to why this code succesfully gives me back the right input.
You're storing the read value in the pointer x which creates a memory leak since you throw away the malloc call. You could remove the malloc call and your program would behave the same. (Probably. It does have undefined behavior).
It's undefined behaviour.
It happens to work for following reason:
&x is the address of the x pointer. As the size of a pointer is usually at least the size of int, scanf("\n%d", &x); simply overwrites the pointer. Then you pass that pointer (whose value is now what the user typed in) to bintest
Your compiler should have given you at least two warnings such as:
'scanf' : format string '%d' requires an argument of type 'int *', but variadic argument 1 has type 'int **'
'printf' : format string '%d' requires an argument of type 'int', but variadic argument 1 has type 'int *'
These two warnings are rather errors and you should not ignore them.
You did NOT store the value of an integer in x IF that is what you wanted; you asked user for an input and overwrote the pointer x with user provided value. That pointer x now points to whatever the user gave.
Later you pass that x into that function and print that value: so you get what the user provided.
However your CANNOT de reference it. The x is pointing to a user provided value. What value is that? Do you know that it is some valid memory location.
Best read help documentation on scanf.
IF you really wanted to store an integer x with user provided value the code goes like
int x;
scanf(... &x).
Then you pass &x to that function.
Supporting what #Jabberwocky said,
test.c: In function ‘main’:
test.c:7:12: warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type ‘int **’ [-Wformat=]
7 | scanf("\n%d", &x);
| ~^ ~~
| | |
| | int **
| int *
test.c: In function ‘bintest’:
test.c:11:16: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
11 | printf("\ny: %d", y);
| ~^ ~
| | |
| int int *
| %ls
test.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
12 | }
| ^
This came up when I tried to compile the code with CLion IDE (gcc (GCC) 9.1.1 20190503 (Red Hat 9.1.1-1), C11) although even I don't understand it fully. I hope it helps and someone could explain it further.
If you want to scan a value to where x is pointing, then use x like this: scanf("\n%d", x). To print the value that you just placed, then pass in x like this: bintest(x);, but print *y like this: printf("%d", *y);
scanf("\n%d", &x); is the same as x = scan;
scanf("\n%d", x); is the same as *x = scan; which is what you want.
So in this example scanf("\n%d", &x); you give scanf &x, which is the address to x itself. Doing this means scanf will change the value of x, thus changing what x is pointing to.
The function scanf wants an address to where it puts its value. So to put it where x is pointing to, you should just pass in x.
The reason the values you have are the same is because you are simply passing in x like this: bintest(x); and printing y like this: printf("%d", y);. In this example, y is just a copy of x.
If you want to test out how these functions are working with pointers try using this code. I entered in 99 as an example.
#include <stdio.h>
#include <stdlib.h>
int bintest();
int main(){
int* x = malloc(sizeof(int));
printf("value of x: %d\n",x);
printf("address of x: %d\n",&x);
printf("value at %d: %d\n", x, *x);;
printf("\n\n*****\nEnter value of x\n*****\n");
scanf("\n%d", x);
printf("value of x: %d\n",x);
printf("address of x: %d\n",&x);
printf("value at %d: %d\n", x, *x);
bintest(x);
}
int bintest(int* y){
printf("\ny: %d", *y);
}
You should get an output similar to this:
value of x: 7018424
address of x: 6422316
value at 7018424: 7017768
*****
Enter value of x
*****
99
value of x: 7018424
address of x: 6422316
value at 7018424: 99
y: 99

Pointer to typedef of an array

I'm trying to do the following thing:
#include <stdio.h>
typedef unsigned char Set[128];
Set A; //Global variable
void main()
{
A[0] = 1;
A[1] = 2;
A[2] = 3;
printf("%x, %x, %x\n", A, &A, &A[0]);
printf("%u, %u, %u\n", A[0], A[1], A[2]);
Set *p;
p = A; //Same result with: p = &A;
printf("%x, %x, %x\n", p, &p, &p[0]);
printf("%u, %u, %u\n", p[0], p[1], p[2]);
}
The first and third prints are fine - I get to see the addresses of the two variables, and for 'p' the address it points on.
I want 'p' to point on 'A' so I'll be able to access to the values in the array of 'A' through 'p', but it doesn't work - the values at the fourth print are not as the second, it's not printing the values of the array.
how can I create a pointer to 'Set' variable type?
You're using many wrong / mismatched format specifiers for the supplied argument types. This causes undefined behavior.
Remember, for a pointer type, you must use %p format specifier, and in case the pointer is not a pointer to a char type, you must cast the argument to void *.
Regarding the above statement for the requirement to cast, refer chapter §6.2.5/P28,
A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type. [....]
and footnote 48,
The same representation and alignment requirements are meant to imply interchangeability as
arguments to functions, return values from functions, and members of unions.
That being said, always pay attention to the types!!
In your code,
A is of type unsigned char [128] (array),
and p is of type unsigned char (*) [128].
Thus, p = A; is not a valid statement, as the types are not compatible. You must take the address of A to make the statement valid, something like
p = &A; // now the types are compatible
Well that's because pointer type of p is different that type of a. Here when you try to use p[1] you are basically trying to access some memory which you don't have access to. (You have undefined behavior when you access p[1] etc). And also due to mismatched type you will also run into undefined behavior in printf itself.
Rather you can get what you want by (Now you will get desired array elements).
printf("%u, %u, %u\n", (*p)[0], (*p)[1], (*p)[2]);
Also to type ponters use %p format specifier. (Casting it to void*).
printf("%p, %p, %p\n", (void*)A, (void*)&A, (void*)&A[0]);
How to compile code?
Also try to compiler your code with all warnings enabled. gcc -Wall -Werror progname.c.
Compiler complained!
Also p=A compiler complained about it. Because you are assigning unsigned char* to unsigned char(*)[128].
error: assignment from incompatible pointer type [-Werror=incompatible-pointer-types]
p = A; //Same result with: p = &A;
^
And
error: format ‘%x’ expects argument of type ‘unsigned int’, but argument 4 has type ‘unsigned char (*)[128]’ [-Werror=format=]
printf("%x, %x, %x\n", p, &p, &p[0]);
^
How to make these warnings go away?
p=&A;
This will do the correct assignment. And use the correct format specifiers as mentioned in answer.
How did the unsigned char* appear?
Well array decayed into pointer in this case - and it decayed into pointer to the first element. The type of the first element is unsigned char - a pointer to it would be unsigned char*. That's how it came into ...
p is pointer to type unsigned char [128], that means it is of type unsigned char (*)[128] while the type of A, after decay, is unsigned char *. Both are of incompatible type. You need
p = &A;
and
printf("%p, %p, %p\n", (void *)A, (void *)&A, (void *)&A[0]);
printf("%u, %u, %u\n", A[0], A[1], A[2]);
Set *p;
p = &A; // Assign address of A which is of type unsigned char (*)[128]
printf("%p, %p, %p\n", (void *)p[0], (void *)p, (void *)&p[0]);
printf("%u, %u, %u\n", p[0][0], p[0][1], p[0][2]);

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

Data type warning when initializing pointers

I'm currently trying to wrap my head around pointers in C, coming from front-end developing this not an entirely easy endeavour. I'm following this tutorial, and everything is running smoothly until I try to compile the following example:
#include <stdio.h>
int main(int argc, char *argv[]) {
int **ramon;
int *paul;
int melissa = 5;
paul = &melissa;
ramon = &paul;
printf("ramon = %d\n", ramon); // <- warning: format '%d' expects type 'int'...
printf("&paul = %d\n", &paul); // <- warning: format '%d' expects type 'int'...
printf("*ramon = %d\n", *ramon); // <- warning: format '%d' expects type 'int'...
printf("&melissa = %d\n", &melissa); <- warning: format '%d' expects type 'int'...
printf("**ramon = %d\n", **ramon);p1); <- warning: format '%d' expects type 'int'...
return(0);
}
From the first printf line I get this error: "warning: format '%d' expects type 'int', but argument 2 has type 'int **'"
I reckon this has to do with the way I initialize my pointers, but standing at the bottom of a steep learning curve I don't know how to progress. What is wrong, how do I initialize pointers to avoid the warnings?
Your pointer initialization looks correct. The problem is that you are trying to print a variable of type int** (i.e. a "pointer to a pointer to an int") using the %d format specifier which is for int values.
Print int value
If you want to print the value of melissa (i.e. 5) which is essentially what ramon is indirectly pointing to, you need to de-reference the pointer value the correct number of times.
De-referencing pointers is done via the * operator, and it essentially means "the value at which this pointer is pointing to".
De-referencing it once (i.e. *ramon) will get the int* value which ramon is pointing to.
De-referencing it a second time will get the int value which the de-referenced int* value is pointing to.
You can chain together de-reference operators like so to get what you want:
printf("ramon = %d\n", **ramon);
Print pointer value
If you want to print a pointer (i.e. memory location) value, you can use the %p format specifier. This will print the memory address out in hex:
printf("ramon = %p\n", ramon); // Print the "pointer to the pointer to melissa"
printf("ramon = %p\n", *ramon); // Print the "pointer to melissa"
ramon isn't an int, it's a pointer to a pointer to an int. **ramon would be an int. You're trying to print a bunch of ints with %d, but you're mostly trying to print pointers which uses the format %p.
read man printf. It is not clear whether you want to print the value pointed to by ramon or the actual value of ramon which is an address of an pointer to an int. Same for other warnings as well.
The type of the expression ramon is an int **, and the %d specifier expects an int. *ramon will be of type int *, and **ramon will be the desired int.
If you want to print the pointer itself, use the %p specifier.
ramon and paul are pointers and the printf format specifier for printing values of pointers themselves (not what they're pointing to) is %p. Try
printf("ramon = %p\n", ramon);
The warning has nothing to do with how you are initializing your pointers, it has to do with the mismatch in types between printf's %d specifier and the types you are passing to it.
If you want to print a pointer, use %p.
You declared ramon of type "pointer to pointer to type int". i.e. it holds an address to a "pointer to type int". %d on the other hand is the format specifier for int which is why you are getting the errors. Instead try the following:
printf("&paul = %p\n", ramon); //print the address that ramon points to
printf("&melissa = %p\n", *ramon); //print the address that paul points to
printf("&melissa = %p\n", paul); //same as above
printf("melissa = %d\n", **ramon); //print the contents of melissa
printf("melissa = %d\n", *paul); //same as above
printf("melissa = %d\n", melissa); //same as above
Output
&paul = 0xbf8072f4
&melissa = 0xbf8072f0
&melissa = 0xbf8072f0
melissa = 5
melissa = 5
melissa = 5
I reckon this has to do with the way I initialize my pointers
Why would you reckon that when the error message says nothing about initialization? Read it again:
"warning: format '%d' expects type 'int', but argument 2 has type 'int **'"
You have %d in the format string for your printf() call, as a placeholder for the value that you want to print. %d is used as a placeholder for values that are int s. The value you want to print is ramon. That variable has the type int**. The type int and the type int** are not the same.
If you want to print a pointer, then you should write the format string so as to expect a pointer. We format pointers with %p.
but standing at the bottom of a steep learning curve I don't know how to progress.
The way to progress is to read the error and/or warning messages and attempt to understand them. The error messages are talking about types. You should not be trying to do anything with pointers if you haven't first got your head around the concept that values have a type (i.e., what kind of thing they are).

Resources