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]);
Related
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]);
}
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;
}
I need to tag the address of an int pointer with a 1 in the rightmost bit and store that address somewhere. For example the address at 0x10 would become 0x11.
I have tried doing
int* addr = some_pointer;
int* tagged = (int*) (addr | 0x00000001);
but I get error: invalid operands to binary expression ('int *' and 'int'). How could I go about doing this?
How can I set the rightmost bit of a pointer to 1?
C99/C11 provides optional integer types (u)intptr_t to covert a void* pointer to an integer and then back to a pointer. This round trip results in a pointer that is equal in value to the original. It may or may not have the same bit pattern as the original pointer.
#include <stdint.h>
int i = 42;
int* addr = &i;
void *vptr = addr;
uintptr_t uptr = (uintptr_t) vptr;
// Set least significant bit.
uintptr_t uptr1 = uptr | 1;
// or one-liner
uintptr_t uptr1 = ((uintptr_t) (void *) &i) | 1;
There is no print specifier for (u)intptr_t, so code can cast to the widest type for display purposes
printf("%p --> %ju --> %ju\n", vptr, (uintmax_t) uptr, (uintmax_t) uptr1);
// or use macros from <inttypes.h>
printf("%p --> %" PRIuPTR " --> %" PRIuPTR "\n", vptr, uptr, uptr1);
As long as OP only needs to store the value as an integer, no problem. (u)intptr_t values that originate from a valid pointer can convert back to a matching pointer type with no problem.
So far so good, yet OP may want to use the manipulated value.
Now the trick is that uptr1 may or may not covert to a valid void * pointer. Even if it does convert to a valid void * pointer, the conversion to an int * may or may not work. These two steps are beyond the C spec - undefined behavior.
// UB
void *vptr1 = (void *) uptr1;
printf("%p\n", vptr1);
int *iptr1 = vptr1;
If code makes it this far, attempting to de-reference this new pointer, it is also UB.
printf("%d\n", *iptr1); // UB, good luck
As stated in comments, you need to convert the pointer to integral type explicitly:
int* addr = some_pointer;
int* tagged = (int*) ((uintptr_t)addr | 0x00000001);
Or shorter:
int* tagged = (int*) ((uintptr_t)some_pointer | 0x1);
You may need to include <stdint.h> in order to use macro define uintptr_t.
If you want to know why...
First, bit or operator | only allows Integral Types as operands.
A bit about the type categories of C in C89 draft. (I didn't check C99, C11)
Integral Type = char, signed and unsigned integer types, enumerated types.
Arithmetic Type = Integral Type and Floating Type
Scalar Type = Arithmetic Type and Pointer Type
So pointer is not an Integral Type. However, this is not enough to explain the error.
If there is an implicit conversion rule that automatically converts a pointer type to an integral type, you will be ok. (FYI: implicit conversion is a set of type conversion rules that will be applied to source automatically)
However, no such rule exists. So, you saw the error.
But sometimes, we really need to do math operations on a pointer variable. This is why we need explicit conversion.
Simple way to do this that will likely annoy your compiler is to use address of operator int* ptr = &var;.
Below is my program:
#include <stdio.h>
int main(int argc, char *argv[]) {
int val = 5;
int* ptr = &val;
int* addr = (int*)((int)&ptr | 0x00000001);
printf("address val: %x, ptr: %x, &ptr: %x, addr: %x \n", &val, ptr, &ptr, addr);
return 0;
}
The output of which is:
address val: 5880dacc, ptr: 5880dacc, &ptr: 5880dac0, addr: 5880dac1
#include <stdio.h>
int main(void) {
int a[5] = {0, 1, 2, 3, 4}, *p;
p = a;
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
return 0;
}
When I executed this code, I got a negative value for p. I have studied that address cannot be negative. Then why I have got a negative value
%d is not the correct format specifier to handle a pointer (address). You should be using %p and cast the corresponding argument to void* for printing an address. Using wrong argument type for a particular format specifier invokes undefined behavior.
To quote C11 chapter §7.21.6.1
[...] If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
In this code, *p does not denote an address, anyway.
You cannot print an array by just using the %ds in a single format string. You need to have a loop. In your code,
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
the format string expects 5 ints as argument, while you supply only a pointer and an int. FWIW, supplying insufficient argument for supplied conversion specifiers invoke undefined behavior, too. Quoting the same standard,
[...] If there are insufficient arguments for the format, the behavior is
undefined. [...]
To elaborate, replace
printf("%d\n%d\n%d\n%d\n%d\n", p, *p);
by
for (i= 0; i < 5; i++, p++)
printf("%d %p\n", *p, (void *)p);
For pointers, use %p with printf():
int a[5] = {0, 1, 2, 3, 4}, *p;
p = a;
printf("%p\n%d", (void *)p, *p);
Also make sure your comiler warnings are at the highest level. You should get a warning for using %d with a pointer then:
warning <code>: 'printf' : '%d' in format string conflicts with argument 1 of type 'int *'
Mis-matched printf() specifiers and arguments
printf("%d\n%d\n%d\n%d\n%d\n", p, *p); expects 5 int. Code is supplying a int * and int. Result: undefined behavior.
Instead:
printf("Pointer %p\nValue: %d\n", (void *) p, *p);
I have a program below ...I have a turbo c compiler so int is 2 bytes..
#include<stdio.h>
main()
{
int a[3][2]={
{1,3},
{2,0},
{3,4}
};
printf("%d",(a+1)); //increments 2 bytes
printf("%d",(&a[0]+1)); // increments 4 bytes
printf("%d",(a[2]));
return 0;
}
What is the difference between a+1 and &a[0]+1 ?
They are equivalent expresssions.
a + 1 and &a[0] + 1 values are the same and they are both of type int (*)[2].
Note that you are not correctly printing the pointer values: use p conversion specifier and cast the argument to (void *) to print the value of a pointer:
printf("%p\n", (void *) (a + 1));
printf("%p\n", (void *) (&a[0] + 1));
printf("%p\n", (void *) (a[2]));
Your compiler appears to have a bug. If a names an array then in [most] expressions a and &a[0] should have the same type and value so the result of the +1 should be identical in both cases.
a+1 and &a[0]+1 should both be equivalent to &a[1].
To be strictly correct when testing this you should use %p as a format specifier for displaying pointer values.
a names the array int a[3][2], so it has the type int [3][2]. In the expression a + 1 it decays to a pointer to the first element, which is therefore of type int (*)[2].
In the expression &a[0], a again decays to a pointer of type int (*)[2], so a[0] has the type int [2]. The address-of operator is a special case in that it does not provoke pointer decay, so &a[0] has type int (*)[2] and has the same type and value as the decayed a.
At a guess, I'd speculate that your compiler is incorrectly decaying a[0] in &a[0], so that it's giving &a[0] the type int **. If data pointers on your platform are 4 bytes in size then that would explain the observed result.