When compiling and linking C code, your compiler will store the various bits and pieces in different parts of the resulting executable file. These are known as 'sections', and depending on what is stored there, have different protection levels, usually enforced by the CPU virtual memory paging mechanism. For literal values (in this case "1DF"
), the compiler will store these in a section that is marked as read-only. Thus:
char *nbr = "1DF";
declares a pointer variable (nbr
, stored on the stack), that points to "1DF"
, which is stored in a read-only section.
For this reason, when you attempt to modify one of the characters of that string, the CPU will raise an error; the segmentation fault.
Solution
You can declare nbr
as a pointer to a fixed length array of char
(thus making the initial contents undefined and not stored in a read-only section) by changing the declaration to:
char nbr[4];
The array is declared with a length of 4 to accommodate the trailing zero byte to indicate the end of the string.
Bonus Chatter
This will 'work', but there are a few things you should consider:
As noted, a string in C needs to be terminated with a zero byte ('\0'
in character notation) to be considered valid. Depending on the compiler, optimisation level, state of the computer, phase of the moon, etc, the array pointed to by nbr
could contain a zero byte in the appropriate place, but you should set it to avoid undefined behaviour.
As the str
argument to ft_itoa
is a char *
, the length of the array pointed to by str
is unknown inside ft_itoa
. A common idiom in C is to add an argument which is the length of the array so it can be safely worked with, and to change the return type to an int
to allow indicating whether the operation succeeded or not (for example in the case where the string representation of nb
can't fit in the array pointed to by str
). This would make the declaration of ft_itoa
something like int ft_itoa(int nb, char *str, int str_len)
and the return could be 0
if failed, 1
if succeeded.
In Depth
Looking over the executable created by compiling your code we have the following illustrative sections (many other sections have been omitted from the output):
$ objdump --section-headers
a.out: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
...
12 .text 00000324 000102e0 000102e0 000002e0 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
...
14 .rodata 00000008 0001060c 0001060c 0000060c 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
...
21 .data 00000008 0002101c 0002101c 0000101c 2**2
CONTENTS, ALLOC, LOAD, DATA
...
.text
is used to store the executable code portion (note the READONLY
and CODE
flags)
.data
is used to store global variables (note the DATA
flag and absence of the READONLY
flag)
.rodata
is used to store literal data (note the READONLY
and DATA
flags)
We can confirm that the .rodata
section actually contains the literal string 1DF
with:
$ objdump --full-contents --section .rodata
a.out: file format elf32-littlearm
Contents of section .rodata:
1060c 01000200 31444600 ....1DF.