C++ 指向(定义了指针数组)字符串的指针数组:这些字符串是否按顺序存储在内存中?
我想知道当使用/通过指向字符串的指针数组定义字符串时,字符串是如何存储在内存中的 例如:C++ 指向(定义了指针数组)字符串的指针数组:这些字符串是否按顺序存储在内存中?,c++,c,arrays,string,pointers,C++,C,Arrays,String,Pointers,我想知道当使用/通过指向字符串的指针数组定义字符串时,字符串是如何存储在内存中的 例如: char *pa[] = { "Hello World!", "foo","bar","huhu","Let´s talk about that" }; 是字符串还是更好:它们的字符顺序存储在内存中,一个接一个 例如,在本例中: 第二个字符串foo(即f)的第一个字符字节直接存储在第一个字符串Hello World!的\0-Null字符后面的字节中 或 字符串是否在内存中分开存储?例如: char *pa
char *pa[] = { "Hello World!", "foo","bar","huhu","Let´s talk about that" };
是字符串还是更好:它们的字符顺序存储在内存中,一个接一个
例如,在本例中:
第二个字符串foo(即f)的第一个字符字节直接存储在第一个字符串Hello World!的\0-Null字符后面的字节中
或
字符串是否在内存中分开存储?例如:
char *pa[] = { "Hello World!", "foo","bar","huhu","Let´s talk about that" };
\第一个字符串的0-空字符Hello World!-第二个字符串foo的-f字符之间的字节序列
或
存储是否依赖于环境、编译器、平台等,一次直接顺序存储,一次不连续存储
此外,第二个字符串foo的第一个字符f.e.是否也会直接存储在第一个字符串Hello World!的\0-字符之后!,这意味着它们是按顺序存储的,并且在第二个字符串foo的\0-字符和第三个字符串栏的第一个字符之间,即b是与字符串组非附属字节之间的间隔,取决于编译器、平台等
问题是C和C++,因为我和两者都工作。如果这两种语言之间的答案不同,请说明哪种语言是焦点
希望你能理解我的意思。非常感谢您的回答。不,您不能假设任何事情。它们是否存储在连续内存中由实现定义 如果你真的想让字符串变成那样,试试看
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 };
不,你不能假设任何事情。它们是否存储在连续内存中由实现定义 如果你真的想让字符串变成那样,试试看
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" };
编译器可能只存储字符串测试的一个副本,并从pa[0]和pa[1]指向它。事实上,我只是用两个现代编译器进行了尝试,他们两个都做到了
理论上,对于一个真正聪明的编译器来说,只存储字符串并进行更多的测试是可能的,并且将pa[0]和pa[1]指向字符串的中间
我想你是出于好奇才问这个问题的,但是如果你想写一些代码,这些代码在某种程度上依赖于内存中字符串常量的顺序,那么最直接、最简单的答案就是:不要这样做。此外,如果你有
char *pa[] = { "testing", "testing", "more testing" };
编译器可能只存储字符串测试的一个副本,并从pa[0]和pa[1]指向它。事实上,我只是用两个现代编译器进行了尝试,他们两个都做到了
理论上,对于一个真正聪明的编译器来说,只存储字符串并进行更多的测试是可能的,并且将pa[0]和pa[1]指向字符串的中间
我想你是出于好奇才这么问的,但是如果你想编写某种程度上依赖于内存中字符串常量顺序的代码,那么直接而简单的答案是:不要这样做。Steve Summit回答了什么,另外:如果存储了多个字符串,它们可以是任意顺序的,或者彼此相距很远
此外,使用>、>=等将指针与这些字符串进行比较是未定义的行为。例如,您可以检查p1是否为测试,p2是否为测试,p2是否为p1+8,这将在没有任何保证的情况下产生0或1,但不检查p2>=p1+8 Steve Summit的回答,另外:如果存储了多个字符串,它们可以是任意顺序,也可以彼此相距很远
此外,使用>、>=等将指针与这些字符串进行比较是未定义的行为。例如,您可以检查p1是否为测试,p2是否为测试,p2是否为p1+8,这将在没有任何保证的情况下产生0或1,但不检查p2>=p1+8 正如其他人提到的,内存布局是由实现定义的 扩展和使用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;
}
正如其他人提到的,内存布局是由实现定义的 扩展和使用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;
}
它们不一定是顺序的,编译器有自由决定存储是否依赖于环境、编译器、平台等。是的。正是这样。它们不一定是顺序的,编译器有自由决定它,即使如此,存储也取决于情况、编译器、平台等。是的。正是这样。如果存储多个字符串,它们可以是任意顺序,或者彼此相距很远。如果存储多个字符串,它们可以是任意顺序,或者彼此相距很远。或者char*pa[]={base,base+6,base+10}@pmg“@Steve Summit”这是一个非常聪明的选择。不知道这是可能的。我有两个问题
那就是:1。这种技术也只能在符合C89的编译器上使用吗?或者这是属于较新标准的技术?2.如果字符串是常量,我是否应该像你们两个一样声明指向字符串的指针。是的,该技术适用于C89甚至更早版本以来的所有C实现。2.const char*是一种防御射击自己脚的方法;您可以自由地将文本复制到适当的可变数组:char base[]=hello\0foo\0bar;/*注意对“\0”的更改*/还要注意pa[N]等于&pa[N-1]+strlen pa[N-1]+1。如果使用基本初始化器字符串,而不需要对下面的代码进行任何代码更改,则可以创建一个C++初始化器,或者Cch*Pa[] = {基,基+ 6,基+ 10 };@pmg“@Steve Summit”这是一个非常聪明的选择。不知道这是可能的。我有两个问题:1。这种技术也只能在符合C89的编译器上使用吗?或者这是属于较新标准的技术?2.如果字符串是常量,我是否应该像你们两个一样声明指向字符串的指针。是的,该技术适用于C89甚至更早版本以来的所有C实现。2.const char*是一种防御射击自己脚的方法;您可以自由地将文本复制到适当的可变数组:char base[]=hello\0foo\0bar;/*注意对“\0”的更改*/还要注意pa[N]等于&pa[N-1]+strlen pa[N-1]+1。可以使用C++初始化器创建一个C++初始化器,如果基本初始化器字符串不需要对下面的代码进行任何代码更改,那么它将能够进行修改。我仍在努力使自己完全理解算法的各个方面。谢谢你。哇,这是一个非常广泛的实现方法。我仍在努力使自己完全理解算法的各个方面。谢谢你。