Действительно ли печатается адрес строки в C

У меня есть 2 вопроса... (Я изучаю C, и это могут быть глупые вопросы. Извинения)

  • Как Как объявить строки в C и в большинстве книг, они всегда говорят, объявляя строку, даже если вы выделяете память, говоря

    char p2[] = "String";
    

Мой вопрос: есть ли смысл объявлять строку?

помещаются в область только для чтения, а затем копируются в массив. Действительно ли в C печатать адрес строки, как это?

printf("%p\n", &"Hello There"); // I tried, it prints some address

и делая это

printf("%p\n", &"Hello There");
printf("%p\n", &"Hello There");

он печатает тот же адрес. что такое чувство, он должен печатать другой адрес. Здесь компилятор делает некоторую оптимизацию?

Ответы

Ответ 1

C стандарт, §6.4.5 Строковые литералы, говорит:

Неизвестно, являются ли эти массивы различными, если их элементы имеют соответствующие значения.

Таким образом, два строковых литерала с одним и тем же содержимым могут обозначать один и тот же массив, и печать их адресов дает одно и то же значение указателя дважды. Это решение для компилятора и компоновщика; когда я компилирую следующую программу как два отдельных модуля...

// main.c
#include <stdio.h>

extern void print_foo_addr(void);

int main()
{
    printf("%p\n", &"foo");
    print_foo_addr();
    return 0;
}

и

// printfoo.c
#include <stdio.h>

void print_foo_addr()
{
    printf("%p\n", &"foo");
}

... тогда я получаю два разных значения указателя (GCC 4.7.3 в Linux), но когда я поместил определение для print_foo_addr в main.c, я получаю одно и то же значение дважды. Так что да, это оптимизация, которая явно разрешена стандартом, но GCC по крайней мере выполняет эту оптимизацию только для каждого модуля.

Ответ 2

Это специально разрешено стандартом C.

6.4.5p5-6:

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

Неизвестно, являются ли эти массивы различными, если их элементы имеют соответствующие значения.

Ответ 3

"Hello There" - строковый литерал, и он будет доступен в строковой таблице (причина получения того же адреса для "Hello There" в printf).

Когда вы делаете

char p2[] = "String";

будет выделена память, а "String" будет скопирована на вновь созданную память. Но

char * p3 = "String"; будет указывать на раздел только для чтения. i.e строка таблицы.

В этом случае, если вы печатаете p3 и &"String" будет одинаковым.

Если вы печатаете p2 и &"String", будет напечатан другой адрес. Поскольку p2 - адрес стека.

Ответ 4

Литеральные строки помещаются в специальный раздел, который следует читать только. Кроме того, если вы используете один и тот же строковый литерал в нескольких местах, тогда компилятор обычно может создавать только один экземпляр этой строки. Вот почему вы видите тот же адрес в этом примере:

printf("%p\n", &"Hello There");
printf("%p\n", &"Hello There");

Однако вы не можете полагаться на это, потому что это оптимизация компилятора, которая может или не может произойти.