字符串类型数组的指针运算,C++如何处理这个?

Posted

技术标签:

【中文标题】字符串类型数组的指针运算,C++如何处理这个?【英文标题】:Pointer arithmetic on string type arrays, how does C++ handle this? 【发布时间】:2009-06-17 10:17:42 【问题描述】:

我正在学习指针,但有一个概念困扰着我。 我知道,如果您有一个指向数组的 INT 类型指针(例如“pointer1”),那么您可以用 INTS 填充该数组。如果你想寻址数组的一个成员,你可以使用指针,你可以做 pointer1 ++;遍历数组。该程序知道它是一个 INT 数组,因此它知道以 INT 大小的步长单步执行。 但是如果数组是长度可以变化的字符串呢?当您尝试使用 ++ 递增每个元素的长度不同时,它怎么知道该怎么做?

类似地,当您创建一个字符串向量并使用reserve 关键字时,如果字符串可以有不同的长度,它如何知道要保留多少? 这可能真的很明显,但我无法解决它,它不符合我目前(可能是错误的)对指针的思考。 谢谢

【问题讨论】:

【参考方案1】:

很简单。

字符串数组不同于字符串向量。

字符串数组(C 风格指针)是指向字符数组“char**”的指针数组。所以字符串数组中的每个元素的大小都是“指向字符数组的指针”,因此它可以毫无问题地遍历字符串数组中的元素。数组中的指针可以指向不同大小的内存块。

对于字符串向量,它是一个字符串对象数组(C++ 风格)。每个字符串对象都具有相同的 object 大小,但在某处包含一个指向实际存储字符串内容的内存的指针。所以在这种情况下,向量中的元素的大小也是相同的,尽管不同于“只是一个指向字符数组的指针”,允许简单的元素地址计算。

【讨论】:

这正确解释了为什么所有 std::string 对象的大小相同。但我不同意“字符串数组”表示 char*[] 而“字符串向量”表示向量。你可以有一个字符串[] 或一个向量,所以当你谈论“字符串”时,你需要明确(也许从上下文中)你的意思。【参考方案2】:

这是因为字符串(至少在 C/C++ 中)与整数并不完全相同。如果我们在谈论 C 风格的字符串,那么它们的数组就像

char* test[3] =  "foo", "bar", "baz" ;

实际上发生的事情是“测试”是一个指针数组,每个指针都指向字符所在的实际数据。假设,随机,“测试”数组从内存地址 0x10000 开始,并且指针有四个字节长,那么我们可能有

test[0] (memory location 0x10000) contains 0x10020
test[1] (memory location 0x10004) contains 0x10074
test[2] (memory location 0x10008) contains 0x10320

然后我们可能会查看 0x10020 附近的内存位置,我们会找到实际的字符数据:

test[0][0] (memory location 0x10020) contains 'f'
test[0][1] (memory location 0x10021) contains 'o'
test[0][2] (memory location 0x10022) contains 'o'
test[0][3] (memory location 0x10023) contains '\0'

在内存位置 0x10074 附近

test[1][0] (memory location 0x10074) contains 'b'
test[1][1] (memory location 0x10075) contains 'a'
test[1][2] (memory location 0x10076) contains 'r'
test[1][3] (memory location 0x10077) contains '\0'

对于 C++ std::string 对象,情况大致相同:实际的 C++ 字符串对象不“包含”字符,因为正如您所说,字符串的长度是可变的。它实际上包含的是一个指向字符的指针。 (至少,它在 std::string 的简单实现中是这样——实际上它具有更复杂的结构来提供更好的内存使用和性能)。

【讨论】:

谢谢,你和哈维的回答真的很有帮助【参考方案3】:

字符串数组是指向某些字符串的第一个字符的指针数组。指向 char 的指针的大小可能与指向 int 的指针大小相同。

本质上,二维数组在内存中不一定是线性的,指向的数组可以在任何地方。

【讨论】:

【参考方案4】:

这可能看起来像迂腐,但在像 C++ 这样的轻率语言中,这很重要:在你原来的问题中,你说:

你可以做pointer1 ++;遍历数组。

Postincrement (pointer1++) 这里的语义通常错误,因为它的意思是“增加指针1,但保持表达式值在指针1的原始值”。如果不需要pointer1的原始值,可以使用pre-increment(++pointer1),语义上就是“指针加一”的意思。

出于某种原因,大多数 C++ 教科书到处都在做后增量,教 C++ 新人的坏习惯;-)

【讨论】:

【参考方案5】:

在 C++ 中,数组和向量总是包含固定大小的元素。字符串符合这个条件,因为你的字符串元素要么是指向存储在其他地方的空终止 c 字符串(char *)的指针,要么是普通的 std::string 对象。

std::string 对象的大小是恒定的,实际的字符串数据分配在其他地方(小字符串优化除外,但那是另一回事了)。

vector<string> a;
a.resize( 2 ); // allocate memory for 2 strings of any length.

vector<char *> b;
b.resize( 2 ); // allocate memory for 2 string pointers.

vector<char> c; // one string. Should use std::string instead.
c.resize( 2 ); // allocate memory for 2 characters (including or not the terminator).

请注意,std::vector 的 reserve() 函数只是准备让向量增长。它主要用于优化目的。您可能想使用 resize()。

【讨论】:

以上是关于字符串类型数组的指针运算,C++如何处理这个?的主要内容,如果未能解决你的问题,请参考以下文章

我该如何处理这个 C++ Multimap 问题?

复制控制函数中如何处理 C++ 数组成员?

Javascript 数值比较运算符究竟是如何处理字符串的?

Web Api 如何处理这个查询字符串?

数组是指针? [重复]

java.lang.NullPointerException - 如何处理空指针异常