18

一直在想,用 [] 或 * 声明变量有什么区别?我的看法:

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

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

char *str = "Hi all";

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

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

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

那么,如果有人能告诉我其中的区别,将不胜感激?我有一种预感,两者可能会被编译成相同的,除非在某些特殊情况下?

4

6 回答 6

42

让我们研究一下(对于以下内容,请注意char constconst char在 C++ 中相同):

字符串文字和 char *

"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";?这完全是另一回事。这将创建一个字符数组,并用 String 填充它"hello"。文字没有被指出。相反,它被复制到字符数组中。并且数组是在堆栈上创建的。您不能从函数有效地返回指向它的指针。

数组参数类型。

如何让你的函数接受一个数组作为参数?您只需将参数声明为数组:

void accept_array(char foo[]); 

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

void accept_array(char * foo);

游览:多维数组

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

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

接受一个二维数组,其最后一维的大小为 10。多维数组的第一个元素是其下一维的第一个子数组!现在,让我们对其进行改造。它将再次成为指向其第一个元素的指针。因此,实际上它会接受一个指向 10 个字符数组的指针:(删除[]in 头,然后只创建一个指向您在头中看到的类型的指针):

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

由于数组隐式转换为指向其第一个元素的指针,因此您只需在其中传递一个二维数组(其最后一维大小为 10),它就会起作用。事实上,任何n 维数组都是如此,包括 ; 的特殊情况n = 1

结论

void upperCaseString(char *_str) {}; 

void upperCaseString(char _str[]) {};

是一样的,因为第一个只是指向 char 的指针。但请注意,如果您想将字符串文字传递给它(假设它不会更改其参数),那么您应该将参数更改为,char const* _str这样您就不会做不推荐使用的事情。

于 2008-11-21T13:18:02.817 回答
12

三种不同的声明让指针指向不同的内存段:

char* str = new char[100];

让 str 指向堆。

char str2[] = "Hi world!";

将字符串放入堆栈。

char* str3 = "Hi world!";

指向数据段。

两个声明

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

相等,当您尝试在同一范围内声明它们时,编译器会抱怨该函数已经有一个主体。

于 2008-11-21T10:02:51.677 回答
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++ 来表达字符串?

于 2008-11-21T14:56:29.090 回答
0

作为对已经给出的答案的补充,您应该阅读有关数组与指针的 C 常见问题解答。是的,它是 C 常见问题解答而不是 C++ 常见问题解答,但是这两种语言在这方面几乎没有实质性区别。

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

于 2008-11-21T13:30:28.640 回答
0

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

于 2008-11-21T16:18:25.290 回答
-1

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

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

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

至于这个upperCaseString()问题,一旦 C 字符串被分配和定义,你可以通过数组索引或指针符号来迭代它,因为数组实际上只是在 C 中包装指针算术的一种方便方法。


(这是简单的答案——我希望其他人会得到规范之外的权威、复杂的答案:))

于 2008-11-21T10:01:41.103 回答