Dheeraj
Dheeraj

Reputation: 69

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?

Upvotes: 1

Views: 835

Answers (4)

Kozmotronik
Kozmotronik

Reputation: 2520

What are pointers?

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

How the pointers are incremented

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

Summary

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

08822407d
08822407d

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

Vlad from Moscow
Vlad from Moscow

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

chqrlie
chqrlie

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.
  • 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

Upvotes: 1

Related Questions