char* p 和 char p[] 的区别

        在最近的项目中频繁的使用char* p 和 char p[ 10 ],总是默认的以为他们相同,可是在用的过程中总是出现一些错误。在网上搜了下还是有许多的讲解,就整理下添加自己的一下想法。

char* p = "HelloWorld";

"HelloWorld"的类型是 const char*,编译器在编译的过程中会在静态数据区为"HelloWorld"分配空间存储这个字符串,然后将字符串的首地址赋值给指针 char* p。当使用指针p试图改变"HelloWorld"时,如:p[0] = 'a',编译器并不会出错,但是在运行时会出错。改成char p[] = "HelloWorld"就不会出错了,char p[] = "HelloWorld"现在内存中开辟一连续存储单元,然后将字符串存到存储单元。


        函数中可以返回,已经申请内存空间的局部变量的指针:

char* str()
{
       char* p;
       p = (char*)malloc(10);
       return p;
}

 实例A:

#include <stdio.h>
char *returnStr()
{
    char *p="Hello world!";
    return p;
}
int main()
{
    char *str = NULL;//一定要初始化,好习惯
    str = returnStr();
    printf("%s \n", str);
   
    return 0;
}

这个没有任何问题,因为"HelloWorld"是字符窜常量,存放在静态数据区。把该字符串存放在静态数据区的首地址赋值给了指针。所以在returnStr()执行完成后,该字符串所在的内存不会被回收,通过指针能够正常的访问。

实例B:

#include <stdio.h>
char *returnStr()
{
    char p[] = "hello world!";
    return p;
}
int main()
{
    char *str = NULL;//一定要初始化,好习惯
    str = returnStr();
    printf("%s \n", str);
   
    return 0;
}

”HelloWorld"是字符串常量,但是把字符串常量赋值给局部变量(char p[] 型数组),该局部变量存放在栈中。这样就有两块一样的内存,也就是说 ”char p[] = "HelloWorld"; “ 这条语句让”HelloWorld“这个字符串在内存中有两份拷贝,一份在动态分配内存的栈中,另一份在静态存储区,这是与前者的区别。

       当returnStr()执行结束后,栈要被清空,局部变量的内存也被释放。所以这时函数返回的是一个已被释放内存地址,打印出来也就是乱码。

如果真要返回一个局部变量的地址,那么该局部变量一定要设为static类型。

实例B-1:

#include <stdio.h>
char *returnStr()
{
    static char p[] = "Hello world!";
    return p;
}
int main()
{
    char *str = NULL;
    str = returnStr();
    printf("%s \n", str);
   
    return 0;
}


这个问题可以通过下面的一个例子来更好的说明:

#include <stdio.h>
//返回的是局部变量的地址,该地址位于动态数据区,栈里

char *s1()
{
    char* p1 = "qqq";//为了测试‘char p[]="Hello world!"’中的字符串在静态存储区是否也有一份拷贝
    char p[]="Hello world!";
    char* p2 = "w";//为了测试‘char p[]="Hello world!"’中的字符串在静态存储区是否也有一份拷贝
    printf("in s1 p=%p\n", p);
    printf("in s1 p1=%p\n", p1);
    printf("in s1: string's address: %p\n", &("Hello world!"));
    printf("in s1 p2=%p\n", p2);
    return p;
}

//返回的是字符串常量的地址,该地址位于静态数据区

char *s2()
{
    char *q="Hello world!";
    printf("in s2 q=%p\n", q);
    printf("in s2: string's address: %p\n", &("Hello world!"));
    return q;
}

//返回的是静态局部变量的地址,该地址位于静态数据区

char *s3()
{
    static char r[]="Hello world!";
    printf("in s3 r=%p\n", r);
    printf("in s3: string's address: %p\n", &("Hello world!"));
    return r;
}

int main()
{
    char *t1, *t2, *t3;
     t1=s1();
     t2=s2();
     t3=s3();
   
    printf("in main:");
    printf("p=%p, q=%p, r=%p\n", t1, t2, t3);

    printf("%s\n", t1);
    printf("%s\n", t2);
    printf("%s\n", t3);
   
    return 0;
}


运行输出结果为:

in s1 p=0013FF0C
in s1 p1=00431084
in s1: string's address: 00431074
in s1 p2=00431070
in s2 q=00431074
in s2: string's address: 00431074
in s3 r=00434DC0
in s3: string's address: 00431074
in main:p=0013FF0C, q=00431074, r=00434DC0
$
Hello world!
Hello world!

这个结果刚好解释了上面,同时得出一个结论。

字符串常量之所以成为常量,因为他可以看做是一个没有命名的字符串而且是常量,存放在静态数据区。

这里的静态数据区,是相对堆和栈等动态数据区而言。

静态数据区存放的是全局变量和静态变量,所以字符串常量又可以称之为一个无名的静态变量。

因为”HelloWorld“这个字符串在函数s1()和s2()中都引用了,但在内存中只有一个拷贝,这与静态变量性质相似。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值