Hello i am new to C language and trying to understand pointers.
Doing some examples i stumbled with this function and im not completely sure what it is about.
void dump(void *p, int n)
{
unsigned char *p1 = p;
while (n--)
{
printf("%p - %02x\n", p1, *p1);
p1++;
}
}
I dont understand the p in unsigned char *p1 = p; there is no other use for it in the function. I also dont quite understand the p1 in printf("%p - %02x\n", p1, *p1);, is it the actual value of the *p1 pointer?
Can anyone explain this topics to me? I'll be very grateful.
In the example it shows me that when a i run with this main()
int main(void)
{
int i = 10000;
dump(&i, sizeof(i));
return 0;
}
the output is
0x7ffd7e787e74 - 10
0x7ffd7e787e75 - 27
0x7ffd7e787e76 - 00
0x7ffd7e787e77 - 00
unsigned char *p1 = p; there is no other use for it in the function.
But there is. void has no size and arithmetics on a void* wouldn't know how far a "step" when trying to step the pointer to the next element of the pointed out type, as p1++; means. Where should it point after adding 1?
char, that is the smallest addressable entity, on the other hand, has a well defined size (1), and p1++ means the same as stepping one char (byte) in memory, resulting in pointing at the next char (byte).
void is special. You can't instantiate/store void. void is what you use to define a procedure/function that has no return value, void func(...);. It's also what's used to define a function that doesn't accept any arguments, ... func(void);.
A void* can be used to point at any type of object, of any size, from a char, with size 1, to a megaobject, of size gigantic. void* is therefore often used to accept pointers to any type of object - but, actually stepping a pointer 1 step ahead means "step to the next object of the pointed out type in memory" which also means that the compiler needs to know the size of the object the pointer is pointing at. Converting the void* to a (unsigned) char* and using that pointer lets the function step (p1++) forward in memory, one byte at a time.
unsigned char *p1 = p; converts the value of p from void * to unsigned char * and stores it in p1. This conversion yields the same address but with information that it points to a different type.
printf("%p - %02x\n", p1, *p1); should properly be printf("%p - %02hhx\n", (void *) p1, *p1);. In this, %p formats the address passed to it (the value of p1) for display, so it shows a memory address in a human-readable way. Since the type of p1 is unsigned char *, *p1 is an unsigned char at the address p1 points to, and %02hhx converts its value to a hexadecimal numeral with at least 2 digits, using a leading 0 digit if necessary.
int a;
(&a+1) -&a: 1
(char*)(&a+1) -(char*)&a: 4
Could you please explain why we got a different result when we did (char *) casting?
I compiled the code and found that the addresses are the same before and after casting. But when we do arithmetic, we get different results. Why?
&a: 1283454684
&a+1: 1283454688
(char*)&a: 1283454684
(char*)(&a+1): 1283454688
When doing pointer arithmetic the C compiler uses the size of the data pointed by the pointer as the "unit of measure", given that the smallest size is a single byte.
So when you have a pointer type* p and you add n the compiler will do:
C:
p+n
ASM:
p + n * sizeof(<data type pointed by p>)
Note that this happens under the hood everytime you access an array.
struct bigStruct{
int a;
int b;
...
int z;
};
// Define array of 100 bigStructs
struct bigStruct allStructs[100];
allStructs[3] == *(&allStructs + 3)
allStructs[3] == *(&struct bigStruct)((char*)&allStructs + 3*sizeof(struct bigStruct))
What is the point of typecasting into char ? Why not typecast it in int instead ?
#include <stdio.h>
int main()
{
int arr[15];
arr[1]=5;
arr[0]=2;
int diff = (char *)&arr[1] - (char *)&arr[0];
int diff2 = &arr[1] - &arr[0];
printf("%d\n%d", diff, diff2);
return 0;
}
Pointer arithmetic is not for the weak of heart, but always this will be true:
(&arr[0]/* pointer to first element*/)
+
(1 /* "next" */)
==
(&arr[1]/* pointer to second element*/)
This is true for any type, it is part of the rules of pointer arithmetic.
So it cannot be any other than
(&arr[1]/* pointer to second element */)
-
(&arr[0]/* pointer to first element */)
==
1
which is of course exactly like
diff2 == 1
This is not changed if the result of & is cast to a pointer to the actual type of the array entries, in this case int and int*. With that +1 still means "next array entry".
On the other hand
(char *)&arr[0]
is bend to be a pointer to something different than the type of the entries of the array. It has been forced to be a pointer to a char. If you increase that by one, it has to be a pointer to the next char and
(char *)&arr[0] + N
==
(char *)&arr[1]
can only be true, if N is the number of chars between the addresses of two consecutive array entries.
So
N =
(char *)&arr[1] - (char *)&arr[0]
ensures it.
To understand this let us take a simple example:-
#include <stdio.h>
int main()
{
int arr[3]={1,2,3};
int *p=arr;
for(int i=0;i<3;i++){
printf("%d ",*p);
p++; // In this line p is an address.
//Here address is incremented by 1.
// But the logic is that 1 is an integer.
// If 1 might not be an integer then the result should not be like this.
// Same is in your case if you are storing difference of two addresses
// in an integer then it calculates the difference
// with respect to the type of address(int in your case).
}
return 0;
}
In c++ if integer is used with addresses for any operation then its calculations are totally based upon the type of address(int,void,float....).
I have a struct defined:
struct Query {
int *pages;
int currentpage;
};
struct Query *new = malloc(sizeof(struct Query));
new->pages = malloc(sizeof(int) * 4);
I then checked the size of new->pages to ensure that the size was 4 by doing:
int size = sizeof(new->pages)/sizeof(new->pages[0]);
However, size keeps returning 2 as opposed to 4.
Would anyone know what I might be doing wrong?
Thanks for your help.
Your expectation is wrong.
sizeof(new->pages) in
int size = sizeof(new->pages)/sizeof(new->pages[0]);
doesn't return the total number of int elements. Just the size of the int pointer (int*). Since sizeof(int*) is 8 and sizeof(int) is 4 on your platform, it returns 2.
By the way, you should use size_t for size as sizeof operator returns a size_t and %zu is the format specifier (in printf()) to print size_t.
You are seeing this because the sizeof operator yields the size of the type of its operand in bytes, and the type of new->pages is a pointer to integer, as defined by the struct, so it evaluates to the size of the pointer, rather than the array.
Note the difference by the example:
int arr[4] = {0,1,2,3};
int *p = arr;
printf("%zu\n", sizeof(arr)); // prints 16
printf("%zu\n", sizeof(p)); // prints 4
The convention of getting number of elements of an array using sizeof(arr)/sizeof(arr[0]) works ONLY on arrays, it does not work on pointers, you have to keep track the length on your own.
Pointer are not arrays.Despite the fact that the pointer can point to an array,applying the sizeof() operator on a pointer returns the size of pointer,not the size of the array that it points to.
So,in order to keep track of the size,i recommend that you use a variable of type size_t to store the value (size).
Oh yeah,and don't name any of your variables new in case you want to use a c++ compiler!
struct Query {
int *pages;
int currentpage;
};
size_t size = 4;
struct Query *p = malloc(sizeof(struct Query));
p->pages = malloc(sizeof(int) * size);
I was reading through some lecture notes that in order for a pointer to reference a 2D array, it has to be given the address of the first element.
int a[10][10];
int *p = &a[0][0];
I've never tried this, so I was curious why isn't it enough to assign the array itself to the pointer, just as we do in a 1D case.
int a[10][10];
int *p = a;
The array is kept in an uninterrupted 'line' of memory anyway, and 2D arrays only have a different type, but the same structure as 1D arrays.
By doing this
int *p = &a[0][0];
I don't see how we give the pointer any more information than by doing this
int *p = a;
Or maybe all arrays regardless of their number of dimensions have the same type, the only difference being that multidimensional arrays store their extra dimensions before their first element and we need to jump over those memory spaces which remember sizes of an array's dimensions?
First, some background:
Except when it is the operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
Given the declaration
int a[10][10];
the expression a has type "10-element array of 10-element array of int". Unless this expression is the operand of the sizeof or unary & operators, it will be converted to an expression of type "pointer to 10-element array of int", or int (*)[10].
Given that declaration, all of the following are true:
Expression Type Decays to
---------- ---- ---------
a int [10][10] int (*)[10]
&a int (*)[10][10]
*a int [10] int *
a[i] int [10] int *
&a[i] int (*)[10]
*a[i] int
a[i][j] int
&a[i][j] int *
Also,
sizeof a == sizeof (int) * 10 * 10
sizeof &a == sizeof (int (*)[10][10])
sizeof *a == sizeof (int) * 10
sizeof a[i] == sizeof (int) * 10
sizeof &a[i] == sizeof (int (*)[10] )
sizeof *a[i] == sizeif (int)
sizeof a[i][j] == sizeof (int)
sizeof &a[i][j] == sizeof (int *)
Note that the different pointer types int (*)[10][10], int (*)[10], and int * don't have to be the same size or have the same representation, although on the platforms I'm familiar with they do.
The address of the first element of the array is the same as the address of the array itself; thus, all of a, &a, a[0], &a[0], and &a[0][0] will yield the same value, but the types will be different (as shown in the table above).
So, assume we add the following declarations:
int *p0 = &a[0][0]; // equivalent to int *p0 = a[0];
int (*p1)[10] = &a[0]; // equivalent to int (*p1)[10] = a;
int (*p2)[10][10] = &a;
All of p0, p1, and p2 initially have the same value, which is the address of the first element in a; however, because of the different pointer types, the results operations involving pointer arithmetic will be different. The expression p0 + 1 will yield the address of the next int object (&a[0][1]). The expression p1 + 1 will yield the address of the next 10-element array of int (&a[1][0]). And finally, the expression p2 + 1 will yield the address of the next 10-element array of 10-element array of int (effectively, &a[11][0]).
Note the types of p1 and p2; neither is a simple int *, because the expressions being used to initialize them are not that type (refer to the first table).
Note the pattern; for an array type, the simpler the expression, the more complicated the corresponding type will be. The expression a does not refer to a single int object; it refers to a 10x10 array of int objects, so when it appears in an expression, it is treated as a pointer to an array of integers, not a pointer to a single integer.
The compiler knows that "a" is a pointer to ten integers. If you don't declare the dimensions, then the compiler sees the new pointer as a pointer to an unknown number of integers. This will work in your case, but it will generate a compiler warning because the compiler sees them as incompatible pointers. The syntax for what you are trying to do (without generating a compiler warning) is:
int a[10][10];
int *p1 = &a[0][0];
int (*p2)[10] = a;
printf("p1: %p p2: %p\n", p1, p2);
One reason this is important is pointer arithmetic:
p1++; //move forward sizeof(int) bytes
p2++; //move forward sizeof(int) * 10 bytes
You understanding is close, the difference is the type information. Pointer does has its type. For example int* p, the pointer type is int*, as int a[10][10], the corresponding pointer type is int *[10][10].
In your example, p and a do point to the same address, but they're different type, which matters when perform arithmetic operation on them.
Here's an example from this URL
Suppose now that we define three pointers :
char *mychar;
short *myshort;
long *mylong;
and that we know that they point to the memory locations 1000, 2000, and 3000, respectively.
Therefore, if we write:
++mychar;
++myshort;
++mylong;
mychar, as one would expect, would contain the value 1001. But not so obviously, myshort would contain the value 2002, and mylong would contain 3004, even though they have each been incremented only once. The reason is that, when adding one to a pointer, the pointer is made to point to the following element of the same type, and, therefore, the size in bytes of the type it points to is added to the pointer.
You are right, you can assign the array itself to the pointer:
int a[10][10] = {[0][0]=6,[0][1]=1,[1][0]=10,[1][1]=11};
int b[10][10][10] = {[0][0][0]=8,[0][0][1]=1,[0][1][0]=10,[1][0][0]=100};
int *p, *q, *r, *s;
p = &a[0][0];
q = a; // what you are saying
r = &b[0][0][0];
s = b; // what you are saying
printf("p= %p,*p= %d\n",p,*p);
printf("q= %p,*q= %d\n",q,*q);
printf("r= %p,*r= %d\n",r,*r);
printf("s= %p,*s= %d\n",s,*s);
And the output is:
p= 0xbfdd2eb0,*p= 6
q= 0xbfdd2eb0,*q= 6
r= 0xbfdd3040,*r= 8
s= 0xbfdd3040,*s= 8
They point to the same address, regardless of the dimension of the matrix. So, what you are saying is right.
Well in 2D array, the outcome of *a and a is the same, they all point to the first address of this 2D array!
But if you want to define a pointer to point to this array, you could use int (*ptr)[10] for example.
You are right, 1D and 2D share the same structure, but 2D has some additional manipulation on pointers like above.
So all in all, in 2D array, a, *a and &a[0][0] prints the same address, but their usages may vary.
Like this:
#include<stdio.h>
int main() {
int a[10][10];
int *pa1 = &a[0][0];
int *pa2 = *a;
printf("pa1 is %p\n", pa1);
printf("pa2 is %p\n", pa2);
printf("Address of a is %p\n", a);
// pointer to array
int (*pa3)[10];
pa3 = a;
printf("pa3 is %p\n", pa3);
return 0;
}
They print the same address.