zoukankan      html  css  js  c++  java
  • 【转】char *str 和 char str[]的区别

    转自】http://blog.csdn.net/hackbuteer1/article/details/6706562    在原文的基础上稍作修改 
    1  char* get_str(void)  
    2  {  
    3      char str[] = "abcd";  
    4      return str;  
    5  } 

                char str[] = "abcd";定义了一个局部字符数组,返回它的地址肯定是一个已经释放了的空间的地址。 此函数返回的是内部一个局部字符数组str的地址,且函数调用完毕后 此数组被销毁,所以返回的指针也就指向一块被销毁的内存,这种写法得不到想要的结果,是错误的。

        

    1  char* get_str(void)  
    2  {  
    3      char *str = "abcd";  
    4      return str;  
    5  }  

          char* str = "abcd";表示先定义个字符串常量,存储在文字常量区,然后将其地址赋给str,即str指向字符串“abcd”。 此函数返回的是字符串常量的地址,而像这种字符串都是属于全局的,在编译的时候就已经分配了内存了,只有程序退出的时候才会被销毁,所以返回它的地址是没有问题的,但是值得注意的是,我们不能去改变字符串的值,因为存储在文字常量区的字符串只能读不能写。另外值得注意的是:这个char型的str指针属于局部变量,存储在栈里面,只是字符串在文字常量区,所以函数返回的时候,先将字符串在文字常量区的地址返回,然后作用域结束后释放str在栈里面的空间。

     
    1 const char str[] = "abcd";        //abc存储在堆栈中  
    2 const char *str = "abcd";         //abc存储在静态存储区  

            准确的说,上面两个“abcd"都是存储在静态数据区,即文字常量区。文字常量区是可读不可写的。所以任何试图对常量区进行写的操作都是非法的,当然了,这也不是一定不可写的,你可以采取某种渠道改变文字常量区的内存属性,比如改变pe相关节的属性就可以对常量区进行读写,当然了,这个目前可以忽略。。。
           那么为什么str[] = "abcd";      可以写呢?   答案就在str[] = "abcd";会有一个额外的拷贝过程,即把文字常量区的 "abcd"拷贝到栈内存去,存入到str数组中,所以就可以写了。

          总结:
    所有以" "或' '包含的字符、字符串都是常量,应该是存储在堆上。

    1 char *str = "xxxxx"//str指向文字常量区中该字符串的地址,“xxxxx”是全局的,但str仍然是局部变量。
    2 char str[] = "xxxxx"//str在栈上申请空间,将文字常量区的字符串内容复制进来,所以"xxxxx"变成局部变量。

    首先,数组和指针是不同的数据类型,有本质的区别:

    1 char str[] = "abcd";         //sizeof(str) == 5 * sizeof(char)
    2 char * str = "abcd";        //sizeof(str) == 4(x86) or 8(x64),是个指针,无论什么类型的指针在32位机器上的大小均为4bytes

    再然后,"abcd"叫做“字符串常量”,任何类型的常量都是右值(没有名字的临时变量),必须让"abcd"成为左值(有名字的变量),才能够修改"abcd"这个字符串。

    1 char str[] = "abcd";              //等号两端是相同的数据类型,右值成为左值
    2 char * str = "abcd";             //等号两端是不同的数据类型,右端自动转型成char*,该str得到了“abcd”的地址,而"abcd"这个char数组仍然没有名字。

    最后 char a[]="Hello";与char aa[8];aa="Hello" 的不同之处在哪为什么第一个对,第二个错?

    1     char a[8];
    2     a="Hello"; //error C2440: '=' : cannot convert from 'const char [6]' to 'char [8]'
    3     char aa[8]="hello";  //it's ok
    4     char *aaa="hello";  //it's ok
    为什么必须在定义的时候初始化呢?

        char a[8];这样定义了一个数组后,数组名a就是个地址常量,也就是指针常量,只能指向该数组在内存地址空间中的首地址。不可以再指向别的地址。所以如果a = "hello";就是把文字常量区的字符数组"hello"的首地址赋给地址常量a,这是不允许的。
         如果写成char aa[8] = "hello";这就是在定义数组a的时候就对其初始化,把"hello"串的每个字符赋值给数组a的元素,在这里存在一个拷贝的过程。这是合理的。

         char *aaa="Hello";也定义了一个指针,而该指针可以指向文字常量区的字符数组"Hello"的首地址,也可以指向文字常量区的字符数组"world"的首地址。

    下面通过一个程序具体看一下。【转自】http://blog.csdn.net/sdlyjzh/article/details/17342541

    该程序是为了实现讲字符串中的单词逆序,例如,如果输入“I am a boy",希望输出"boy a am I"。

     1 #include <stdio.h>  
     2   
     3 int main(void)  
     4 {  
     5     char *str="I am a boy!";  
     6     void reverse(char *start, char *end);  
     7     void reverseString(char *str);  
     8     reverseString(str);  
     9     puts(str);  
    10   
    11   
    12 }  
    13   
    14   
    15 void reverse(char *start, char *end)  
    16 {  
    17     char temp;  
    18     if(start==NULL||end==NULL)  
    19         return;  
    20     while(start<end)  
    21     {  
    22         temp=*start;  
    23         *start = *end;  
    24         *end=temp;  
    25         start++;  
    26         end--;  
    27     }  
    28 }  
    29   
    30   
    31 void reverseString(char *str)  
    32 {  
    33     if(str==NULL)  
    34         return;  
    35     char *start,*end;  
    36     start=end=str;  
    37     while(*end!='\0')  
    38     {  
    39         end++;  
    40     }  
    41     end--;  
    42   
    43     reverse(start,end);  
    44   
    45     start=end=str;  
    46     while(*start!='\0')  
    47     {  
    48         if(*start==' ')  
    49             start=++end;  
    50         else  
    51         if (*end==' '||*end=='\0')  
    52         {  
    53             reverse(start,--end);  
    54             start=++end;  
    55         }  
    56         else  
    57         {  
    58             end++;            
    59         }  
    60     }  
    61   
    62 }

    程序编译没有问题,运行报错,提示写入内存0x........时失败。

    根据报错的地址,发现是

     1 void reverse(char *start, char *end)  
     2 {  
     3     char temp;  
     4     if(start==NULL||end==NULL)  
     5         return;  
     6     while(start<end)  
     7     {  
     8         temp=*start;  
     9         *start = *end;   //出错  
    10         *end=temp;  
    11         start++;  
    12         end--;  
    13     }  
    14 }  

    也就是给*start写入数据出错,原因就是由于主函数中用char *str 创建的字符串是一个常量。只要把他改为char str[]即可。

     
     
  • 相关阅读:
    【算法习题】青蛙跳台阶
    【转】从PowerDesigner概念设计模型(CDM)中的3种实体关系说起
    redis常用链接
    读书笔记——《redis入门指南(第2版)》第四章 进阶——4.1-5
    查询linux计算机的出口ip
    读书笔记——《redis入门指南(第2版)》第三章 入门
    vmware中的linux虚拟机配置以nat模式上网,并用xshell连接该虚拟机
    每日代码系列(1)
    第一次尝试自己编写
    原型模式
  • 原文地址:https://www.cnblogs.com/aheng123/p/5299592.html
Copyright © 2011-2022 走看看