博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
char * 与char []探究理解
阅读量:4355 次
发布时间:2019-06-07

本文共 1996 字,大约阅读时间需要 6 分钟。

问题引入

以前一直认为二者是一样的,今天突然发现他们还是有很大的不同的。例如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 
#include
#include
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\n",s1,s2,s3); }}

结论

在C/C++中,指针和数组在很多地方可以互换使用,这使得我们产生一种错觉,感觉数组和指针两者是完全等价的,事实上数组和指针是有很大的区别的。

数组对应着一块内存区域,而指针是指向一块内存区域,其地址和容量在生命期里不会改变,只有数组的内容可以改变;而指针却不同,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。

用运算符sizeof可以计算出数组的容量(字节数),而用sizeof却无法计算指针所指内存的容量,用sizeof(p)得到的结果永远是4或者2(即指针变量所占内存单元的字节数,一般情况下指针变量占2个或4个字节的内存单元)。在进行参数传递时,数组会自动退化为同类型的指针。

在使用过程中,我们可以给char*开辟空间,例如char *s=(char*)malloc(64);这个空间实在堆上的,使用起来就和字符数组很像了(几乎一样)

 

char* 类型使用总结:

C语言字符串处理函数:

 

作者: 

出处: 

本人Github:

本文版权归作者AlvinZH和博客园所有,欢迎转载和商用,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

转载于:https://www.cnblogs.com/AlvinZH/p/6815414.html

你可能感兴趣的文章
制造行业流程管理的“IPO”思维
查看>>
Android PhotoView基本功能实现
查看>>
基于Docker搭建MySQL主从复制
查看>>
两台centos之间传送文件
查看>>
使用DevExpress官方汉化文件对界面进行汉化的过程
查看>>
关于获取各种浏览器可见窗口大小的一点点研究
查看>>
C#获取枚举描述
查看>>
emwin 之模态窗口
查看>>
.NET (C#) Internals: ASP.NET 应用程序与页面生命周期(意译)
查看>>
值语义与对象语义
查看>>
查找(二叉排序树)
查看>>
python全栈开发-Day8 函数基础
查看>>
ESE Toolkit:使用Windows的内部高性能数据库构建应用程序
查看>>
为Windows 8开发业务应用程序
查看>>
<authentication> 元素
查看>>
svn向服务器添加新建文件夹
查看>>
iphone UI 开发教程
查看>>
简单选项卡加圆角
查看>>
soritong MP3播放器缓冲区溢出漏洞分析
查看>>
17.10.24 数据最水的一次考试
查看>>