Pointer of pointer arithmetic? - c

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.

Related

Why char pointer increments by one byte though its size is 8?

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

how to pass one pointer value to another pointer?like can I do int *a=*b;where b is defined already but the pointer a is not addressing to any integer

Actually I was reading about pointers and wanted to try something ,so I wrote a small code
int main(){
int x = 10;
int *ptr;
ptr = &x;
printf("%d is stored at address %d\n",x,ptr );
int *c=*ptr;
c=&ptr;
printf("location is %d\n",c);
printf("value of c= %d",*c);
}
the result I expected was value of c would be 10 but instead the value came as the location of x.
output: 10 is stored at address 997523644 location is 997523648 value of c= 997523644
does this problem arise because I didnt pass any location as first?or is it something else or my question is quite silly I know:D,Can anyone help me?
The first thing that is missing in the code that you have provided, is the declaration of ptr. You haven't declared the ptr variable yet, so first you need to do
int *ptr;
, which tells that you need a pointer variable to point to a int variable.
Since you declare another pointer int *c and ptr is already a pointer, you only need to assign int *c = ptr (or c=ptr in case you want to declare int *c seperately first), which will store the value of ptr (location of x) to c. So, doing int *c=*ptr is wrong. Now you can access the value of x by doing derefencing (*c or *ptr), which you already did.
Doing c=&ptr is also wrong, because c is of type int * and &ptr is of type int **. In case you are trying to store the address of ptr, you have to first declare a variable of type int **, for example int **d. Now d=&ptr is valid and d holds a value which is the address of ptr. Dereferencing d (*d) should give you the value that the address of ptr is holding, which is nothing but the address of x (same as the value of c). If you dereference d twice (**d), you should get the back the value of x (10).
int* c = ptr should be enough, you can read it as: c is pointer to integer, c = ptr since ptr is already a pointer this will make both c and ptr point to the same value.
What you are currently doing: c=&ptr; is making c point to the address of ptr, so if you want to access x value you will need to dereference twice, once to get the address of ptr, and once again to get the content of x.
Changed it to this:
#include <stdio.h>
int main(void) {
int x = 10;
int *ptr = &x;
printf("%d is stored at address %p\n",x,ptr );
int *c=ptr;
int d = &ptr;
printf("location is %p\n", c);
printf("value of c= %d", *c);
return 0;
}
As ptr is an address already, you can just do it:
int *c=ptr;
Output is:
10 is stored at address 0x7ffd6127dd54
location is 0x7ffd6127dd54
value of c= 10
To print variable address, you can check this answer:
Stackoverflow Answer
You just need to remove the line
c=&ptr;
The above line means that you're setting C as the location of ptr, which is some random value. So C points to the location of ptr, and ptr points to the location of x. C is a double-pointer
Alternatively, if you keep that line in there, you can make it work by instead printing
printf("value of c= %d",**c);
either solution would get the output you expect

C - Assign value to pointer at position, is it possible?

In Visual Studio 2019, I tried to assign value to int pointer at specified position, but it doesn't work. Is this possible?
Moreover how I can printf a pointer's value, and not the address?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p =(int*)calloc(10,1);
p[0]=1;
p[1]=0;
p[2]=1;
printf("%d\n",p);
}
Thank
calloc(10,1) allocates 10 single byte items not 10 integers. So (except 8 bits uCs where int is 2 bytes) your allocated memory area is far too short. if you want to allocate space for 10 integers you need to int *p = calloc(10, sizeof(*p));
printf("%d", p) invokes an UB as p is the reference (address) stored in the pointer p. You need to dereference the pointer to get the integer referenced (pointed) by the p pointer printf("%d\n, *p);
To print the reference stored in the pointer you need to use the correct format: printf("%p\n", (void *)p);.
It works.
To print the value you need to derreference with * or index with [].
printf("%d\n",*p); //p[0]
printf("%d\n", p[0]); //p[0]
printf("%d\n",*(p + 1)); //p[1]
printf("%d\n", p[1]); //p[1]

Why does second printf print 0

#include<stdio.h>
int main()
{
char arr[] = "somestring";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
printf("ptr2 - ptr1 = %ld\n", ptr2 - ptr1);
printf("(int*)ptr2 - (int*) ptr1 = %ld", (int*)ptr2 - (int*)ptr1);
return 0;
}
I understand
ptr2 - ptr1
gives 3 but cannot figure out why second printf prints 0.
It's because when you substract two pointers, you get the distance between the pointer in number of elements, not in bytes.
(char*)ptr2-(char*)ptr1 // distance is 3*sizeof(char), ie 3
(int*)ptr2-(int*)ptr1 // distance is 0.75*sizeof(int), rounded to 0
EDIT: I was wrong by saying that the cast forces the pointer to be aligned
If you want to check the distance between addresses don't use (int *) or (void *), ptrdiff_t is a type able to represent the result of any valid pointer subtraction operation.
#include <stdio.h>
#include <stddef.h>
int main(void)
{
char arr[] = "somestring";
char *ptr1 = arr;
char *ptr2 = ptr1 + 3;
ptrdiff_t diff = ptr2 - ptr1;
printf ("ptr2 - ptr1 = %td\n", diff);
return 0;
}
EDIT: As pointed out by #chux, use "%td" character for ptrdiff_t.
Casting a char pointer with int* would make it aligned to the 4bytes (considering int is 4 bytes here). Though ptr1 and ptr2 are 3 bytes away, casting them to int*, results in the same address -- hence the result.
This is because sizeof(int) == 4
Each char takes 1 byte. Your array of chars looks like this in memory:
[s][o][m][e][s][t][r][i][n][g][0]
When you have an array of ints, each int occupies four bytes. storing '1' and '2' conceptually looks more like this:
[0][0][0][1][0][0][0][2]
Ints must therefore be aligned to 4-byte boundaries. Your compiler is aliasing the address to the lowest integer boundary. You'll note that if you use 4 instead of 3 this works as you expected.
The reason you have to perform a subtraction to get it to do it (just passing the casted pointers to printf doesn't do it) is because printf is not strictly typed, i.e. the %ld format does not contain the information that the parameter is an int pointer.

What is the difference in C between &i and i if i is an array of integers? [duplicate]

This question already has answers here:
How come an array's address is equal to its value in C?
(6 answers)
Closed 9 years ago.
I tried a code to see what is the difference between &i and i if i is an array. My assumption was that i represents the starting address of the array, and I had no idea what will happen if I print &i as well.
The result was surprising (to me), as both i and &i was the starting address of the array.
#include<stdio.h>
int main()
{
char str[25] = "IndiaBIX";
int i[] = {1,2,3,4};
printf("%i\n", &i);
printf("%i\n", i);
return 0;
}
The result will be:
2686692
2686692
This is the same address.
But if I use a pointer to int:
#include<stdio.h>
#include <stdlib.h>
int main()
{
int *j = (int *) malloc(sizeof(int));
*j = 12;
printf("%i %i %i\n", *j,j,&j);
return 0;
}
The result will be:
12
5582744
2686748
Here I assume the first is the value of the memory area pointed to by j,the second is the address of the memory area pointed to by j, the third is the memory address of the pointer itself. If I print i and &i, why does &i not mean the memory address of the pointer i?
int i[] = {1,2,3,4};
The difference is their type, i has a type of integer array, &i has a type of a pointer of an integer array.
Yeah, both i and &i leads to print the same answer but they are not exactly same,
-> i represents the address of the first element in an array named i.
-> &i represents the address of the whole array(though values of both are same, their types are different)
For more info, please refer this [link]http://publications.gbdirect.co.uk/c_book/chapter5/arrays_and_address_of.html
int ar[10];
ip = ar; /* address of first element */
ip = &ar[0]; /* address of first element */
ar10i = &ar; /* address of whole array */

Resources