【问题标题】:How is array of string literal in C stored?C中的字符串文字数组如何存储?
【发布时间】:2020-08-01 15:59:15
【问题描述】:

看看下面的代码和输出:

char *words[] = {"wehrmarcht", "collectorate", "hello", "hello","precorrection", "hello","wehrmarcht"};
char *wp;
cnode *np;
for(wp = *words; wp - *words < sizeof(words); wp += strlen(wp) + 1) {
    printf("wp -> %s\n", wp);
}
printf("==============================================\n");
for(int i = 0; i < sizeof(words) / sizeof(char *); i++) {
    printf("words[%d] -> %s\n", i,words[i]);
}

输出:

wp -> collectorate
wp -> precorrection
wp -> wp -> %s

wp -> ==============================================

==============================================
words[0] -> wehrmarcht
words[1] -> collectorate
words[2] -> hello
words[3] -> hello
words[4] -> precorrection
words[5] -> hello
words[6] -> wehrmarcht

Process finished with exit code 0

有人能解释一下是什么让 wp 指向代码中的某些字符串吗? 提前致谢。

【问题讨论】:

  • 您是否假设包含只读字符串文字的段与代码中的出现顺序有某种关联?
  • 当你的程序使用文字字符串(例如“...”)时,这些字符串是程序的一部分,它是常量初始化数据的区域(你不能修改它们),你访问这个区域,你的for about wp 从“wehrmarcht”的地址开始(所以你的输出不能是你给出的那个)然后在那个内存部分进行,当然这一切都取决于如何编译器/链接器放置数据并且行为未定义
  • 一些编译器可以选择共享/合并重复的字符串字面量,而"hello" 出现了三次,这真的会打乱常规序列的假设。
  • @WeatherVane 标记的答案证实了你的想法,这确实有道理。

标签: c string pointers memory string-literals


【解决方案1】:

为了进行实验,我只是将您的示例更改为 显示字符串的地址。
你可以看到我们不能对方式做出任何假设 这些字符串中的每一个都是相对于彼此存储的。

在我的系统(Linux 64 位)上,我获得:

$ ./prog_c
words[0] @ 0x5631c83b6080 -> wehrmarcht
words[1] @ 0x5631c83b60c0 -> collectorate
words[2] @ 0x5631c83b6100 -> hello
words[3] @ 0x5631c83b6100 -> hello
words[4] @ 0x5631c83b6140 -> precorrection
words[5] @ 0x5631c83b6100 -> hello
words[6] @ 0x5631c83b6080 -> wehrmarcht
/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <stdio.h>

int
main(void)
{
  const char *words[]={"wehrmarcht", "collectorate", "hello", "hello", "precorrection", "hello", "wehrmarcht"};
  const int count=(int)(sizeof(words)/sizeof(words[0]));
  for(int i=0; i<count; ++i)
  {
    printf("words[%d] @ %p -> %s\n", i, (void *)words[i], words[i]);
  }
  return 0;
}

【讨论】:

    【解决方案2】:

    C 中的字符串字面量数组是如何存储的?

    我认为您误解了,数组words[] 中的char 指针指向的字符串文字随后存储在内存中,事实并非如此。只有char 指针存储在连续内存中。

    此外,您似乎将0x764f73a1 之类的内存地址与以字节为单位的对象或数组的大小混合在一起。


    因此,您的第一个 for 循环:

    for(wp = *words; wp - *words < sizeof(words); wp += strlen(wp) + 1) {
        printf("wp -> %s\n", wp);
    }
    

    调用未定义的行为并且没有意义。

    1.

    wp = *words
    

    wp 由第一个字符串文字的地址分配。

    2.

     wp - *words < sizeof(words)
    

    这个条件没有意义。您将指向 char words 的指针数组的大小与指针 wp 保存的地址作为值减去第一个字符串文字的地址进行比较。

    3.

     wp += strlen(wp) + 1
    

    这不起作用,因为字符串文字不必连续存储在内存中。


    与此相反,第二个for 循环:

    for(int i = 0; i < sizeof(words) / sizeof(char *); i++) {
        printf("words[%d] -> %s\n", i,words[i]);
    }
    

    是正确的,因为它只使用数组words 中的char 指针,并且只迭代与words 中的指针一样多的次数。

    【讨论】:

    • 你是完全正确的。 ` 字符 **wp; for(wp = words; wp - words %s\n", *wp); }` 这个循环也可以工作。很抱歉我接受了另一个答案,因为打印的地址让我很清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-12
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多