Как хранится массив строкового литерала в C? - PullRequest
0 голосов
/ 19 апреля 2020

Взгляните на следующий код и вывод:

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]);
}

output:

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 на некоторые строки в коде? Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 19 апреля 2020

Чтобы поэкспериментировать, я просто изменил ваш пример, чтобы отобразить адреса строк.
Вы можете видеть, что мы не можем делать никаких предположений о том, как каждая из этих строк хранится относительно друг друга.

В моей системе (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;
}
1 голос
/ 19 апреля 2020

Как хранится массив строкового литерала в C?

Я думаю, вы ошибаетесь в том, что строковые литералы, на которые указывают указатели char в массиве words[] впоследствии сохраняются в памяти, что не соответствует действительности. В непрерывной памяти хранятся только указатели char.

Кроме того, вы, похоже, смешиваете адреса памяти, такие как 0x764f73a1, с размером объектов или массивов в байтах.


Таким образом, ваш первый for l oop:

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)

Это условие не имеет смысла. Вы сравниваете размер массива указателя с символом words с адресом, который указатель wp хранит в качестве значения минус адрес первого строкового литерала.

3.

 wp += strlen(wp) + 1

Это не работает, поскольку строковые литералы не должны храниться непрерывно в памяти.


В противоположность этому, второй for l oop:

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

является правильным, поскольку он использует только указатели char в массиве words и выполняет итерацию столько раз, сколько указатели находятся в words.

...