一、概念不同
char *str 声明的是一个指针,这个指针可以指向任何字符串常量。char str[] 声明的是一个字符数组,数组的内容可以是任何内容,严格意义上说,末尾加上'\0' 之后才能算是字符串,
二、变量不同
char *str里的str是指针变量,str的值未初始化(局部变量的话。全局则自动初始化为NULL)。char str[ ]里str是地址常量,str的值是str[ ]的地址。
三、定义方法不同:
在char * str中,明显str的类型是char*。这没什么特殊的,只是一个简单的char指针。char str[]是不能这样定义的,所以假定用char str[6] = "abcde";那么这里str的类型是char[6](6个,不是5个,因为最后有个0) ,而这种定义语句也是定义一个char[6]类型的唯一方法。
楼上说的都有道理,但是没解释出本质区别。
区别就在于两个定义中str的类型不同。
第一个,在
char * str;
中,明显str的类型是char*。这没什么特殊的,只是一个简单的char指针。
第二个,char str[];是不能这样定义的,所以假定用
char str[6] = "abcde";
那么这里str的类型是char[6](6个,不是5个,因为最后有个0) ,而这种定义语句也是定义一个char[6]类型的唯一方法。char[6]是什么意思呢?他不是char*,也不是char* const (以下讨论这个),而是一个特殊的类。这个类的大小是6字节(比如sizeof(str)返回6),它可以用[ ]来返回一个char&(比如str[3]的类型是char&),但是自身不能直接被修改,比如str ="abcde";就不可以。
我刚才说char[6]很像char* const。这是因为,假如有
char* const str2 = "abcde";
那么str和str基本有同样的行为,比如str2[3]也是一个char&,而且str2 = "abcde"也不可以用,但是char* const和char[6]有本质的不同。前者只是一个指针。什么意思呢,就是str2的值是"abcde"的地址(而"abcde"被存在其他的地方),而str的内存值直接就是6个字节,"abcde"。所以两者还是截然不同的类型。比如,sizeof(str2)是4(32位操作系统)或8(64位),而sizeof(str)是6.
char[6]可以被直接转换为char*。转换的时候,得到的结果是一个指向第一个元素的指针。反过来,char*也可以转换为char[6],转换的结果是一个变量指向char*所指向的那个内存区域。
楼上说的str++可以在char* str时用而不能在char str[6]时用,这是因为数组类型 char[6]不能用作一个左值。
楼上还有说char * str可以指向任何字符串常量。这个是无必要的。char *可以指向任何内存区域,不一定必须是字符串常量。当然,如果指向一个无效内存,用的时候会出问题。
另外楼上说一个"Hello World!"放在常量储存区,一个"Hello World!"放在线程堆栈区,这也是不对的。事实上,无论如何,"Hello World!"本身都在常量储存区。而:
char *str = "Hello World!";
会在堆栈上储存一个4个字节(假定32位系统)的指针指向储存"Hello World!"的区域。
而
char str[] = "Hello World!";
会首先在堆栈上先分配一个13字节的char数组,然后把常量储存区的那个"Hello World!"复制过来。
char *str 声明的是一个指针,这个指针可以指向任何字符串常量;
char str[] 声明的是一个字符数组,数组的内容可以是任何内容,严格意义上说,末尾加上'\0' 之后才能算是字符串
两者都代表一个字符数组存储空间的首地址,区别在:
char *str;
这个变量可以进行指针运算,比如:
str++;
str--;
但如果定义成:
char str[];
则str++这样的语句是错误的,这个首地址不得进行赋值计算。
在不改变str指针指向地址的情况下,下面的语句是一样的结果。
printf("%s",str+2);
第一种为定义一个指针变量;
第二种为定义一个数组;
如果定义时为其赋初始值,如char *str1 = "Hello World!"; char *str2[] = "Hello World!";前者编译器把"Hello World!"放在常量储存区;后者把"Hello World!"放在线程堆栈区,当str2离开作用域所占用内存即收回.