[英]Pointer array to (with pointer array defined) strings: Are the strings stored sequential in memory?
我想知道字符串是如何存储在 memory 中的,当使用/通过指向它们的指针数组定义它们时。
例如:
char *pa[] = { "Hello World!", "foo","bar","huhu","Let´s talk about that" };
字符串(或更好:它们的字符)是否按顺序存储在 memory 中,一个接一个?
例如,在这种情况下:
第二个字符串"foo"
的第一个字符字节f
直接存储在第一个字符串"Hello World!"
的\0
-Null 字符之后的字节内。 .
或者
存储在 memory 中的字符串是否分开存储?例如:
\0
- 第一个字符串"Hello World!"
的空字符 - 第二个字符串"foo"
的f
字符之间的字节序列?
或者
即便如此,存储是否取决于情况、编译器、平台等,并且一次是直接顺序的,一次不是?
是否还会发生,第二个字符串"foo"
的第一个字符f
直接存储在第一个字符串"Hello World!"
的\0
字符之后。 ,这意味着它们是按顺序存储的,并且在第二个字符串"foo"
的\0
字符和第三个字符串"bar"
的第一个字符之间,即b
是字符串组非附属字节的间隙,依赖于编译器、平台等?
问题是针对 C 和 C++ 的,因为我同时使用两者。 如果这两者之间的答案发生变化,请说明重点关注哪种语言。
希望你能明白,我的意思。 非常感谢您的任何回答。
不,你不能假设任何事情。 它们是否存储在连续的 memory 中由实现定义。
如果您真的希望字符串是那样的,请尝试
const char *base = "hello\0foo\0bar";
const char *hello = base;
const char *foo = base + 6; // hello + strlen(hello) + 1
const char *bar = base + 10; // foo + strlen(foo) + 1
或者,正如@SteveSummit 建议的那样
const char *pa[] = { base, base + 6, base + 10 };
此外,如果你有
char *pa[] = { "testing", "testing", "more testing" };
编译器可以只存储字符串"testing"
的一份副本,并从pa[0]
和pa[1]
指向它。 (事实上,我只是用两个现代编译器尝试过,它们都做到了。)
从理论上讲,一个非常聪明的编译器可以只存储字符串"more testing"
并让pa[0]
和pa[1]
指向它的中间。
我假设您是出于好奇而询问,但如果您有任何机会考虑编写代码,该代码以某种方式依赖于 memory 中字符串常量的顺序,那么直接而简单的答案是:不要。
Steve Summit 的回答是:如果存储了多个字符串,它们可以按任何顺序排列,也可以彼此相距很远。
此外,使用“>”、“>=”等比较指向这些字符串的指针是未定义的行为。 因此,您可以检查例如 p1 = "testing"、p2 = "testing"、p2 == p1 + 8 是否(在没有任何保证的情况下会产生 0 或 1),但不能检查 p2 >= p1 + 8 是否。
正如其他人提到的,memory 布局是实现定义的。
扩展pmg的方法并做 C 你可以这样做:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
char ** create_pointer_array_pointing_to_sequential_data(char ** ppa)
{
char ** result = NULL;
if (NULL == ppa)
{
errno = EINVAL;
}
else
{
size_t s = 0;
size_t l = 0;
while (NULL != ppa[l])
{
s += strlen(ppa[l]);
++l;
}
result = malloc((l + 1) * sizeof *result);
if (NULL != result)
{
result[0] = malloc(s + l + 1);
if (NULL != result[0])
{
for (size_t i = 0; i < l; ++i)
{
strcpy(result[i], ppa[i]);
result[i + 1] = result[i] + strlen(result[i]) + 1;
}
result[l] = NULL;
}
else
{
int errno_save = errno;
free(result);
errno = errno_save;
result = NULL;
}
}
}
return result;
}
像这样使用它:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char ** create_pointer_array_pointing_to_sequential_data(char ** ppa);
int main(void)
{
char ** pa = create_pointer_array_pointing_to_sequential_data(
(char*[]){"Hello World!",
"foo",
"bar",
"huhu",
"Let's talk about that",
NULL}
);
if (NULL == pa)
{
perror("create_pointer_array_pointing_to_sequential_data() failed");
exit(EXIT_FAILURE);
}
for (size_t i = 0; NULL != pa[i]; ++i)
{
printf("pa[%zu] starts at %p and ends at %p: %s\n",
i, (void*) pa[i], (void*)(pa[i] + strlen(pa[i])), pa[i]);
}
}
并得到:
pa[0] starts at 0x6000003f0 and ends at 0x6000003fc: Hello World!
pa[1] starts at 0x6000003fd and ends at 0x600000400: foo
pa[2] starts at 0x600000401 and ends at 0x600000404: bar
pa[3] starts at 0x600000405 and ends at 0x600000409: huhu
pa[4] starts at 0x60000040a and ends at 0x600000420: Let's talk about that
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.