繁体   English   中英

指向(定义了指针数组)字符串的指针数组:字符串是否按顺序存储在 memory 中?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM