Адреса двух указателей одинаковы
#include<stdio.h>
#include<string.h>
int main()
{
char * p = "abc";
char * p1 = "abc";
printf("%d %d", p, p1);
}
когда я печатать значения двух указателей, он печатает один и тот же адрес. Зачем?
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 " снова он хранит тот же адрес