两个指针的地址是一样的
#include<stdio.h> #include<string.h> int main() { char * p = "abc"; char * p1 = "abc"; printf("%d %d", p, p1); }
当我打印这两个指针的值时,它正在打印相同的地址。 为什么?
是否将具有相同内容的两个不同的string文字放置在相同的内存位置或不同的内存位置是依赖于实现的。
您应该始终将p
和p1
作为两个不同的指针(即使它们具有相同的内容),因为它们可能指向相同的地址,也可能不指向相同的地址。 您不应该依赖编译器优化。
C11标准,6.4.5,string文字,语义
没有说明这些数组是否是不同的,只要它们的元素具有适当的值。 如果程序试图修改这样一个数组,行为是不确定的。
打印格式必须是%p
:
printf("%p %p", (void*)p, (void*)p1);
看到这个答案为什么。
你的编译器似乎很聪明,检测到这两个文字是相同的。 而文字是不变的编译器决定不存储他们两次。
似乎值得一提的是,这并不一定需要如此。 请看蓝月亮 对此的回答 。
顺便说一句: printf()
语句应该看起来像这样
printf("%p %p", (void *) p, (void *) p1);
因为"%p"
应该被用来打印指针值,并且它被定义为void *
types的指针。 * 1
另外我会说代码没有return
声明,但C标准似乎正在被改变的过程中。 其他人可能会好好澄清这一点。
* 1:铸造void *
不是char *
指针所必须的,而是所有其他types的指针。
你的编译器做了一些叫做“string池”的东西。 你指定你想要两个指针,都指向相同的string文字 – 所以它只做了一个文字的副本。
从技术上说:应该抱怨你没有使指针“const”
const char* p = "abc";
这可能是因为您正在使用Visual Studio,或者您正在使用不带-Wall的GCC。
如果您明确希望将它们存储在内存中,请尝试:
char s1[] = "abc"; char s2[] = "abc";
在这里你明确指出你需要两个c-string字符数组而不是两个指向字符的指针。
警告:string池是一个编译器/优化器function,而不是该语言的一个方面。 由于不同环境下的这些不同的编译器会根据优化级别,编译器标志以及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
从p
后面开始3个字节,所以GCC已经看到了def
的常见后缀(包括\0
终止符),并对你所显示的进行了类似的优化。
(这是一个答案,因为评论太长了。)
代码中的string文字存储在代码的只读数据段中。 当你写下像“abc”这样的string时,它实际上会返回一个“const char *”,如果你有所有的编译器警告,就会告诉你在这个时候正在进行转换。 你不能因为你在这个问题中指出的原因而改变这些string。
当你创build一个string文字(“abc”)时,它被保存到一个包含string文本的内存中,如果你引用相同的string文字,它将被重用,因此两个指向相同位置的指针, abc“string文字被存储。
我以前学过这个,所以我可能没有很清楚的解释,对不起。
这实际上取决于你使用的编译器 。
在我使用TC ++ 3.5的系统中, 为两个指针打印两个不同的值,即两个不同的地址 。
你的编译器被devise为将检查存储器中是否存在任何值,并且根据它的存在,如果引用相同的值,它将重新分配或使用与先前存储的值相同的引用 。
所以不要太想它,因为它取决于编译器parsing代码的方式。
就这样…
因为string“abc”本身就是内存中的一个地址。 当你再次写入“abc”时,它会存储相同的地址
这是编译器优化,但忘记了可移植性的优化。 有时编译代码比实际代码更具可读性。
你正在使用string文字,
当编译器捕获两个相同的string文字时,
它给出相同的内存位置,因此它显示相同的指针位置。