汇编的角度分析指针-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','\0'}; //也可以直接写 ,数组直接在堆栈中的缓冲区,写入了数据                   
                    
char names[] = "ABCDE";                   //在常量区的地址中,编译过后就存在了,可读不可写
                    
printf("%s\n",arr);                    
                    
printf("%s\n",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 != '\0')        
        dest++;    
    while((*dest++ = *src++)!='\0');        
            
    return dest;        
}            
            

 

int strcmp(char* s1, char* s2)            
{            
    while(*s1 != '\0' && *s2 != '\0')        
    {        
        if(*s1 != *s2)    
        {    
            return 1;
        }    
        s1++;    
        s2++;    
    }        
    if(*s1 == '\0' && *s2 == '\0')        
    {        
        return 0;    
    }        
    else        
    {        
        return 1;    
    }        
}            

 

posted @ 2021-01-04 15:18  heyhx  阅读(129)  评论(0编辑  收藏  举报