顶级太阳 发表于 2022-11-11 21:38:59

s1e29动动手0.疑问和题目没有太大关系,只是不明白哪里用了溢出

s1e29动动手0,题目如下:
      你应该听说过 itoa 函数(函数文档 -> 传送门),它的作用是将一个整数转换成字符串形式存储。现在要求我们自己来实现一个类似功能的函数 myitoa(int num, char *str),该函数的第一个参数是待转换的整型变量,第二参数传入一个字符指针,用于存放转换后的字符串。
给出主程序段:
……
int main(void)
{
      char str;

      printf("%s\n", myitoa(520, str));
      printf("%s\n", myitoa(-1234, str));

      return 0;
}
要求的结果:

我的代码:
#include<stdio.h>

char *myitoa(int a,char *array)
{

        int i=0,j,flag=0,m; //结果位数i计算
        char ch_array; //中间数组。

       
        if(a<<0)//判断正负值。如果是负数,将符号‘-’存入数组array第一个位置
        {
                array='-';
                i++;
                a=-a;
               
        }
        m=0;
        if(a>=10)    //每次除10,提取余数存入中间数组ch_array
        {
                ch_array=a%10;
                m++;       
        }

        for(j=m;j<0;j--)//数组存储值反转存储到指定的数组里
        {
                array=ch_array;
                i++;
        }

}

int main(void)
{
        char str;
       
        printf("%s\n",myitoa(520,str));
        printf("%s\n",myitoa(-1234,str));

        return 0;
}

悲惨的运行结果:


仔细分析了代码的各个部分,实在搞不明白哪里出了问题,造成这个“段错误(核心已转存)”。上网查找段错误的原因,是指发生了越界,也就是访问了不应该访问的内存,这个内存要么不存在,要么不允许使用。还有一个可能文件损坏。
那么首先,我尝试编译了好多遍了,应该排除文件损坏的原因。整个代码没有指定内存位置,应该不会被这么多次调用到不允许访问的内存,那么就是越界了。整个代码过程,根据题目要求定义了一个10元素的数组,我又定义了一个10元素组成的中间数组char ch_array.外加使用了4个整形变量,都是用了几个数字,根据题目,数组最大用到5个元素,那么变量值最大用到4也就结束了,不可能超出范围呀。还求哪位有耐心帮忙找找这个“段错误”错在了哪里。谢谢。

顶级太阳 发表于 2022-11-11 22:27:08

jackz007 发表于 2022-11-11 22:05
下面是我修改的版本

谢谢Jack。上次就看出来您的for循环使用的炉火纯青,在下佩服。根据你的提示,我修改了判断正负的if语句(第10行),修改了取尾数语句(第18行),在第21行插入了a=a/10;语句。虽然不明白你的第13行,计算出10进制尾数后,存入的时候要与0相加,也按照您的方式进行了修改。试运行结果还是同样的结果,编译通过,运行时出现“段错误”提示,不能出现正确结果。

我想要的不只是一个正确的答案,想要的是解决我现在遇到的问题。十分感谢。

dolly_yos2 发表于 2022-11-12 08:36:22

先说编码问题,其实您的编译器本应该协助您解决这些问题的。看看我使用的编译器是怎么评价您的代码的:test.c:10:13: warning: converting the result of '<<' to a boolean; did you mean '(a << 0) != 0'? [-Wint-in-bool-context]
      if(a<<0)//判断正负值。如果是负数,将符号‘-’存入数组array第一个位置
            ^
test.c:6:19: warning: unused variable 'flag' [-Wunused-variable]
      int i=0,j,flag=0,m; //结果位数i计算
                  ^
test.c:30:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
3 warnings generated.
理解和解决了这些问题,就理解和解决了您目前出现的段错误。
当然,您的代码除此之外还有逻辑上的问题,还需要后续的修改才能得到正确的结果,您可以先尝试,遇到无法解决的问题欢迎继续提问。

顶级太阳 发表于 2022-11-13 19:28:04

dolly_yos2 发表于 2022-11-12 08:36
先说编码问题,其实您的编译器本应该协助您解决这些问题的。看看我使用的编译器是怎么评价您的代码的:
理 ...

谢谢您的答复,根据你的编译器提示,我找到了溢出的位置,也对逻辑进行了修正,已经完成了题目。好奇问一下,您用的是什么编译器,可以告诉我么?你这个编译器的提示太丰富了,我能够使用不?

dolly_yos2 发表于 2022-11-14 10:11:20

顶级太阳 发表于 2022-11-13 19:28
谢谢您的答复,根据你的编译器提示,我找到了溢出的位置,也对逻辑进行了修正,已经完成了题目。好奇问一 ...

得到之前回复里的输出的编译器和版本是clang version 14.0.6
当然, gcc 也可以得到类似的结果(这里我改了一下源代码文件名):test2.c: In function ‘myitoa’:
test2.c:10:13: warning: ‘<<’ in boolean context, did you mean ‘<’? [-Wint-in-bool-context]
   10 |         if(a<<0)//判断正负值。如果是负数,将符号‘-’存入数组array第一个位置
      |            ~^~~
test2.c:6:19: warning: unused variable ‘flag’ [-Wunused-variable]
    6 |         int i=0,j,flag=0,m; //结果位数i计算
      |                   ^~~~
test2.c:30:1: warning: control reaches end of non-void function [-Wreturn-type]
   30 | }
      | ^
版本是gcc (GCC) 12.2.0
您可以试着给您的编译命令加上额外的调试选项,我一般常用的是(在此处使用的也是) -Wall -Wextra -fsanitize=address ,即改为gcc -Wall -Wextra -fsanitize=address test.c
相关选项的含义可以在这里查找对应您使用的版本的文档: https://gcc.gnu.org/onlinedocs/
如最新版的选项总结在这里: https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Option-Summary.html

顶级太阳 发表于 2022-11-14 11:40:11

dolly_yos2 发表于 2022-11-14 10:11
得到之前回复里的输出的编译器和版本是
当然, gcc 也可以得到类似的结果(这里我改了一下源代码文件名 ...

十分感谢。刚刚自己开始学习,完全靠摸索,很多东西还都不懂。
页: [1]
查看完整版本: s1e29动动手0.疑问和题目没有太大关系,只是不明白哪里用了溢出