What the memory difference between char *array and char array[]?

Viewed 302

When I execute the next code

int main()
{
    char tmp[] = "hello";
    printf("%lp, %lp\n", tmp, &tmp);
    return 0;
}

I had got the same addresses. But for the next code, they will be different

int main()
{
    char *tmp = "hello";
    printf("%lp, %lp\n", tmp, &tmp);
    return 0;
}

Could you explain the memory differences between those examples?

3 Answers

char tmp[] = "hello"; is an array of 6 characters initialized to "hello\0" (it has automatic storage duration and resides within the program stack).

char *tmp = "hello"; is a pointer to char initialized with the address for the string literal "hello\0" that resides in readonly memory (generally within the .rodata section of the executable, readonly on all but a few implementations).

When you have char tmp[] = "hello";, as stated above, on access the array is converted to a pointer to the first element of tmp. It has type char *. When you take the address of tmp (e.g. &tmp) it will resolve to the same address, but has a completely different type. It will be a pointer-to-array-of char[6]. The formal type is char (*)[6]. And since type controls pointer arithmetic, iterating with the different types will produce different offsets when you advance the pointer. Advancing tmp will advance to the next char. Advancing with the address of tmp will advance to the beginning of the next 6-character array.

When you have char *tmp = "hello"; you have a pointer to char. When you take the address, the result is pointer-to-pointer-to char. The formal type is char ** reflecting the two levels of indirection. Advancing tmp advances to the next char. Advancing with the address of tmp advances to the next pointer.

char a[] = "hello";

and

char *a = "hello";

Get stored in different places.

char a[] = "hello"

In this case, a becomes an array(stored in the stack) of 6 characters initialized to "hello\0". It is the same as:

char a[6];
a[0] = 'h';
a[1] = 'e';
a[2] = 'l';
a[3] = 'l';
a[4] = 'o';
a[5] = '\0';

char *a = "hello"

Inspect the assembly(this is not all the assembly, only the important part):

    .file   "so.c"
    .text
    .section    .rodata
.LC0:
    .string "hello" ////Look at this part
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movq    $.LC0, -8(%rbp)
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

See

.section    .rodata
.LC0:
    .string "hello"

This is where the string is stored. char a[] is stored in the stack while char *a is stored wherever the compiler likes. Generally in rodata.

With

char tmp[] = "hello";

you are setting aside an array of char large enough to store the string "hello" and copying the contents of the string to that array, such that you get this in memory:

     +–––+
tmp: |'h'| tmp[0]
     +–––+
     |'e'| tmp[1]
     +–––+
     |'l'| tmp[2]
     +–––+
     |'l'| tmp[3]
     +–––+
     |'o'| tmp[4]
     +–––+
     | 0 | tmp[5]
     +–––+

There is no tmp object separate from the array elements themselves, so the address of the array (tmp) is the same as the address of its first element (tmp[0]).

With

char *tmp = "hello";

you are creating a pointer to char and initializing it with the address of the first character in the string literal "hello", such that you get this in memory:

     +–––+       +–––+
tmp: |   | ––––> |'h'| tmp[0]
     +–––+       +–––+
                 |'e'| tmp[1]
                 +–––+
                 |'l'| tmp[2]
                 +–––+
                 |'l'| tmp[3]
                 +–––+
                 |'o'| tmp[4]
                 +–––+
                 | 0 | tmp[5]
                 +–––+

In this case tmp is a separate object from the array elements, so the address of tmp is different from the address of tmp[0].

Related