指针返回和范围

时间:2016-07-12 18:50:08

标签: c++ pointers memory scope

返回在函数内声明的指针被认为是不好的做法?例如:

int* foo(void)
{
    int * ret_val = 1234;

    return ret_val;
}

我相信你应该使用:

static int * ret_val = 1234;

但话又说回来,将范围内的内存返回到你的范围内是不是仍然被认为是不好的做法?

6 个答案:

答案 0 :(得分:2)

返回指针不是问题,只要它指向仍在范围内的内存,例如动态分配的内存,全局数据或仍然存在于调用堆栈中的局部变量。

上面代码的问题在于,您在取消引用指针时没有为其指定任何内容。这样:*ret_val = 1234;将值1234分配给ret_val指向的地址,但ret_val未分配任何内容。

如果另一方面你这样做了:

int* foo(void)
{
    int * ret_val;

    ret_val = malloc(sizeof(int));
    *ret_val = 1234;

    return ret_val;
}

这很好,因为你正在返回一个指向动态分配内存的指针。

答案 1 :(得分:2)

罪魁祸首是

*ret_val = 1234;

应用了未初始化的指针。

  

我相信你会想要使用:

static int* ret_val;

不,要修复你可以使用

int* foo() {
     static int_val = 1234;
     return &int_val;
}

但如果那是你真正想要的东西,这是有争议的。该函数的所有调用者将共享int_val的相同实例。

答案 2 :(得分:0)

如果你返回一个指向局部变量的指针,这是一个非常糟糕的做法,因为你将有一个悬空指针

<input id="file" type="file">
<div id="binary"></div>

但有时它可能有用:

int* foo(void)
{
    int a = 1337;
    return &a; //Don't do this!
}

无论如何,你应该避免返回指针,因此不存在内存泄漏的风险。

答案 3 :(得分:0)

除了使用ret_val而不分配它之外,从函数返回指针是公平的做法,尽管需要特别小心:

  • 不要返回指向局部变量的指针,因为它会在函数退出时被销毁,如果取消引用则会导致未定义的行为
  • 如果函数分配内存,则调用函数负责确保指针在不再需要时被释放,以避免内存泄漏
  • 如果函数以指针的形式处理数组,则需要知道数组的大小以避免未定义的行为,通常作为额外的size参数或全局常量

答案 4 :(得分:0)

你应该考虑:

int *foo() {
        int *ret_val = new int(1234);
        return ret_val;
}

代替(错误代码):

int* foo(void)
{
    int * ret_val;

    *ret_val = 1234;

    return ret_val; // dangling pointer!
}

否则你会有悬空指针(第二个例子)。 显然不要忘记释放内存。 您还应该考虑使用智能指针: https://en.wikipedia.org/wiki/Smart_pointer

当你指定C ++和C语言时,上面的代码是C ++(operator new),请参考(例如)@Mattia F.回答ANSI C。

答案 5 :(得分:0)

指针就像一个快捷方式或超链接。仅创建快捷方式不会安装程序。创建超链接并不会神奇地设置整个网站。

与指针相同:int*是指向整数的指针。它本身不是整数。因此,在尝试跟踪指针之前,必须确保指针指向有意义的内容。

这样做的一种方法是创建一个整数并设置指向它的指针:

int* ret_val = new int;

这将创建一个整数(new运算符),然后将ret_val指针设置为指向它。

通过new创建的对象一直存在,直到您通过delete或应用程序结束时明确销毁它们为止。因此,如果函数中有new int,即使函数结束,也可以安全地访问它。

如果您将指针ret_val设置为不是一个新的整数,而是设置为一个现有的局部变量,即

,那么危险,可能引起您的关注的是什么?
int myInteger;
int* ret_val = &myInteger;

在这种情况下,ret_val指向局部变量myInteger,当包含声明的范围结束时,该变量将被销毁。你最终得到一个悬垂的指针,引用不存在的东西(想想:破坏的超链接)。使用这样的指针可能会导致未定义的行为。它可能会使程序崩溃,但它也可以默默地接受它,修改内存中的一些随机空间。

所以,形状的函数:

int* foo(void)
{
    int* ret_val = new int;
    *ret_val = 1234;
    return ret_val;
}

使用安全。它不一定是一个好习惯:这种函数的用户必须知道它创建了一个新的整数,稍后 - 在某个时刻 - 某人应该delete。这样做的功能通常以某种方式强调这种行为,例如通过它的名字。例如,allocateInt()清楚地表明它创建了以后应该删除的内容。相反,getInt()表明整数已经存在,并且没有创建任何新内容。