char str[] 和char *str 的区别

一、C语言中的几个存储区

一个由C/C++编译的程序占用的内存分为以下几个部分

1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

3、全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域;未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。

4、常量区:常量字符串就是放在这里的。程序结束后由系统释放。

5、程序代码区

例如:

  //main.cpp
  int a=0;    //全局初始化区
  char *p1; //全局未初始化区
  main()
  {
      int b;                  //栈
      char s[]="abc";         //栈
      char *p2;               //栈
      char *p3="123456";      //123456\0在常量区,p3在栈上。
      static int c=0;         //全局(静态)初始化区
      p1 = (char*)malloc(10);
      p2 = (char*)malloc(20);   //分配得来得10和20字节的区域就在堆区。
      strcpy(p1,"123456");      //123456\0放在常量区,编译器可能会将它与p3所向"123456"优化成一个地方。
 }

二、问题:

使用两个字符串指针,使用memcpy为什么会报段错误?

1、问题

void test(void)
{
        char * a = "hello world1";
        char * b = "hello world2";
        memcpy(a, b, strlen(b) + 1); // 此时会直接段错误
		return 0;
}

void main(void){
	test();
}

解释:
char *str = "hello world"//一份拷贝,"hello world"是常量字符串存在静态数据区,把该字符串常量存在的静态数据区的首地址赋给指针str,所以test()函数退出时,该字符串常量所在内存不会被回收,故能通过指针访问; 而memcpy的第一个参数是变量,不能是常量,因此在此时会报错。

2、问题

void test(void)
{
        char  a[] = "hello world1";
        char  b[] = "hello world2";
        memcpy(a, b, strlen(b) + 1); // 此时程序正常
		return 0;
}

void main(void){
	test();
}

解释:
str[] = "hello world"//"hello world"常量字符串在内存中有两份拷贝,一份在动态分配的栈中,一份在静态存储区,str[]数组为函数内部局部变量,存储在栈上,在test()函数退出时,栈要清空,局部变量的内存也被清空

3、问题

void c(int n,char *pName)
{
    char *a[4] = {"aaa","bbb","ccc","ddd"};
    pName = a[n];
}

void main()
{
    int n=0;
    char *pName = "DB";

    c(2,pName);
    printf("%s\n",pName);    //输出为DB
}

解释:
//输出DB,因为char *pName = “DB”;已经使得pName指向了DB,但c(2,pName);并不能改变pName指向的地址。形象点说就是:我有一个箱子给你用,你可以在里面装东西,但是你不能把我的箱子换成另外一个给我。在这里指的是不能函数调用不能使pName变成函数中的二维数组a。

三、找到个新的博客园作者的分享,比较经典,分享一下:

原网址

#include <stdio.h>

//此函数中d也是个局部变量,函数执行完自动销毁,但是指针分配的空间不会被自动回收,除非程序员delete掉。
//所以这个可以正常输出。
char *a()
{
    char *d = "ZET";//这个初始化的一种形式,相当于分配了四个空间
    return d;
}

//但是第二个数组空间是系统维护的,函数执行完自动销毁 
char *b()
{
    char p[10] = {"3G平台"};
    return p;
}


//参数是值传递方式,改变形参的地址,传递的实参的地址确不会因此改变 
void c(int n,char *pName)
{
    char *a[4] = {"aaa","bbb","ccc","ddd"};
    pName = a[n];
}

void main()
{
    int n=0;
    char *pName = "DB";
    printf("%s\n",a());//输出ZET
    printf("%s\n",b());//随机输出乱码

    c(2,pName);
    printf("%s\n",pName);    //输出DB,因为char *pName = "DB";已经使得pName指向了DB,但c(2,pName);并不能改变pName指向的地址。
 //形象点说就是:我有一个箱子给你用,你可以在里面装东西,但是你不能把我的箱子换成另外一个给我。
 //在这里指的是不能函数调用不能使pName变成函数中的二维数组a。
    
    scanf("%d",&n);
}

问题四

 1 #include<stdio.h>                                                                                           
  2 #include<string.h>                                                                                          
  3                                                                                                             
  4 int main(void)                                                                                              
  5 {                                                                                                           
  6     //char* buf="1-test"; //换成该行会直接段错误                                                            
  7     char buf[10]="1-test"; //换成此时是正常的                                                               
  8     char *temp =NULL;                                                                                       
  9 |   temp = strtok(buf,"-");                                                                                 
 10 |   printf("%s\n",temp);                                                                                    
 11     return 0;                                                                                               
 12 }   

1、char* buf="1-test"; //换成该行会直接段错误
2、char buf[10]="1-test"; //换成此时是正常的

第一行的1-test字符串是在常量区,也就是说该buf的内容是不能进行改变的,而strtok函数的意思是按照截断的字符进行替换,因为字符串是不能进行替换的,也就是说此时的内容必然会报错。
第二行的"1-test"是在堆区,是一个变量,即可以进行替换,因此,此时对字符串的内容进行替换是没有问题的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绛洞花主敏明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值