【问题标题】:Segfault when trying to recode itoa in C尝试在 C 中重新编码 itoa 时出现段错误
【发布时间】:2021-05-23 05:54:48
【问题描述】:

新手试图在这里重新编码itoa。 我不太确定 itoa 函数是如何工作的,但这是我现在希望我的工作方式: char *ft_itoa(int nb, char *str) 我希望将nb 的每个数字转换为要放入*str 的字符。 这是我的代码(我不能使用任何函数,但 write 只允许我在这里调试。

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);
}

程序在尝试执行此行时会出现段错误: str[i] = y + '0';

如果我不得不大胆猜测,我会说这是因为在我的主要

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

*nbr 未“分配”。我不确定声明 char *nbr = "1DF"; 时分配是如何工作的。

提前感谢您的帮助!

【问题讨论】:

    标签: segmentation-fault itoa


    【解决方案1】:

    在编译和链接 C 代码时,您的编译器会将各种位和片段存储在生成的可执行文件的不同部分中。这些被称为“部分”,根据存储在那里的内容,具有不同的保护级别,通常由 CPU 虚拟内存分页机制强制执行。对于文字值(在本例中为 "1DF"),编译器会将它们存储在标记为只读的部分中。因此:

    char *nbr = "1DF";
    

    声明一个指针变量(nbr,存储在堆栈中),指向"1DF",存储在只读部分中。

    因此,当您尝试修改该字符串的某个字符时,CPU 将引发错误;分段错误。

    解决方案

    您可以通过将声明更改为:将nbr 声明为指向char 的固定长度数组的指针(从而使初始内容未定义并且不存储在只读部分中):

    char nbr[4];
    

    数组被声明为长度为 4 以容纳尾随零字节以指示字符串的结尾。

    奖金聊天

    这将“有效”,但您应该考虑以下几点:

    • 如前所述,C 中的字符串需要以零字节(字符表示法中的'\0')终止才能被视为有效。根据编译器、优化级别、计算机状态、月相等,nbr 指向的数组可能在适当的位置包含零字节,但您应该设置它以避免未定义的行为。

    • 由于ft_itoastr 参数是char *str 指向的数组的长度在ft_itoa 内部是未知的。 C 中的一个常见习惯用法是添加一个作为数组长度的参数,以便可以安全地使用它,并将返回类型更改为 int 以允许指示操作是否成功(例如在nb 的字符串表示形式无法放入 str 指向的数组的情况。这将使ft_itoa 的声明类似于int ft_itoa(int nb, char *str, int str_len),如果失败则返回0,如果成功则返回1

    深入

    查看通过编译代码创建的可执行文件,我们有以下说明性部分(输出中省略了许多其他部分):

    $ 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 用于存储可执行代码部分(注意 READONLYCODE 标志)
    • .data 用于存储全局变量(注意DATA 标志和READONLY 标志的缺失)
    • .rodata 用于存储文字数据(注意 READONLYDATA 标志)

    我们可以确认.rodata 部分实际上包含文字字符串1DF

    $ objdump --full-contents --section .rodata
    
    a.out:     file format elf32-littlearm
    
    Contents of section .rodata:
     1060c 01000200 31444600                    ....1DF.
    

    【讨论】:

    • 没问题@badakzz。如果您认为它回答了您最初的问题,您可以将其标记为已接受的答案。
    猜你喜欢
    • 2016-03-14
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    相关资源
    最近更新 更多