Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 指向(定义了指针数组)字符串的指针数组:这些字符串是否按顺序存储在内存中?_C++_C_Arrays_String_Pointers - Fatal编程技术网

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++初始化器,如果基本初始化器字符串不需要对下面的代码进行任何代码更改,那么它将能够进行修改。我仍在努力使自己完全理解算法的各个方面。谢谢你。哇,这是一个非常广泛的实现方法。我仍在努力使自己完全理解算法的各个方面。谢谢你。