字符* 文本消息[] 如何在内存中格式化?

How is char* textMessages[] formatted in memory?

本文关键字:内存 格式化 文本 消息 字符      更新时间:2023-10-16

众所周知,像int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}}这样的多数组是连续的,所以它与int array2[6] = { 0, 1, 2, 3, 4, 5 };完全相同

for (int *p = *array1, i = 0; i < 6; i++, p++)
{
std::cout << *p << std::endl;
}

0

1

阿拉伯数字

3

5

然后,我有这些代码:

char *textMessages[] = {
"Small text message",
"Slightly larger text message",
"A really large text message that ",
"is spread over multiple lines*"
};

我发现它的布局与 int[3][2] 不同:

  • 对于每个子消息,如"Small text message",每个 alpha 都是连续的,偏移量为1(sizeof(char( == 1(。
  • 然而,"Small text message"的最后一个元素——e"Slightly larger text message"的第一个元素——S在模因中是不连续的:

char *textMessages[] = {
"Small text message",
"Slightly larger text message",
"A really large text message that ",
"is spread over multiple lines*"
};
char *a = *(textMessages)+17, *b = *(textMessages + 1), *c = *(textMessages + 1) + 27, *d = *(textMessages + 2), *e = *(textMessages + 2) + 31, *f = *(textMessages + 3);
std::ptrdiff_t a_to_b = b - a, c_to_d = d - c, e_to_f = f - e;
printf("they(a b c d e f) are all messages's first or final element: %c %c %c %c %c %cn", *a, *b, *c, *d, *e, *f);
printf("nnaddress of element above: n%pn%pn%pn%pn%pn%pn", a, b, c, d, e, f);
printf("nnptrdiff of a to b, c to d and e to f: %d %d %dn", a_to_b, c_to_d, e_to_f);

they(a b c d e f) are all messages' first or final element: e S e A t i

address of element above:
002F8B41
002F8B44
002F8B5F
002F8B64
002F8B83
002F8B88

ptrdiff of a to b, c to d and e to f: 3 5 5

我的问题是:

  1. 3 5 5这里是什么意思?
  2. 为什么3 5 5,而不是5 5 5
  3. 这里的布局是什么?

编辑: 我不认为这个问题重复多维数组如何在内存中格式化?,因为我问的与那个问题的疑问不同,解决方案不应该是问题的答案。

如何在内存中格式化char* textMessages[]

就像其他一维数组一样。每个元素都存储在一个连续的内存位置。这些元素是指向char对象的指针。

其中每个指针都指向字符串文本的开头。字符串文本具有静态存储持续时间,其内存位置由实现定义。

这里的 3 5 5 是什么意思?

您已经在不指向同一数组的指针之间完成了指针减法(每个字符串文本都是一个单独的数组(。因此,程序的行为在技术上是未定义的。

在实践中,大多数时候,你得到的是内存中指向值的距离。由于这些数组的位置是实现定义的,因此这些值没有任何意义。

为什么是 3 5 5,而不是

5 5 5
  • 因为行为是未定义的
  • 因为这恰好是指针字符对象之间的距离。距离将取决于编译器选择存储字符串文本的位置。

您可以根据自己的观点选择任何一种解释。


附言。您正在将字符串文本转换为指向非常量字符的指针。自从标准化以来,此转换已被弃用C++并且自 C++11 年以来格式不正确。

.PPS。访问超出大小为 2 的array1[0]范围int *p = *array1(如在第一个代码片段中一样(在技术上具有未定义的行为。这同样适用于第二个*(textMessages + 2) + 31

字符串文字具有静态存储持续时间,这意味着它们在程序启动时在内存中分配,但不能保证它们彼此位于连续内存中,因为此时,程序甚至可能不知道它们在数组中。 当数组被构造时,这些字符串的地址被放置在连续内存中(当然,不是字符串本身(

附言 我在上面所说的"字符串"实际上意味着"字符串文字">

从语言律师的角度来看,这是:

int array1[3][2] = {{0, 1}, {2, 3}, {4, 5}};
for (int *p = *array1, i = 0; i < 6; i++, p++)
{
std::cout << *p << std::endl;
}

未按标准定义,因为array1是一个由 3 个大小为 2 的数组组成的数组。所以 0 和 1 是同一个数组,但不是 1 和 2,所以第一次递增指针是正确的,但第二次递增使它指向第一个数组(这是正确的(,所以取消引用它正式是 UB。

当然,任何当前和过去的实现都接受它。


但这是一种完全不同的动物:

char *textMessages[] = {
"Small text message",
"Slightly larger text message",
"A really large text message that ",
"is spread over multiple lines*"
};

这里textMessages是一个指针数组,而不是一个 2D 数组。但情况更糟。它是一个由 4 个指向字符串 litteral 的char *指针组成的数组,修改字符串 litteral 是未定义的行为。这意味着textMessages[0][0] = 'X';可能会使程序崩溃。

但是,一旦我们知道我们有一系列指向字符串 litteral 的指针,一切都变得清晰起来:编译器以它想要的方式将字符串 litteral 存储在内存中,并且只是提供了指向该内存的指针。因此,3,5,5 只是填充值,因为您的编译器已决定以这种方式存储文本垃圾。

3 5 5在这里没有任何意义,5 5 5.

char *textMessages[]是一个 char* 数组,它的元素是指针。它们(指针(在数组中是连续的。但这些指针的价值并没有那么相关。代码中的字符串可能存在于不同的位置。

我的编译器上的结果是:243 309 1861