我最近对指针感到好奇,而且我不明白为什么以下内容不起作用。
我的想法是创建一个变量,说出它的地址(十进制),要求用户将其输入回来,并将其作为指向前一个变量的指针的地址。最后,两个变量应具有相同的值。
最后一个指针应该指向错误的内存地址,因为它存在段错误,但是当我打印指针的地址时,它们是相同的!
#include <iostream>
int main() {
int temp = 0;
printf("Temporary integer addr 0x%x (dec %d)\n", &temp, &temp);
int input = -1;
printf("Give me an address to read (in dec)\n");
std::cin >> input;
printf("You chose the number %d (hex 0x%x)\n", input, input);
int* intPtr = (int*)input;
int* tempPtr = &temp;
if (intPtr == tempPtr) {
printf("It works, they are equal!\n");
} else {
printf("Expected: 0x%x got 0x%x\n", tempPtr, intPtr);
printf("Expected value: 0x%d got 0x%d", temp, *intPtr); // segfaults
}
return 0;
}
这是控制台输出
Main function addr 0xb0ddf7d0 (dec -1327630384)
Temporary integer addr 0xb0ddf7c8 (dec -1327630392)
Give me an address to read (in dec)
-1327630392
You chose the number -1327630392 (hex 0xb0ddf7c8)
Expected: 0xb0ddf7c8 got 0xb0ddf7c8
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
这有什么问题?如何创建一个指向用户输入地址的指针? 我在g ++(GCC)8.2.1 20181127上编译了它
答案 0 :(得分:8)
您的程序具有未定义的行为。首先,格式说明符%x
将使printf
期望使用unsigned int
类型的参数。但是,您正在向其传递类型为int*
的参数。您想使用%p
进行打印。最有可能的是,您正在64位计算机上工作,这意味着地址将为64位宽。 int
几乎肯定不会足够大以表示所有可能的地址。虽然将一种类型的参数传递给将解释该参数值的函数作为错误类型通常是未定义的行为,但实际上在实践中最有可能发生的情况是printf
只会打印较低的值指针值的两位解释为unsigned int
。然后,让您的用户类型返回实际上仅是您的实际地址的下半部分,然后将其转换回指针,然后访问该内存位置,几乎可以肯定,该地址将不是类型为{的对象的有效地址。 {1}}。那是您再次获得未定义行为的地方(幸运的是,这一次在segfaul中表现出来)。
如果您想要一个可以表示指针值的整数,请使用例如std::uintptr_t
。而且,只是不要在C ++中使用C样式强制转换。它们在那里是为了向后兼容C代码。 C样式转换没有优势,但有许多劣势(有关更多信息,请参见例如this或this或this或this问题)。另外,int
的类型也不安全,请不要使用printf
。您的问题再次证明了这一点(有关更多信息,请参见here)。如果改用printf
,则指针将自动正确打印。通常,std::cout
希望您注意确保实际传递的参数类型与格式字符串中指定的类型相匹配。如果您犯任何错误,最终将导致未定义的行为。另一方面,printf
将做正确的事或无法编译。最后,我只是束手无策,但请注意,看到std::cout
被用作输入之后,std::cin
被用作输入,这真的是多么的奇怪……
答案 1 :(得分:2)
int
不会在64位体系结构上存储指针。通常,您需要long
(在LP64架构上;保证long long
至少在任何地方至少64位宽),或者可移植地定义了intptr_t
或uintptr_t
typedef stdint.h
/ cstdint
(如果有)。
如果您需要一个比int
大的类型,并且使用int
,则地址将被截断。
这对我有用:
#include <iostream>
#include <inttypes.h>
#include <stdint.h>
int main() {
void* mainPtr = (void*) &main;
printf("Main function addr 0x%" PRIxPTR " (" PRIdPTR " %ld)\n", (uintptr_t)&mainPtr, (uintptr_t)&mainPtr);
int temp = 0;
printf("Temporary integer addr 0x%" PRIxPTR " (dec %" PRIdPTR ")\n", (uintptr_t)&temp, (uintptr_t)&temp);
uintptr_t input = -1;
printf("Give me an address to read (in dec)\n");
std::cin >> input;
printf("You chose the number %" PRIdPTR " (hex 0x%" PRIxPTR ")\n", input, input);
int* intPtr = (int*)input;
int* tempPtr = &temp;
if (intPtr == tempPtr) {
printf("It works, they are equal!\n");
} else {
printf("Expected: 0x%" PRIxPTR " got 0x%" PRIdPTR "\n", (uintptr_t)tempPtr, (uintptr_t)intPtr);
printf("Expected value: 0x%d got 0x%d", temp, *intPtr); // segfaults
}
return 0;
}
请注意,打印这些特殊typedefs
的便携式方法是
PRIxPTR
和在int inttypes.h
/ cinttypes
中定义的类似宏,如果要使用stdio,则依赖于字符串文字串联(C ++的std::cout <<
应该以较少的忙碌打印它们)。 / p>