Reputation: 69
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?
Upvotes: 1
Views: 835
Reputation: 2520
Briefly the pointers are a special types of variables for holding memory addresses and their bit wide or byte size that the compilers allocate may vary depending on the platform. If you get the size of a pointer using the sizeof
operator for an 8-bit target for example, you will get 2 bytes mostly, that is, a pointer can hold an address value up to 64kB. This is reasonably 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 (264, greater than 1.8 * 1019). With 8-bit bytes, these 64 bit addresses occupy 8 bytes.
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 an int
pointer as in the following example:
int* ptr = (int*) 0x7fffb997144f; // Compilers will allow this
The pointers are incremented depending on the byte size of the type to which a pointer points.
Some type sizes except char
types, may vary depending on the platform.
Now that we know about pointers and how they are incremented let's see it in an example. The following example is compiled with GCC and executed in 64-bit Linux system.
#include <stdio.h>
int main(void)
{
char c[3];
short int si[3];
int i[3];
long l[3];
long long ll[3];
float f[3];
double d[3];
char* cp = c;
short int* sip = si;
int* ip = i;
long* lp = l;
long long* llp = ll;
float* fp = f;
double* dp = d;
printf("char pointer size is %zu\n", sizeof(cp));
for (int i = 0; i < 3; i++) {
printf("%p\n", (void *)cp++);
}
printf("\nshort int pointer size is %zu\n", sizeof(sip));
for (int i = 0; i < 3; i++) {
printf("%p\n", (void *)sip++);
}
printf("\nint pointer size is %zu\n", sizeof(ip));
for (int i = 0; i < 3; i++) {
printf("%p\n", (void *)ip++);
}
printf("\nlong pointer size is %zu\n", sizeof(lp));
for (int i = 0; i < 3; i++) {
printf("%p\n", (void *)lp++);
}
printf("\nlong long pointer size is %zu\n", sizeof(llp));
for (int i = 0; i < 3; i++) {
printf("%p\n", (void *)llp++);
}
printf("\nfloat pointer size is %zu\n", sizeof(fp));
for (int i = 0; i < 3; i++) {
printf("%p\n", (void *)fp++);
}
printf("\ndouble pointer size is %zu\n", sizeof(dp));
for (int i = 0; i < 3; i++) {
printf("%p\n", (void *)dp++);
}
cp = NULL;
sip = NULL;
ip = NULL;
lp = NULL;
llp = NULL;
fp = NULL;
dp = NULL;
return 0;
}
The output of the example is as follows:
char pointer size is 8
0x7ffc1d893c79
0x7ffc1d893c7a
0x7ffc1d893c7b
short int pointer size is 8
0x7ffc1d893c72
0x7ffc1d893c74
0x7ffc1d893c76
int pointer size is 8
0x7ffc1d893c64
0x7ffc1d893c68
0x7ffc1d893c6c
long pointer size is 8
0x7ffc1d893c40
0x7ffc1d893c48
0x7ffc1d893c50
long long pointer size is 8
0x7ffc1d893c20
0x7ffc1d893c28
0x7ffc1d893c30
float pointer size is 8
0x7ffc1d893c14
0x7ffc1d893c18
0x7ffc1d893c1c
double pointer size is 8
0x7ffc1d893bf0
0x7ffc1d893bf8
0x7ffc1d893c00
As you can see in the output, all pointers have the same size even though they point different types. This size may vary depending on the platform.
However the values of the pointers are incremented or decremented depending on the type which they point to. Again, sizes of some types may vary depending on the platform.
Some updates has been made upon @chqrlie's reasonable comments
Upvotes: 1
Reputation: 108
That's because a character occupies 1 byte, while a pointer to character is a pointer, not a character or something else, that means it stored a memory address, so it occupies 8 bytes. Also all kinds of pointer is 8 bytes on your machine.
Upvotes: 0
Reputation: 311088
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.
Upvotes: 2
Reputation: 145277
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
.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
Upvotes: 1