繁体   English   中英

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

[英]C++ strings: [] vs. *

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

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

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

char *str = "Hi all";

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

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

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

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

让我们看看它(对于下面的内容,请注意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";有什么看法char * s = "foo";

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

使用String文字初始化数组

现在,什么是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这样您就不会弃用。

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

char* str = new char[100];

让str指向堆。

char str2[] = "Hi world!";

将字符串放在堆栈上。

char* str3 = "Hi world!";

指向数据段。

这两个声明

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

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

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

  • 下面的代码初始化一个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 ++中的字符串?

作为已经给出的答案的补充,您应该阅读关于数组与指针的C FAQ 是的,这是一个C FAQ而不是C ++常见问题解答,但这个领域的两种语言之间几乎没有实质性区别。

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

另请参阅http://c-faq.com/aryptr/aryptr2.html.C-FAQ可能本身就是一本有趣的读物。

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

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

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

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


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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM