Адреса двух указателей одинаковы


#include<stdio.h>
#include<string.h>

int main()
{
  char * p = "abc";
  char * p1 = "abc";
  printf("%d %d", p, p1);
}

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

10 79

10 ответов:

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

вы всегда должны относиться к p и p1 как два разных указателя (даже если они имеют одинаковое содержимое), поскольку они могут указывать или не указывать на один и тот же адрес. Вы не должны полагаться на оптимизацию компилятора.

стандарт C11, 6.4.5, строковые литералы, семантика

не указано, являются ли эти массивы различными при условии их элементы имеют соответствующие значения. Если программа попытается измените такой массив, поведение не определено.


формат печати должен быть %p:

  printf("%p %p", (void*)p, (void*)p1);

посмотреть ответ почему.

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

кажется, стоит упомянуть, что это не обязательно должно быть так. Пожалуйста, смотрите Голубая Луна ' s ответ на это.


Кстати: The printf() заявление должно выглядеть так

printf("%p %p", (void *) p, (void *) p1);

как "%p" используется для выведите значения указателя, и он будет определен для указателя типа void * только.*1


также я бы сказал, что код пропускает return заявление, но стандарт C, похоже, находится в процессе изменения. Другие могли бы любезно разъяснить это.


*1: кастинг в void * вот не надо char * указатели, а указатели на все другие типы.

ваш компилятор сделал что-то под названием "объединение строк". Вы указали, что вам нужны два указателя, оба указывающие на один и тот же строковый литерал, поэтому он сделал только одну копию литерала.

технически: он должен был пожаловаться на вас за то, что вы не сделали указатели "const"

const char* p = "abc";

это, вероятно, потому, что вы используете Visual Studio или используете GCC без стены.

Если вы явно хотите, чтобы они были сохранены дважды в памяти, попробуйте:

char s1[] = "abc";
char s2[] = "abc";

здесь вы явно заявляете, что вам нужны два массива символов c-string, а не два указателя на символы.

предостережение: объединение строк-это функция компилятора / оптимизатора, а не аспект языка. Таким образом, разные компиляторы в разных средах будут производить разное поведение в зависимости от таких вещей, как уровень оптимизации, флаги компилятора и находятся ли строки в разных единицах компиляции.

как уже говорили другие, составитель столкнулся с тем, что они имеют одинаковое значение, и поэтому решает их в финальный исполняемый файл. Но это становится более причудливым: когда я компилирую следующее с gcc -O

#include<stdio.h>
#include<string.h>

int main()
{
  char * p = "abcdef";
  char * p1 = "def";
  printf("%d %d", p, p1);
}

печати 4195780 4195783 для меня. То есть, p1 запускает 3 байта после p, так GCC увидел общий суффикс def (включая Терминатор) и сделал аналогичную оптимизацию к тому, который вы показали.

(это ответ потому, что это слишком долго, чтобы быть комментарий.)

строковые литералы в коде хранятся в сегменте данных только для чтения кода. Когда вы записываете строковый литерал, такой как" abc", он фактически возвращает " const char*", и если бы у вас были все предупреждения компилятора на нем, вы бы сказали, что вы бросаете в этот момент. Вам не позволено изменять эти строки по той причине, которую вы указали в этом вопросе.

при создании строкового литерала ("abc") он сохраняется в памяти, которая содержит строковые литералы, а затем повторно используется, если вы ссылаетесь на один и тот же строковый литерал, таким образом, оба указателя указывают на одно и то же место, где хранится строковый литерал" abc".

Я узнал это некоторое время назад, так что я, возможно, не объяснил это очень ясно, извините.

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

в моей системе с TC++ 3.5 печати два разных значения двух указателей, т. е. два разных адреса.

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

Так что не думайте об этом слишком много, как это зависит от того, как компилятор парсит код.

ВОТ И ВСЕ...

потому что строка " abc " сама по себе адрес в памяти. когда вы пишете " abc " снова он хранит тот же адрес

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

вы используете строковый литерал,

когда компилятор поймать двух одинаковых строковых литералов,

Он дает такое же положение памяти, поэтому он показывает такое же расположение указателя./