C ++字符串:[] vs. *

时间:2008-11-21 09:46:36

标签: c++ syntax reference pointers

一直在想,用[]或*声明变量之间的区别是什么?我看待它的方式:

char *str = new char[100];
char str2[] = "Hi world!";

..应该是主要区别,但我不确定你是否可以做类似

的事情
char *str = "Hi all";

..因为指针应该引用一个静态成员,我不知道它是否可以?

无论如何,真正困扰我的是知道它们之间的区别:

void upperCaseString(char *_str) {};
void upperCaseString(char _str[]) {};

那么,如果有人能告诉我差异,我们将不胜感激吗?我有一种预感,除了在某些特殊情况下,两者都可以编译得相同吗?

6 个答案:

答案 0 :(得分:41)

让我们看看它(对于以下内容,注意char constconst char在C ++中是相同的):

字符串文字和字符*

"hello"是一个包含6个const字符的数组:char const[6]。作为每个数组,它可以隐式转换为指向其第一个元素的指针:char const * s = "hello";为了与C代码兼容,C ++允许另外一个转换,否则会形成错误:char * s = "hello";它会删除const !这是一个例外,允许编译C-ish代码,但不推荐使用char *指向字符串文字。那么我们对char * s = "foo";有什么看法?

"foo" - > array-to-pointer - > char const* - > qualification-conversion - > char *。字符串文字是只读的,不会在堆栈上分配。您可以自由地使指针指向它们,并从函数返回该指针,而不会崩溃:)。

使用字符串文字

初始化数组

现在,char s[] = "hello";是什么?这是整个其他的东西。这将创建一个字符数组,并用字符串"hello"填充它。字面意思没有指出。而是将其复制到字符数组中。并且数组在堆栈上创建。您无法从函数中有效地返回指向它的指针。

数组参数类型。

如何使函数接受数组作为参数?您只需将参数声明为数组:

void accept_array(char foo[]); 

但是你省略了它的大小。实际上,任何大小都会这样做,因为它只是被忽略:标准说,以这种方式声明的参数将被转换为与

相同
void accept_array(char * foo);

游览:多维数组

以任何类型替换char,包括数组本身:

void accept_array(char foo[][10]);

接受一个二维数组,其最后一个维度的大小为10. 多维数组的第一个元素是它的下一个维度的第一个子数组!现在,让我们改变它。它将再次指向其第一个元素。所以,实际上它会接受一个指向10个字符数组的指针:(删除头部的[],然后只需指向你在脑中看到的类型的指针):

void accept_array(char (*foo)[10]);

当数组隐式转换为指向其第一个元素的指针时,您只需在其中传递一个二维数组(其最后一个维度大小为10),它就可以工作。实际上,任何 n维数组都是这种情况,包括n = 1的特殊情况;

结论

void upperCaseString(char *_str) {}; 

void upperCaseString(char _str[]) {};

是相同的,因为第一个只是一个指向char的指针。但请注意,如果您想将String-literal传递给它(假设它不会更改其参数),那么您应该将参数更改为char const* _str,这样您就不会弃用。

答案 1 :(得分:12)

三个不同的声明使指针指向不同的内存段:

char* str = new char[100];

让str指向堆。

char str2[] = "Hi world!";

将字符串放在堆栈上。

char* str3 = "Hi world!";

指向数据段。

两个声明

void upperCaseString(char *_str) {};
void upperCaseString(char _str[]) {};

是相同的,当你尝试在同一范围内声明它们时,编译器会抱怨已经有一个正文的函数。

答案 2 :(得分:2)

好的,我留下了两条负面评论。这不是很有用;我删除了它们。

  • 以下代码初始化一个char指针,指向动态分配的内存部分的开头(在堆中)。

char *str = new char[100];

可以使用delete []释放此块。

  • 以下代码在堆栈中创建一个char数组,初始化为字符串文字指定的值。

char [] str2 = "Hi world!";

这个数组可以毫无问题地修改,这很好。所以


str2[0] = 'N';
cout << str2;

应该将Ni world!打印到标准输出,让某些骑士感到非常不舒服。

  • 以下代码在堆栈中创建一个char指针,指向字符串文字 ...指针可以重新分配而没有问题,但是指向的块不能被修改(这是未定义的行为;例如,它在Linux下的段错误。)

char *str = "Hi all";
str[0] = 'N'; // ERROR!
  • 以下两个声明

void upperCaseString(char *_str) {};
void upperCaseString(char [] _str) {};

对我来说看起来与相同,在你的情况下(你想要将字符串大写到位),这无关紧要。

然而,所有这些都引出了一个问题:为什么使用char *在C ++中表达字符串?

答案 3 :(得分:0)

作为已经给出的答案的补充,您应该阅读the C FAQ regarding arrays vs. pointers。是的,这是一个C FAQ而不是C ++常见问题解答,但这个领域的两种语言之间几乎没有实质性区别。

另外,作为旁注,请避免使用前导下划线命名变量。这是为编译器和标准库定义的符号保留的。

答案 4 :(得分:0)

请同时查看http://c-faq.com/aryptr/aryptr2.html C-FAQ本身可能是一本有趣的读物。

答案 5 :(得分:-1)

第一个选项动态分配100个字节。

第二个选项静态分配10个字节(字符串+ nul字符为9)。

您的第三个示例不起作用 - 您正在尝试静态填充动态项目。

对于upperCaseString()问题,一旦分配并定义了C字符串,就可以通过数组索引或指针表示法迭代它,因为数组实际上只是一种方便的方法来包装指针C中的算术。


(这是一个简单的答案 - 我希望其他人会从规范中获得权威,复杂的答案:))