问题引入
以前一直认为二者是一样的,今天突然发现他们还是有很大的不同的。例如char *a = "abc"和char b[] = "abc",当我使用strcat(b,a)时得到的b是二者的结合,当我使用strcat(a,b)时系统报错。也就是说前者改变其内容程序是会崩溃的,而后者完全正确。
预备知识
内存分配的三种方式方式:静态存储区、堆区和栈区。它们的功能不同,使用方式也就不同。
1.静态存储区:内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。它主要存放静态数据、全局数据和常量。
2.栈区:在执行函数时,函数(包括main函数)内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。(任何变量都处于站区,例如int a[] = {1, 2},变量a处于栈区。数组的内容也存在于栈区。)
3.堆区:亦称动态内存分配。程序在运行的时候用malloc或new申请任意大小的内存,程序员自己负责在适当的时候用free或delete释放内存。动态内存的生存期可以由我们决定,如果我们不释放内存,程序将在最后才释放掉动态内存。 但是,良好的编程习惯是:如果某动态内存不再使用,需要将其释放掉,并立即将指针置位NULL,防止产生野指针。
解决问题
回到问题上来,我们来举个例子:char *a = "Hello",char b[] = "World",其中a是指向字符串第一个字符'H'的一个指针,b也是指向字符数组第一个字符'W'的指针,但这二者不相同,不同在哪呢?
char *a = "Hello":定义了一个char型的指针a,a在栈上,指向"Hello"所在的内存单元,它不知道这个内存单元有多大。"Hello"存放在常量区,是无法修的。通过指针a只可以访问字符串常量,而不可以改变它。它在编译时就会被确定。
char b[] = "World":定义一个字符数组,在栈上开了一块区域,b为这块区域的首地址。"World"是存放在这块区域中,是可以修改的。可以通过指针b去访问和修改数组内容。它要在运行时才会被确定。
贴段代码理解一下:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int main() { char *a="Hello";//a在栈上,"Hello"在常数区上 //a[2]='a';//系统错误:不可以修改常数区数据,只能读取 char b[]="Hello";//b在栈上,且为字符串"Hello"的首地址 b[2]='a';//可以这样做,可以修改 char *s1=(char*)malloc(64);//在栈上开辟一个区域放s1,在堆上开辟一个区域,再让s1指向他 char s2[64]; while(~scanf("%s %s",s1,s2)) { char *s3=s2;//此时s3与s2用法一样,因为他们指向同一个在栈上的地方 s3[2]='a'; printf("%s %s %s ",s1,s2,s3); } }
结论
在C/C++中,指针和数组在很多地方可以互换使用,这使得我们产生一种错觉,感觉数组和指针两者是完全等价的,事实上数组和指针是有很大的区别的。
数组对应着一块内存区域,而指针是指向一块内存区域,其地址和容量在生命期里不会改变,只有数组的内容可以改变;而指针却不同,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。
用运算符sizeof可以计算出数组的容量(字节数),而用sizeof却无法计算指针所指内存的容量,用sizeof(p)得到的结果永远是4或者2(即指针变量所占内存单元的字节数,一般情况下指针变量占2个或4个字节的内存单元)。在进行参数传递时,数组会自动退化为同类型的指针。
在使用过程中,我们可以给char*开辟空间,例如char *s=(char*)malloc(64);这个空间实在堆上的,使用起来就和字符数组很像了(几乎一样)
char* 类型使用总结:http://blog.csdn.net/z702143700/article/details/46628251
C语言字符串处理函数:http://www.cnblogs.com/alaigle/archive/2012/05/24/2516062.html
作者: AlvinZH
出处: http://www.cnblogs.com/AlvinZH/
本人Github:https://github.com/Pacsiy/JobDu
本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。