1

Newbie trying to recode itoa here. I am not quite sure about how the itoa function works, but here's how I want mine to work for now : char *ft_itoa(int nb, char *str) I want each digit of nb to be converted into a char which is to be put in *str. Here's my code (I am not allowed to use any function but write that will only allow me to debug here.

char    *ft_itoa(int nb, char *str)
{
    int i;
    int y;
    int nbinit;
    int neg;

    i = 0;
    y = 0;
    nbinit = nb;
    neg = 0;
    if(nb < 0)
    {
        nb = -nb;
        neg = 1;
        str[i] = '-';
        i++;
    }
    while(nb / 10 > 0)
    {
        i++;
        nb = nb / 10;
    }
    if(neg == 1)
        nb = -nbinit;
    else
        nb = nbinit;
    while(nb / 10 > 0)
    {
        y = nb % 10;
        str[i] = y + '0';
        i--;
        nb = nb / 10;
    }
    str[i] = nb + '0';

    return (str);
}

The program will segfault when trying to execute this line : str[i] = y + '0';

If I had to take a wild guess, I would say it is because in my main

int     main(void)
{   
    char *nbr = "1DF";
    int nb = 479;
    ft_itoa(nb, nbr);
    return (0);
}

*nbr is not 'malloced'. I am not sure about how the allocation works when declaring char *nbr = "1DF";.

Thanks in advance for your help !

badakzz
  • 35
  • 6

1 Answers1

1

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.
msbit
  • 4,152
  • 2
  • 9
  • 22
  • No problems @badakzz. If you think it's answered your initial question, you can mark this as the accepted answer. – msbit Feb 24 '21 at 06:27