簡體   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