如何打印void指针指向的变量

时间:2017-08-10 20:04:17

标签: c++ pointers

我希望函数根据不同的参数值返回不同的类型,但是如何打印void指针指向的变量 在main()

#include <iostream>
#include <string>
using namespace std;
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)
    {
    string param = "hello";
    return &param;
    }
    else
    {
    return nullptr;
    }
}
int main()
{

    void *ptr = func(3);//

    cout << ptr;// print the address not the value
    getchar();
    return 0;
 }     

4 个答案:

答案 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));