汇编的角度分析指针-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; } }