我希望函数根据不同的参数值返回不同的类型,但是如何打印void指针指向的变量
在main()
?
#include <iostream>
#include <string>
using namespace std;
void * func(int a)
{
if (a == 1)
{
int param = 5;
return ¶m;
}
else if (a == 2)
{
double param = 5.5;
return ¶m;
}
else if (a == 3)
{
string param = "hello";
return ¶m;
}
else
{
return nullptr;
}
}
int main()
{
void *ptr = func(3);//
cout << ptr;// print the address not the value
getchar();
return 0;
}
答案 0 :(得分:3)
param
是一个自动变量。您不能将其退回并在其范围之外使用它。
param
仅存在于func
内,如果您将其返回,则结果为未定义行为。
要解决此问题,您可以:
param
。执行此操作后,您可以安全地返回param
地址,但是当您不需要时,您必须记得将其释放。以下是对代码的更正
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
void * func(int a)
{
if (a == 1)
{
int *param = new int(5);
return param;
}
else if (a == 2)
{
double *param = new double(5.5);
return param;
}
else if (a == 3)
{
char *param = new char[50];
strcpy(param, "test");
return param;
}
return nullptr;
}
int main()
{
int *ptr = (int*)func(1);
cout << *ptr << std::endl; // print the int value
delete ptr;
double *ptr2 = (double*)func(2);
cout << *ptr2 << std::endl; // print the double value
delete ptr2;
char *ptr3 = (char*)func(3);
cout << ptr3 << std::endl; // print the string
delete[] ptr3;
getchar();
return 0;
}
答案 1 :(得分:3)
如果你可以使用C ++ 17,你可以使用std::variant
而不是void *
轻松解决它:
#include<iostream>
#include<string>
#include<variant>
std::variant<int, double, std::string, void *> func(int a) {
if (a == 1) {
int param = 5;
return param;
} else if (a == 2) {
double param = 5.5;
return param;
} else if (a == 3) {
std::string param = "hello";
return param;
} else {
return nullptr;
}
}
int main() {
std::visit([](auto v) {
std::cout << v << std::endl;
}, func(3));
}
在wandbox上查看并运行。
在C ++ 11/14中,您可以使用tagged union执行相同的操作。基本的想法是,您返回的内容包含足够的信息,以便调用者可以离开它原始类型。
存在替代品。
例如,您可以擦除类型并返回包含原始(已擦除)变量和指向函数的指针的对,该函数填充了函数模板的实例。后者将能够从void *
重建原始变量,因为它知道它的类型
好吧,几乎是一个很棒的机器,你可以避免使用带标记的联合或std::variant
(在一天结束时或多或少是类型安全版本的标记联合)。
答案 2 :(得分:0)
您返回的是本地变量的地址。当函数返回时,该变量超出范围,这意味着它正在使用的内存可以重用。试图取消引用该指针(即访问它指向的内存)会调用undefined behavior。
即使你返回一个有效的指针,你的函数返回void *
的事实意味着关于指针指向的任何类型信息都会丢失。您可以从该地址开始打印一个或多个字节,但它不会告诉您原始类型是什么。
答案 3 :(得分:0)
即使该指针有效,您也根本无法获得足够的信息来强制转换为某些东西,然后将其打印出来。 没有关于其大小的信息,没有其内部布局的信息。所以,你只是不能打印void *指向的内容,除非你在某处手工编写了一些信息,并强制static_cast为已知类型。 例如:
double x = 1.2;
int y = 5;
int f(void** output) {
static int x;
if ( x++ ) {
*output = &x;
return 1;
}
*output = &y;
return 2;
}
...
void* out;
int r = f(&out);
if ( r == 1 ) cout << *(static_cast<double*>(out));
else if ( r == 2 ) cout << *(static_cast<int*>(out));