[英]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 const
和const 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 *
。 字符串文字是只读的,不会在堆栈上分配。 你可以自由地指向它们,并从函数返回那个, 而不会崩溃:)。
现在,什么是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 *str = new char[100];
可以使用delete []
释放此块。
char [] str2 = "Hi world!";
这个数组可以毫无问题地修改,这很好。 所以
str2[0] = 'N';
cout << str2;
应该打印Ni world!
达到标准输出,使某些骑士感到非常不舒服。
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.