在C++程序开发中,查看指针指向的内存地址是调试和验证内存操作的常见需求,比如确认动态内存分配是否成功、排查野指针问题等。直接输出指针变量往往无法得到符合预期的地址格式,而将指针强转为void类型后输出是最常用的解决方案。

C++输出指针地址的基础方式
普通的指针变量如果直接传入输出流,对于字符指针等特定类型,输出流会将其当作字符串起始地址来处理,输出对应字符串内容而非地址。即使是其他类型的指针,不同编译器下输出的格式也可能存在差异,因此直接输出指针变量的方式并不通用。
我们可以通过一个简单的示例来验证直接输出指针的问题:
#include <iostream>
using namespace std;
int main() {
int a = 10;
int* p = &a;
// 直接输出指针变量
cout << "直接输出int指针: " << p << endl;
char str[] = "test";
char* cp = str;
// 直接输出字符指针
cout << "直接输出char指针: " << cp << endl;
return 0;
}
上述代码中,int指针的输出可能显示为十六进制地址,但char指针会直接输出字符串test,无法得到地址值,这种方式显然不符合输出地址的需求。
强转void类型打印内存地址的方法
将指针强转为void类型是C++中输出通用内存地址的标准做法,因为void类型的指针没有特定类型指向,输出流会将其统一按照内存地址的格式进行输出,不受指针原本指向类型的影响。
强转的语法非常简单,只需要在输出时使用(void*)进行强制类型转换即可,示例如下:
#include <iostream>
using namespace std;
int main() {
int num = 20;
int* intPtr = #
double pi = 3.14;
double* doublePtr = π
// 强转为void*输出地址
cout << "int变量地址: " << (void*)intPtr << endl;
cout << "double变量地址: " << (void*)doublePtr << endl;
// 动态分配内存的指针地址
int* dynamicPtr = new int(30);
cout << "动态分配int地址: " << (void*)dynamicPtr << endl;
delete dynamicPtr;
return 0;
}
上述代码中,不管是int类型的指针、double类型的指针还是动态内存分配的指针,强转为void*之后都可以正确输出对应的内存地址,格式通常为十六进制,不同编译器可能前缀有0x标识。
不同输出格式的控制
默认情况下,输出的地址是十六进制小写格式,如果需要调整输出格式,可以配合iomanip头文件中的格式控制函数来实现。
常见的格式控制示例如下:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int val = 10;
int* ptr = &val;
// 默认十六进制小写
cout << "默认格式: " << (void*)ptr << endl;
// 十六进制大写
cout << "大写十六进制: " << uppercase << (void*)ptr << endl;
// 恢复小写格式
cout << nouppercase;
// 显示十六进制前缀0x
cout << "带前缀格式: " << showbase << (void*)ptr << endl;
// 输出十进制地址值
cout << "十进制格式: " << dec << (unsigned long long)(void*)ptr << endl;
return 0;
}
注意事项
- 强转void*仅适用于输出场景,不要将强转后的void*指针用于其他内存操作,避免类型不匹配导致未定义行为。
- 不同平台下指针的大小可能不同,32位系统指针为4字节,64位系统指针为8字节,输出的地址长度会对应不同。
- 不要对空指针进行强转输出,空指针的值为0或者nullptr,输出结果没有实际参考意义。
- 如果使用printf函数输出地址,对应的格式符应该是%p,同样需要传入void*类型的指针,示例如下:
#include <cstdio>
int main() {
int x = 5;
int* px = &x;
// printf输出地址的用法
printf("printf输出地址: %pn", (void*)px);
return 0;
}