Consider this program:
#include <stdio.h>
int main()
{
double *dp;
double **dpp;
dpp=&dp;
dp++;
dpp++;
return 0;
}
Suppose dp has address 100 and dpp has address 1000.
What will the address of these pointers be after incrementing?
The simplest thing is to make your program compilable and give it strictly defined behaviour, then run it.
#include <stdio.h>
int main(void)
{
double d[2] = { 3.141593, 2.718128 };
double *dp = &d[0];
double *dpa[2] = { &d[0], &d[1] };
double **dpp = dpa;
printf("dp = %p\n", (void *)dp);
printf("dpp = %p\n", (void *)dpp);
dp++;
dpp++;
printf("dp = %p\n", (void *)dp);
printf("dpp = %p\n", (void *)dpp);
return 0;
}
Note how the code carefully ensures that the pointers always point to valid data. You could extend the printing to print *dpp (another pointer) and **dpp and *dp (both double values).
On my machine (Mac OS X 10.9.1, GCC 4.8.2, 64-bit compilation), the output is:
dp = 0x7fff56945510
dpp = 0x7fff56945520
dp = 0x7fff56945518
dpp = 0x7fff56945528
When compiled for 32-bit, the output is:
dp = 0xbfffc600
dpp = 0xbfffc5f0
dp = 0xbfffc608
dpp = 0xbfffc5f4
The jump of 8 in dp is a consequence of sizeof(double) == 8 (for both 32-bit and 64-bit compilations). The change in dpp of 4 for the 32-bit compilation and 8 for the 64-bit compilation is a consequence of sizeof(double *) == 4 for 32-bit and sizeof(double *) == 8 for 64-bit.
dp++ is undefined behavior, since dp was never initialized. There are no guarantees about what will happen.
What will probably happen, though relying on this would be a poor decision, is that the numerical value in memory of dp is incremented by sizeof(double), and the numerical value of dpp is incremented by sizeof(double *). sizeof(double) is probably 8, and sizeof(double *) is probably 4 or 8.
double *dp => is pointer to variable of type double (size of dp is 4 bytes only)
double **dp1 => is a pointer to pointer which is pointing to double (size of dp1 is 4 bytes)
Pointer's size is always 4 bytes (assuming 32-bit machine; on a 64-bit machine, it's 8 bytes)
i.e pointer size depends on how big the memory address is.
When you increment dp++, you increment pointer pointing to double whose size is 8 bytes so it increments by 8 bytes (100 => 108).
When you increment the pointer to pointer, its size is 4 bytes so it increments by 4 bytes only (1000 => 1004)
Pointer increments depend on the type of object it is pointing at.
In your code you haven't declared a variable of type double directly; you have initialized **dp1 which will will result in undefined behavior.
double a = 10.00;
dp = &a;
add the above two line to understand your code better (just one of the way).
Related
void main() {
char var = 10;
char *ptr = &var;
printf("Pointer address before increment:%p\n", ptr);
printf("sizeof(ptr):%d\n", sizeof(ptr));
ptr++;
printf("Pointer address after increment:%p\n", ptr);
printf("sizeof(ptr):%d\n", sizeof(ptr));
}
Output:
Pointer address before increment:0x7fffb997144f
sizeof(ptr):8
Pointer address after increment:0x7fffb9971450
sizeof(ptr):8
Why does the char pointer increment by one byte only? Its size is 8, right?
When ptr is declared, the compiler allocates 8 bytes to it. When we increment it by 1, it increments based on the datatype. Why? How does this works?
For starters to output values of the type size_t you need to use the conversion specifier zu instead of d
printf("sizeof(ptr):%zu\n",sizeof(ptr));
^^^
Incremented pointer points to the memory after the object it points to. That is the value of a pointer of the type T * is incremented by the value sizeof( T ).
Consider for example accessing array elements.
T a[N];
The expression a[i] evaluates like +( a + i ). So the value of the pointer is incremented by i * sizeof( T ).
This is called the pointer arithmetic,
As for the size of objects of the type char then according to the C Standard sizeof( char ) is always equal to 1.
Also consider the following demonstration program.
#include <stdio.h>
int main( void )
{
char s[] = "Hello";
for ( const char *p = s; *p != '\0'; ++p )
{
putchar( *p );
}
putchar( '\n' );
}
Its output is
Hello
If the pointer p was incremented by the value sizeof( char * ) then you could not output the array using the pointer.
For pointer arithmetics, what matters is not the sizeof the pointer, but the size of the type it points to:
T a[10]; T *p = a; defines a pointer p to an array of objects of type T.
p contains the memory address of the first element of a.
The next element's address is sizeof(T) bytes farther, so incrementing the pointer p by 1 increments the memory address by sizeof(*p).
Here is a modified version:
#include <stdio.h>
int main() {
char char_array[2] = "a";
char *char_ptr = char_array;
printf("sizeof(char_ptr): %zu\n", sizeof(char_ptr));
printf("char_ptr before increment: %p\n", (void *)char_ptr);
printf("sizeof(*char_ptr): %zu\n", sizeof(*char_ptr));
char_ptr++;
printf("char_ptr after increment: %p\n", (void *)char_ptr);
int int_array[2] = { 1, 2 };
int *int_ptr = int_array;
printf("\nsizeof(int_ptr): %zu\n", sizeof(int_ptr));
printf("int_ptr before increment: %p\n", (void *)int_ptr);
printf("sizeof(*int_ptr): %zu\n", sizeof(*int_ptr));
int_ptr++;
printf("int_ptr after increment: %p\n", (void *)int_ptr);
return 0;
}
Output (64 bits):
sizeof(char_ptr): 8
char_ptr before increment: 0x7fff52c1f7ce
sizeof(*char_ptr): 1
char_ptr after increment: 0x7fff52c1f7cf
sizeof(int_ptr): 8
int_ptr before increment: 0x7fff52c1f7c0
sizeof(*int_ptr): 4
int_ptr after increment: 0x7fff52c1f7c4
Output (32 bits):
sizeof(char_ptr): 4
char_ptr before increment: 0xbffc492e
sizeof(*char_ptr): 1
char_ptr after increment: 0xbffc492f
sizeof(int_ptr): 4
int_ptr before increment: 0xbffc4930
sizeof(*int_ptr): 4
int_ptr after increment: 0xbffc4934
That's because a charactor occupies 1 byte, while a pointer to charactor is a pointer, not a charactor or something else, that means it stored a memory adress, so it occupies 8 bytes. Also all kinds of pointer is 8 bytes on your machine.
What are pointers?
Briefly the pointers are a special types of variables for holding memory addresses and its bit wide or byte size that the compilers allocate may vary depending on the platform. If you size a pointer using the sizeof operator in an 8-bit architecture for example, in most devices you will get 2 bytes, that is, a pointer can hold an address value up to 64kB. This is logically big enough to hold address value for devices that only has up to 64kB of ROM and up to a few kBs of RAM.
Since the architecture in which you compile your code is a 64-bit architecture, the system registers are 64-bits wide and it's wide enough to hold very large address values (2 * 10^64). Since its big enough it will naturally size 64-bits / 8 bytes.
As said the pointers are special objects, so you cannot assign kinds of constants like
int* ptr = 0x7fffb997144f; // Compilers will not allow this
Compilers will not allow this because the pointers are not regular kind of variables. So in order to assign a constant address value you must cast it as pointer like in the following example:
int* ptr = (int*) 0x7fffb997144f; // Compilers will allow this
How the pointers are incremented
It depends on the byte size of the type to which a pointer points. That is;
1 for char types
2 for short int types
4 for long types
8 for long long types
Some type sizes like of int and float types may vary depending on the platform.
Now that we know about pointers and how it is incremented let's make an example for each type above. Let's assume that the start address for each example is 0x7fffb997144f.
For char types
char vars[5];
char* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971450
ptr++; // 0x7fffb9971451
For short int types
short int vars[5];
short int* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971451
ptr++; // 0x7fffb9971453
For long types
long vars[5];
long* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971454
ptr++; // 0x7fffb9971458
For long long types
long long vars[5];
long long* ptr = vars; // 0x7fffb997144f
ptr++; // 0x7fffb9971458
ptr++; // 0x7fffb997145f
So, I was messing around with pointers in C
int o = 10;
int x = 20;
int *pA = NULL;
pA = &o;
and after adding an integer to the
pointer
pA += x;
the address stored in the pointer changed from
000000000061FE18
to
000000000061FE68
After checking the value the address was pointing to using *pA the value was 0 and I could add an integer to this address using
*pA += x;
and *pA became equal to 20, but the value stored in variable o was still 10.
Could anyone explain what happened here?
pA += x; - The pointer pA itself is incremented by the value of x multiplied by the size of type pA is pointing to and is equal to the size of x, which is int.
So, assume sizeof(int) or sizeof(x) is 4 and x has the value of 20, you end up multiplying the pointer value of pA by 80 because 4 * 20 = 80, which is matching to your test results.
0x61FE68 - 0x61FE18 = 0x50 = 80d.
After adding an integer to the pointer
pA += x; .... (and) checking the value the address was pointing to using *pA the value was 0...
Since you incremented the pointer pA itself by 20 * sizeof(int) with pA += x;, pA points no longer to any valid object and beyond the bounds of the object it should point to.
To increment the pointer in this way invokes undefined behavior as well as dereferencing this pointer.
That it displayed 0 is just happen arbitrary to the situation. You can't rely on anything. The value can change already at the next execution.
... and I could add an integer to this address using *pA += x; and *pA became equal to 20.
The behavior is undefined as said above. pA does not point to any legally referenced object.
...but the value stored in variable o was still 30.
o isn't changed at all. With the first statement pA += x; you incremented the pointer itself, not the object o pA pointed to at the first place.
Could anyone explain what happened here?
You incremented the pointer pA by sizeof(int) * 20 with the first pA += x;. Everything else can't be really explained, because the behavior is just undefined.
Here you have a small program which should explain pointer arithmetic a bit.
#include <stdio.h>
#define PRINTDIFF(type, p1, p2) printf("sizeof(%s) = %zu p1=%p p2 = %p diff(bytes) = %zi \ndiff(objects) = %zi diff(bytes)/sizeof(%s) = %zi\n\n", \
#type, sizeof(type), \
(void *)(p1), \
(void*)(p2), \
((char *)(p2) - (char *)(p1)), \
(p2) - (p1),\
#type, \
((char *)(p2) - (char *)(p1)) / sizeof(type))
int main(void)
{
short s;
char c;
int i;
long long ll;
long double ld;
short *sp = &s;
char *cp = &c;
int *ip = &i;
long long *llp = ≪
long double *ldp = &ld;
PRINTDIFF(short, sp, sp + 10);
PRINTDIFF(char, cp, cp + 500);
PRINTDIFF(int, ip, ip + 5);
PRINTDIFF(long long, llp, llp + 5);
PRINTDIFF(long double, ldp, ldp + 5);
}
https://godbolt.org/z/4eP3rc
And the result:
sizeof(short) = 2 p1=0x7ffe0660eb76 p2 = 0x7ffe0660eb8a diff(bytes) = 20
diff(objects) = 10 diff(bytes)/sizeof(short) = 10
sizeof(char) = 1 p1=0x7ffe0660eb75 p2 = 0x7ffe0660ed69 diff(bytes) = 500
diff(objects) = 500 diff(bytes)/sizeof(char) = 500
sizeof(int) = 4 p1=0x7ffe0660eb70 p2 = 0x7ffe0660eb84 diff(bytes) = 20
diff(objects) = 5 diff(bytes)/sizeof(int) = 5
sizeof(long long) = 8 p1=0x7ffe0660eb68 p2 = 0x7ffe0660eb90 diff(bytes) = 40
diff(objects) = 5 diff(bytes)/sizeof(long long) = 5
sizeof(long double) = 16 p1=0x7ffe0660eb50 p2 = 0x7ffe0660eba0 diff(bytes) = 80
diff(objects) = 5 diff(bytes)/sizeof(long double) = 5
BTW when you learn you should experiment yourself writing the short programs which will help you understand the C language. There is no easy, effortless way of learning C
The new address pointed by a pointer, after a constant value is added to it, depends on the type it points to:
NewAddress = OldAddress + ConstantValue * sizeof ( Type )
So, in plain math, with pA += x, you have
new_address_pointed_by_pA = old_address_pointed_by_pA + x * sizeof( int )
And since x=20 and an integer in your machine is 4 bytes big, this becomes
new_address_pointed_by_pA = old_address_pointed_by_pA + 20*4 =
= old_address_pointed_by_pA + 80
That's exactly what you experience, as 0x61FE68 - 0x61FE58 = 0x50. Your addresses, in fact, are represented in hexadecimal format. So the new address is 0x50=80 beyond the old one, and that fits with the simple calculation I showed above.
What does that new address contain? Well, we don't know. It depends on the history of that specific memory location.
If it was never used, it's not surprising it contained 0. And it was also expected that after *pA = x it contained 20. And, again, it is not surprising at all that the location it was originally pointing remains unchanged.
But... with that assignment you could have raised a segmentation fault exception. An OS usually raises this signal when a memory location not assigned to your task is accessed.
So, pay attention when you play with pointers, making sure that any arithmetics performed on them leads to legal new values.
I understand how the arithmetic of pointers works, but I have doubts about the one of the pointer of pointer:
If I have this code:
int x;
int* ptr = &x;
int** ptrptr = &ptr;
On a standard Windows system, if I do:
printf("%d",ptr);
ptr++;
printf("%d",ptr);
ptr will have a "+4" value than before, obviously because integer needs 4 bytes.
Now, if I do:
printf("%d",ptrptr);
ptrptr++;
printf("%d",ptrptr);
ptrptr will have a "+16" value than before, why? I apologize if this question has already been posted but I couldn't find out, thank you.
Code:
#include<stdio.h>
int main(void){
int x;
int* ptr = &x;
int** ptrptr = &ptr;
printf("Pointer: %p\nPointer of pointer: %p\n",(void*)ptr,(void*)ptrptr);
ptr++;
ptrptr++;
printf("Pointer: %p\nPointer of pointer: %p\n",(void*)ptr,(void*)ptrptr);
return 0;
}
Output:
Pointer: 000000000062FE44
Pointer of pointer: 000000000062FE38
Pointer: 000000000062FE48
Pointer of pointer: 000000000062FE40
The difference between 0x...FE40 and 0x...FE38 is 8, not 16, and 8 is the correct number of bytes of an address on a 64bit machine.
To hold an int (on your system) you need a box of 4 bytes. So to skip to the next item in memory you add 4 to the address of your initial int.
To hold a pointer_to_int (which is an address on your 64bit system) you need a box of 8 bytes.
A hint: the very numbers you are subtracting are 8-byte-long addresses:
0x00.00.00.00.00.62.FE.40 - 0x00.00.00.00.00.62.FE.38 = 0x08. The dots are only a visual aid.
I wrote a pretty simple piece of C code:
int main(void) {
void *area = malloc(2 * sizeof(int));
unsigned int *int_one = (unsigned int *) area;
unsigned int *int_two = ((unsigned int *) area) + 3;
*int_two = 4293422034;
*int_one = 2;
printf("%u\n%u\n", *int_two, *int_one);
return 0;
}
sizeof(int) is 4 on my machine. Per my understanding, shouldn't the modification of memory at address int_one have an effect on the value stored at address int_two?
Modifying *int_one alters the first 4 bytes of mem. address area (perhaps not all 4, but enough to warrant the result I'm expecting?), and the integer at address int_two starts at the last byte of integer int_one.
So, shouldn't changing memory at int_one have an effect on memory at int_two?
Yet the printf call produces 4293422034 and 2 respectively.
I made sure to use unsigned variables to avoid confusion around 2s complement and negative values, and to use a small value for *int_one to warrant the change of its last byte (don't know if this is right?)
What am I not getting?
Operator '+', when applied to a pointer, increases the pointer n times the size of the object it points to. So increasing an int* by 3 does not add 3 bytes but 3*sizeof(int) bytes.
Pointer arithmetic is scaled by the size of the type the pointer points at. (sizeof(unsigned int) in your case). You'd need to cast to (char*) before adding 3 if you want to increase the address by 3 bytes, but converting that to an unsigned* pointer would incur undefined behavior by violating alignment requirements (6.3.2.3p7) and dereferencing the pointer would make the program even "more undefined" by violating strict aliasing rules (6.5p7).
To realy do this kind of type punning right, you'd need to use memcpy (or unions).
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
void *area = malloc(2 * sizeof(int));
if(!area) return EXIT_FAILURE;
unsigned int *int_one_p = area;
void *int_two_p = (((char*) area) + 3); /*saving this to an (unsigned*) would be UB*/
memcpy(int_two_p,&(unsigned){4293422034},sizeof(unsigned));
memcpy(int_one_p,&(unsigned){2},sizeof(unsigned));
unsigned one,two;
memcpy(&one,int_one_p, sizeof(one));
memcpy(&two,int_two_p, sizeof(two));
printf("%u\n%u\n", two, one);
return 0;
}
I have a piece of code written in C where some pointer arithmetic is performed. I would like to know how the output comes to be this?
#include <stdio.h>
int main()
{
char arr[] = "gookmforgookm";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
printf ("ptr2 - ptr1 = %d\n", ptr2 - ptr1);
printf ("(int*)ptr2 - (int*) ptr1 = %d", (int*)ptr2 - (int*)ptr1);
getchar();
return 0;
}
Output is below:
ptr2 - ptr1 = 3
(int*)ptr2 - (int*) ptr1 = 0
Strictly speaking, you're invoking undefined behaviour and any result that the program produces is OK according to the C standard.
However, you're probably on a machine where sizeof(int) == 4 (as opposed to say, 2). Since there are 4 bytes to an integer, two addresses which are 3 bytes apart are part of the same integer, so the difference between the addresses is 0 * sizeof(int). You might find a different answer if you chose ptr1 = arr + 1;, or you might not. But that's the beauty of undefined behaviour - it would be 'right' either way.
After the subtraction you need to divide the result in the size of the pointed type.
(int*)ptr2 - (int*)ptr1 == (0x1000003 - 0x1000000) / sizeof(int)
(int*)ptr2 - (int*)ptr1 == (0x1000003 - 0x1000000) / 4 == 0
ptr1 and ptr2 are both char * type, that means one byte one pointer.
char *ptr2 = ptr1 + 3;
so
ptr2 - ptr1 = 3
Next, you cast both pointer to type int *, int type need 4 byte, so both pointer aim at the same int, both pointer have the same value through the memory align, you get the 0 result.
When you subtract two pointers, as long as they point into the same array, the result is the number of elements separating them.
Pointer Subtraction and Comparison
The memory addresses of the elements of the same array are always sequential. i.e
if the memory adress of myarray[0] is:
0x4000000
then the memory address of myarray[2] will definitely be
0x4000002
So when you store the address of arr into ptr1 assume it to be x
, and then when you make the address of ptr2, three units higher than ptr1, it will be x+3. So when you subtract ptr1 from ptr2 the answer will be:
(x+3) - x = 3
Hence the answer.
In the second printf() statement, if you want it to display the same result as above (3), you have to convert the pointer to int and not int*.
char *myvar; // given contents somewhere
int addr = (int)myvar; // addr now = the char pointer
So In your case:
printf ("(int)ptr2 - (int) ptr1 = %d", (int)ptr2 - (int)ptr1);