One of the most common uses of the character data type is the creation of an array of characters also known as strings. Strings can be declared and initialized in two ways.
Method 1
char *a = "hello";
This declares a pointer to a string literal. The contents at the address pointed to by the pointer cannot be modified as it exists in the read only part of the memory of the process.
In the first method a is a pointer containing the address to the read only part of the memory containing ‘hello’. Here ‘a’ is a pointer to the string literal “hello”.
I have compiled the code for the ARMv7 architecture, a Raspberry Pi 3B to be specific. Here’s the disassembly of the program
000083e4 <main>:
83e4: e52db004 push {fp} ; (str fp, [sp, #-4]!)
83e8: e28db000 add fp, sp, #0
83ec: e24dd00c sub sp, sp, #12
83f0: e59f3010 ldr r3, [pc, #16] ; 8408 <main+0x24>
83f4: e50b3008 str r3, [fp, #-8]
83f8: e1a00003 mov r0, r3
83fc: e24bd000 sub sp, fp, #0
8400: e49db004 pop {fp} ; (ldr fp, [sp], #4)
8404: e12fff1e bx lr
8408: 0000847c andeq r8, r0, ip, ror r4
00008478 <_IO_stdin_used>:
8478: 00020001 andeq r0, r2, r1
847c: 6c6c6568 cfstr64vs mvdx6, [ip], #-416 ; 0xfffffe60
8480: 0000006f andeq r0, r0, pc, rrx
As you can see in line 5, register R3 is loaded with the value stored at address 0x8408 which is the address to the string in the read only part of the program. In line 6 this address to the string is stored on the stack, in other words the pointer ‘a’ is created.
Method 2
In the second method an array is created on the stack to where the characters of the string are copied.
char b[6] = "hello";
This declares an array of characters on the stack. The contents of array can be modified as it is on the stack which is permitted for read and write.
000083e4 <main>:
83e4: e52db004 push {fp} ; (str fp, [sp, #-4]!)
83e8: e28db000 add fp, sp, #0
83ec: e24dd00c sub sp, sp, #12
83f0: e59f2020 ldr r2, [pc, #32] ; 8418 <main+0x34>
83f4: e24b300c sub r3, fp, #12
83f8: e8920003 ldm r2, {r0, r1}
83fc: e5830000 str r0, [r3]
8400: e2833004 add r3, r3, #4
8404: e1c310b0 strh r1, [r3]
8408: e1a00003 mov r0, r3
840c: e24bd000 sub sp, fp, #0
8410: e49db004 pop {fp} ; (ldr fp, [sp], #4)
8414: e12fff1e bx lr
8418: 0000848c andeq r8, r0, ip, lsl #9
00008488 <_IO_stdin_used>:
8488: 00020001 andeq r0, r2, r1
848c: 6c6c6568 cfstr64vs mvdx6, [ip], #-416 ; 0xfffffe60
8490: 0000006f andeq r0, r0, pc, rrx
In line 4 the stack size is increased. In line 5 register R2 is loaded with address to the string. R3 is loaded with address to top of stack r3 = fp - 12
.
R0 and R1 are loaded with the string values.In line 8, R0 contents are written to the stack. Similarly halfword of R1 is stored onto stack.
Array of strings
Array of strings can be declared in two methods.
Method 1
char a[2][6]={"hello","world"};
printf("%p %s",a[0],a[0]);
On executing this program you will see the following output.
0x7fff80afe6b0 hello
When you run the program a second time you may see a different output.
0x7fff48b07260 hello
This is because the array is being created on the stack. The hello
string is copied to the stack as depicted in method 2. So the address contained in a[0]
is of the stack memory which is created during runtime and hence random.
Method 2
char *a[2]={"hello","world"};
printf("%p %p %s",a,*a,*a);
Output
0x7fffe7f4bae0 0x400604 hello
When its a run a second time.
0x7fff8973fe60 0x400604 hello
So the program creates an array of pointers on the stack, where each pointer contains the address of hello
string in the read only data section of the program.
Be sure to leave your thoughts in the comment section below.