zoukankan      html  css  js  c++  java
  • 汇编的角度分析指针-03(字符串深入理解)

    1、字符串数组与字符串  

    //字符数组
    char arr[6] = {'A','B','C','D','E','F'};
    //字符串                
    char names[] = "ABCDE";            
                    

    反汇编代码如下:

    0040D4B0   push        ebp
    0040D4B1   mov         ebp,esp
    0040D4B3   sub         esp,54h
    0040D4B6   push        ebx
    0040D4B7   push        esi
    0040D4B8   push        edi
    0040D4B9   lea         edi,[ebp-54h]
    0040D4BC   mov         ecx,15h
    0040D4C1   mov         eax,0CCCCCCCCh
    0040D4C6   rep stos    dword ptr [edi]
    0040D4C8   mov         byte ptr [ebp-8],41h    //A
    0040D4CC   mov         byte ptr [ebp-7],42h    //B 
    0040D4D0   mov         byte ptr [ebp-6],43h    //C
    0040D4D4   mov         byte ptr [ebp-5],44h    //D
    0040D4D8   mov         byte ptr [ebp-4],45h    //E
    0040D4DC   mov         byte ptr [ebp-3],46h    //F
    0040D4E0   mov         eax,[string "ABCDE" (00422fa8)]
    0040D4E5   mov         dword ptr [ebp-10h],eax
    0040D4E8   mov         cx,word ptr [string "ABCDE"+4 (00422fac)]
    0040D4EF   mov         word ptr [ebp-0Ch],cx

    字符数组的反汇编中内存中的数据:

    字符串在内存的表现为:结尾多了00,编译器在字符串后边加了  00 作为字符串的结束标记

    论证结论:

    char arr[6] = {'A','B','C','D','E',''}; //也可以直接写 ,数组直接在堆栈中的缓冲区,写入了数据                   
                        
    char names[] = "ABCDE";                   //在常量区的地址中,编译过后就存在了,可读不可写
                        
    printf("%s
    ",arr);                    
                        
    printf("%s
    ",names);                    
                        
    
    执行结果都为   ABCDE 并没有‘0’输出

    2、查看下边的内容哪个可以修改  哪个不可以修改

      

    char* x = "china";            
    char y[] = "china";            
    void Function()            
    {            
                
        *(x+1) = 'A';        //不可以修改,在常量区,可读不可写
                
        y[1] = 'A';          //可以修改,因为在调用的函数的时候把值从常量区复制到了堆栈中
    } 

    观察*(x+1)出的反汇编,并得出为什么不可以修改:

     总结:之所以不可以修改,因为编译器在试图修改常量区的值,而常量区是可读不可写的区域

      

    观看  y[1]='A'  可以修改的反汇编:

    00401038   mov         dword ptr [ebp-4],offset string "china" (0042201c)
    0040103F   mov         eax,[string "china" (0042201c)]   //把从0042201c处的地址值,往后读了四个,放到eax中(chin)
    00401044   mov         dword ptr [ebp-0Ch],eax           //把eax中读到的四个字节放到堆栈中 
    00401047   mov         cx,word ptr [string "china"+4 (00422020)]//把  a与00  两个字节读到cx中
    0040104E   mov         word ptr [ebp-8],cx                 //把cx中读到的两个字节放入堆栈中
    00401052   mov         byte ptr [ebp-0Bh],41h               //修改堆栈中(ebp-0Bh)的值,而非修改的常量区的值

    总结:之所以可以修改,是因为把常量区的值复制到了堆栈中,修改的值是堆栈中的值,而非直接修改的常量区的值

    void Function()            
    {            
        char* x = "china";        
                
        char y[] = "china";        
                
        *(x+1) = 'A';     //不可以修改,在常量区,缓存中存放的只不过是字符串的地址,而不是字符串本身的值  
                
        y[1] = 'A';       //可以修改,因为数组在用的时候,cpu会把常量区的值复制到了堆栈中,修改的只是堆栈中的值,而非常量区的值
    }   

    3、字符串常用的函数

    int strlen (char* s)        
    {        
        int len = 0;    
        while(*s != 0)    //如果没有遇到'/0'的结束符,将一直读下去
        {    
            len++;
            s++;
        }    
        return len;       //返回了字符串或者字符数组的长度
    }        
    char* strcpy (char* dest,char* src)            
    {            
        while((*(dest++)=*(src++))!=0);        
                
        return dest;        
    }            
    char* strcat (char* dest, char* src)            
    {            
        while(*dest != '')        
            dest++;    
        while((*dest++ = *src++)!='');        
                
        return dest;        
    }            
                
    int strcmp(char* s1, char* s2)            
    {            
        while(*s1 != '' && *s2 != '')        
        {        
            if(*s1 != *s2)    
            {    
                return 1;
            }    
            s1++;    
            s2++;    
        }        
        if(*s1 == '' && *s2 == '')        
        {        
            return 0;    
        }        
        else        
        {        
            return 1;    
        }        
    }            
  • 相关阅读:
    关于使用css3属性:transform固定菜单位置,在滑动页面时菜单闪现抖动的问题
    使用iscroll.js插件时,遇到在Android端无法点击a超链的解决办法
    window.external的使用
    SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系
    chain.doFilter(request,response)含义
    巧用Ajax的beforeSend 提高用户体验
    getRequestDispatcher(path).forward(),,执行完,后面的代码居然还会执行!!!记得加return 啊亲
    @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
    ajax修改表单的值后dom没更新的解决办法
    .net core json序列化首字符小写和日期格式处理
  • 原文地址:https://www.cnblogs.com/heyhx/p/14230027.html
Copyright © 2011-2022 走看看