• C语言字符串倒序


    某天在某处看到一个C语言问题,要求将字符串倒序,说是倒序函数有bug,当执行交换两个数的时候会出现core dump,开始看到这个错误以为指针错误,但是别人调试过发现指针并没有问题,然后一下就没找到问题所在,于是回来就用gdb调试了一下,函数到关键部分如下:

    void reverse_str(char *str){
        char *p = NULL,*q = NULL,tmp = 0;
        
        p = str;
        q = str;
        while( *(++q) != '' );q--;
        while(p < q){
            tmp = *p;
            *p = *q;
            *q = tmp;
            p++;
            q--;
        }
    }

    拿到linux下写了个完整程序,如下

    #include <stdio.h>

    void
    reverse_str(char *str){ char *p = NULL,*q = NULL,tmp = 0; p = str; q = str; while( *(++q) != '' );q--; while(p < q){ tmp = *p; *p = *q; *q = tmp; p++; q--; } } int main(void){ char *str = "abcdefg"; printf("%s ",str); reverse_str(str); printf("%s ",str); return 0; }

    编译:gcc -o tst.elf tst.c -g,然后运行,跟上面提到的bug一样,出现Core Dump直接退出,接着调试:gdb ./tst.elf,打上断点b 5,然后一次单步,最后发现运行到*p = *q这句话时,程序就出现上述错误了,但是此时p,q指针并不是野指针,指向的内容也都是正确的,这里一下卡住了,然后晚上搜索了一下,发现是字符串常量的只读属性导致此处修改失败,只需要将char *str = "abcdefg" 修改为char str[] = "abcdefg",修改后发现正确了,下面简单总结一下:

    bug原因:

    char *str声明的字符串位于只读数据段,无法被修改,从而导致*p = *q这个尝试修改只读数据引发错误,程序退出

    解决方法:

    修改字符串使其处于栈区,代码如下

    char str[] = "abcdefg";

    调试:修改程序如下

    #include <stdio.h>
    
    void reverse_str(char *str){
        char *p = NULL,*q = NULL,tmp = 0;
        
        p = str;
        q = str;
        while( *(++q) != '' );q--;
        while(p < q){
            tmp = *p;
            *p = *q;
            *q = tmp;
            p++;
            q--;
        }
    }
    
    int main(void){
        char *tst = "abcdef";
        char str[] = "abcdef";
        reverse_str(str);
        printf("%s
    ",str);
        return 0;
    }

    编译:gcc -o tst.elf tst.c -g,然后反汇编:objdump -D tst.elf > tst.dis,得到相关部分代码如下所示,

    0000000000400617 <main>:
      400617:    55                       push   %rbp
      400618:    48 89 e5                 mov    %rsp,%rbp
      40061b:    48 83 ec 20              sub    $0x20,%rsp
      40061f:    64 48 8b 04 25 28 00     mov    %fs:0x28,%rax
      400626:    00 00 
      400628:    48 89 45 f8              mov    %rax,-0x8(%rbp)
      40062c:    31 c0                    xor    %eax,%eax
      40062e:    48 c7 45 e8 04 07 40     movq   $0x400704,-0x18(%rbp)        // char *tst = "abcdefg";
      400635:    00 
      400636:    c7 45 f0 61 62 63 64     movl   $0x64636261,-0x10(%rbp)        // char tst[] = "abcdefg";
      40063d:    66 c7 45 f4 65 66        movw   $0x6665,-0xc(%rbp)
      
    Disassembly of section .rodata:
    
    0000000000400700 <_IO_stdin_used>:
      400700:    01 00                    add    %eax,(%rax)
      400702:    02 00                    add    (%rax),%al
      400704:    61                       (bad)  
      400705:    62 63 64 65 66           (bad)  {%k5}

    由此可知:编译后产生的程序,char *str会放到.rodata段,也就是只读段;而char str[]则是放入栈(rbp是对栈的操作),是可修改的

    最后总结起来一句话:char *str定义字符串只读不可写,char str[]定义字符串可读可写

  • 相关阅读:
    [windows]清除访问共享的用户和密码信息
    Java架构搜集
    jsp、freemarker、velocity对比
    Spring MVC 了解WebApplicationContext中特殊的bean类型
    Web.xml配置详解之context-param
    <context:annotation-config/> 的理解
    使用@Controller注解为什么要配置<mvc:annotation-driven />
    web.xml配置之<context-param>详解
    @WebServlet
    正向代理与反向代理
  • 原文地址:https://www.cnblogs.com/Ethan-Gao/p/7420638.html
Copyright © 2020-2023  润新知