一、字符数组与字符串
-
字符数组:
char arr[10] = {'A','B','C','D','E','F'}; //编译器默认在结尾添加0x00 char arr[3] = {'A','B','C'}; //但是如果没有留出'\0'的空间,编译器就不会自动添加 char buffer[100] = ""; //定义了一个空字符串,字符串中每个字节默认初始为0x00 char buffer[] = ""; //这个数组长度只有1,且默认初始为0x00注意:定义字符数组来表示字符串时,一定要在结尾给
'\0',我们可以手动添加,也可以不添加让编译器自己自动帮我们在结尾处添加'\0',但是一定要注意如果让编译器添加的话,要把字符数组的宽度的长度设置好,一定要预留空间给'\0'

-
字符串:(也是字符数组的一种,特殊的赋值方式)
char names[] = "ABCDE"; //可以省略数组大小,但是此时的数组大小应该6,因为编译器会自动在末尾加0x00 char* p = "ABCDE"; //这个是将常量区中存储ABCDE字符串的首地址赋给p,此时p的长度是4字节,常量区的字符 串虽然后面补0,但是不能算到字符串的长度中,所以字符串的长度应为5字节注意:编译器在后面添一个 00 做为字符串的结束标记;如果用数组定义的字符串则存在内存中,但指针定义的字符串存在常量区
-
输出字符数组或者字符串:
char arr1[6] = {'A','B','C','D','E','\0'}; char arr2[6] = {'A','B','C','D','E',0}; //注意区分这里的0不是'0' char arr3[6] = {'A','B','C','D','E'}; //只要比5大,数组的长度随便 char names[] = "ABCDE"; printf("%s\n",arr1); printf("%s\n",arr2); printf("%s",names); char word[8]; scanf("%7s", word);//最多读7个字符上面的结果都是一样的,都打印ABCDE
-
%s的用法:打印一个字符串,直到内存为 0 为止。这个0相当于16进制的0,平时我们用则使用0或者'\0'来表示 -
字符串数组:
char a[][10] = {"hello","abcdefg"}; char *a[] = {"hello","abcdefg"};
二、常量区
-
内存分布区还记得吗?当中有一个常量区,可读不可写
-
什么数据存在常量区:字符串等
三、字符串的反汇编(指针)
-
存储在常量区的数据无法修改:
char* x = "china"; //x中存的就是存储在常量区的china字符串的首地址,x指针型变量直接指向常量区中的存储 china字符串的首地址 char y[] = "china"; //这里也是常量区中的china字符串,但是与指针不同的是,这里会将字符串值复制一份到给y 字符数组变量分配的内存中(栈) void Func(){ y[1] = 'A'; //可以修改 //*(x + 1) = 'A'; 无法修改 }x本身是可以再修改的:如
x = "abc";,但是x指向的字符串"china"是无法修改的!即x指向常量区的"china"字符串,现在想用x去改变常量区的字符串,也是不可以的。具体原因看下面反汇编! -
从反汇编角度分析
char* x = "china";与char y[] = "china";的区别-
先来分析一下
char* x = "china":因为char*类型宽度为4字节,VC编译器的执行一个函数时默认提升的堆栈空间为0x40字节,现在由于定义了一个char*类型的局部变量,所以会提升堆栈空间为0x40 + 0x4 = 0x44;而后我们发现反汇编中的操作就是将已经存储在常量区(内存中的某个区域)的字符串"china"的首地址0x422E80存入了给char*类型变量x分配的内存中(main函数的缓冲区),即**char*类型的变量x存储的是"china"字符串在常量区中的首地址**#include "stdafx.h" int main(int argc,char* argv[]){ char* x = "china"; //char y[] = "china"; return 0; }

所以可以发现使用指针类型变量x操作字符串其实就是修改常量区中的字符串,那么由于常量区中的数据可读不可写,所以编译器不允许使用
*(x + 1) = 'A'! -
再在分析
char y[] = "china":这是在main函数中定义了一个char类型的字符数组变量y,接着给字符数组赋值"china"。但是在反汇编中可以发现,这里由于没有使用指针了,那么这个操作就是把已经存储在常量区的字符串"china"复制一份,将数据存到main中为字符数组变量y分配的8字节内存中(因为局部变量遵循本机尺寸)。#include "stdafx.h" void main(int argc,char* argv[]){ //char* x = "china"; char y[] = "china"; y[1] = 'A'; }

这里之所以复制了两次是因为
char y[] = "china";字符数组变量y的长度应为6,因为末尾编译器会补0x00表示字符串结束,那么由于一个寄存器宽度为4字节,不够一次性就将常量区中的"china"常量复制到main给y变量分配的内存(缓冲区)中,所以会分两次,一次复制0x42201C开始往后的4字节(dword)数据,二次复制0x422020开始往后的2字节(word)数据,因为刚说过了要补0x00。最后我们可以发现,y[1] = 'A'的操作不是对常量区中的"china"字符串的操作,而是对复制过来的值操作,所以就可以修改!
-
-
所以:如果想对字符串做写操作,就定义成:
char arr[] = "abc";。如果只做读操作,定义成前面的或者char* arr = "abc";都是可以的。

被折叠的 条评论
为什么被折叠?



