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

    

  char* get_str(void)
{
char *str = "abcd";
return str;
}

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

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

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

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

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

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

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

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

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

     char a[];
a="Hello"; //error C2440: '=' : cannot convert from 'const char [6]' to 'char [8]'
char aa[]="hello"; //it's ok
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"。

 #include <stdio.h>  

 int main(void)
{
char *str="I am a boy!";
void reverse(char *start, char *end);
void reverseString(char *str);
reverseString(str);
puts(str); } void reverse(char *start, char *end)
{
char temp;
if(start==NULL||end==NULL)
return;
while(start<end)
{
temp=*start;
*start = *end;
*end=temp;
start++;
end--;
}
} void reverseString(char *str)
{
if(str==NULL)
return;
char *start,*end;
start=end=str;
while(*end!='\0')
{
end++;
}
end--; reverse(start,end); start=end=str;
while(*start!='\0')
{
if(*start==' ')
start=++end;
else
if (*end==' '||*end=='\0')
{
reverse(start,--end);
start=++end;
}
else
{
end++;
}
} }

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

根据报错的地址,发现是

 void reverse(char *start, char *end)
{
char temp;
if(start==NULL||end==NULL)
return;
while(start<end)
{
temp=*start;
*start = *end; //出错
*end=temp;
start++;
end--;
}
}

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

 
 

【转】char *str 和 char str[]的区别的更多相关文章

  1. char str[] 与 char *str的区别详细解析

    char* get_str(void) { char str[] = {"abcd"}; return str; } char str[] = {"abcd"} ...

  2. char str[]和char *str的区别

    1.http://blog.csdn.net/szchtx/article/details/10396149 char ss[]="C++";  ss[0]='c';        ...

  3. 初始化char指针--赋值和strcpy() 本质区别【转】

    原文地址:http://hi.baidu.com/todaygoodhj/item/0500b341bf2832e3bdf45180 使用常量字符串初始化char指针,或者使用strcpy复制,从语法 ...

  4. char,wchar_t,WCHAR,TCHAR,ACHAR的区别----LPCTSTR

    转自http://blog.chinaunix.net/uid-7608308-id-2048125.html 简介:这是DWORD及LPCTSTR类型的了解的详细页面,介绍了和类,有关的知识,加入收 ...

  5. 【C/C++】字符数组:char,char*,char a[], char *a[], char **s 的区别与联系/const char*和char*的区别

    一.char,char*,char a[], char *a[], char **s 的区别与联系 C语言中的字符串是字符数组,可以像处理普通数组一样处理字符串. 可以理解为在内存中连续存储的字符. ...

  6. 关于 char 和 unsigned char 的区别

    首先卖个关子: 为什么网络编程中的字符定义一般都为无符号的字符?   char buf[16] = {0}; unsigned char ubuf[16] = { 0 };   上面两个定义的区别是: ...

  7. C++ 字符串、string、char *、char[]、const char*的转换和区别

    1.字符串 字符串本质就是一串字符,在C++中大家想到字符串往往第一反应是std::string(后面简称string) 字符串得从C语言说起,string其实是个类,C语言是没有class的,所以C ...

  8. C/C++ char* arr与char arr[]的区别(反汇编解析)

    写作日期:2016.08.31 修改日期:2016.09.01 .2016.09.02. 交流qq:992591601 用了几天时间复习了下C语言.对于C语言的字符串操作有些不习惯,于是作为练习,写下 ...

  9. char *c和char c[]区别

    char *c和char c[]区别 问题引入:在实习过程中发现了一个以前一直默认的错误,同样char *c = "abc"和char c[]="abc",前者 ...

随机推荐

  1. 如何解析复杂的C语言声明

    C语言中有时会出现复杂的声明,比如   char * const * (*next) (); //这是个什么东东?   在讲复杂声明的分析方法前,先来个补充点.   C语言变量的声明始终贯彻两点 :  ...

  2. 文件头 MAGE_FILE_HEADER

    IMAGE_FILE_HEADER这个结构的定义如下: typedef struct _IMAGE_FILE_HEADER { 00h WORD Machine; //运行平台 02h WORD Nu ...

  3. linux2.6.32 内核源码树解析与整理

    一 系统最核心组件目录: 1 arch目录该目录中的每个子目录中都与某种体系结构相对应,用于存放体系结构相关代码,向平台无关的系统核心模块提供所需的功能接口.每个体系结构对应的子目录下通常至少包含以下 ...

  4. 再次探讨C++的动态绑定和静态绑定

    以前在学习C++的时候,对动态绑定和静态绑定的理解是:静态绑定是编译时决定的,非虚函数基本都是静态绑定:而动态绑定用于虚函数,是为了实现多态.这样理解没什么大的问题,但我一直疑惑的是,既然静态绑定可以 ...

  5. 自定义cell 自适应高度

    #pragma mark - 动态计算cell高度 //计算 返回 文本高度 + (CGFloat)calsLabelHeightWithContact:(Contacts *)contact { / ...

  6. 转:Yelp开发团队发布内部网站设计指南

    原文来自于:http://www.infoq.com/cn/news/2014/02/yelp-style-guide 近日,Yelp开发团队在博客发布消息:Yelp公开了内部网站设计指南.这份文档此 ...

  7. linux文件合并,去重,分割

    第一:两个文件的交集,并集前提条件:每个文件中不得有重复行1. 取出两个文件的并集(重复的行只保留一份)2. 取出两个文件的交集(只留下同时存在于两个文件中的文件)3. 删除交集,留下其他的行1. c ...

  8. std::vector的分片拷贝和插入

    一般我们在用Qt的QByteArrary或者List的时候,会有相应的append的方法,该函数,就是把数据加入末尾.但是std::vector就没有相应的方法.但是我们可以用insert方法来实现: ...

  9. sqlserver的rownum

    oracle: select  rownum from department sqlserver: select   row_number() over (order by id)  from dep ...

  10. 注意:rsyslog 源码安装 会出现日志重复发的情况,需要rpm包安装

    cd /etc/yum.repos.d;wget http://rpms.adiscon.com/v8-stable/rsyslog.repo uat-web02:/etc/yum.repos.d# ...