当返回指向本地数组的指针时,为啥它总是相同的值?

Posted

技术标签:

【中文标题】当返回指向本地数组的指针时,为啥它总是相同的值?【英文标题】:When returning a pointer to a local array why is it always the same value?当返回指向本地数组的指针时,为什么它总是相同的值? 【发布时间】:2010-04-07 22:50:08 【问题描述】:

我正在为一个班级项目编写一个简单的数据包嗅探器。有一段时间,我遇到了一个数据包的来源和目的地似乎相同的问题。例如,以太网帧的源和目标将始终是相同的 MAC 地址。我定制了ether_ntoa(char *),因为Windows 似乎没有像Linux 那样的ethernet.h。代码sn-p如下:

char *ether_ntoa(u_char etheraddr[ETHER_ADDR_LEN])

    int i, j;
    char eout[32];

    for(i = 0, j = 0; i < 5; i++)
    
        eout[j++] = etheraddr[i] >> 4;
        eout[j++] = etheraddr[i] & 0xF;
        eout[j++] = ':';
    
    eout[j++] = etheraddr[i] >> 4;
    eout[j++] = etheraddr[i] & 0xF;
    eout[j++] = '\0';
    for(i = 0; i < 17; i++)
    
        if(eout[i] < 10)
            eout[i] += 0x30;
        else if(eout[i] < 16)
            eout[i] += 0x57;
    
    return(eout);

我通过使用malloc() 让编译器分配内存(即我使用char * eout; eout = (char *) malloc (32); 而不是char eout[32])解决了这个问题。但是,我认为当在编译时调整 char 数组的大小时,编译器会分配不同的内存位置。这是不正确的吗?

【问题讨论】:

你能澄清一下你面临的问题吗 听起来像是内存泄漏。更好的设计是让调用者分配一个缓冲区,它将连同缓冲区的大小一起传递给您的自定义函数。 【参考方案1】:

正如其他人指出的那样,您不能返回指向具有自动存储持续时间的对象的指针 - 当eout 超出范围时,它不再存在。 GCC 实际上会警告您:

ether_ntoa.c: In function ‘ether_ntoa’:
ether_ntoa.c:26: warning: function returns address of local variable

达到预期结果的常用方法是让调用者负责分配目的地。例如:

int ether_ntoa(unsigned char etheraddr[ETHER_ADDR_LEN], char *dest, size_t len)

    return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x",
        (unsigned)etheraddr[0],
        (unsigned)etheraddr[1],
        (unsigned)etheraddr[2],
        (unsigned)etheraddr[3],
        (unsigned)etheraddr[4],
        (unsigned)etheraddr[5]);

(另请注意,您的手动编码转换例程可以替换为简单的snprintf() 调用)。你可以这样称呼它:

char eout[32];
ether_ntoa(etheraddr, eout, sizeof eout);
/* Converted address is now in eout */

Linux 上的ether_ntoa() 函数使用不同的方法——它将函数中的缓冲区声明为static。如果你这样做了,那么你的eout 将在程序的生命周期内存在,所以你可以返回一个指向它的指针。缺点是只有一个eout——每次调用ether_ntoa,都会覆盖之前的。

【讨论】:

【参考方案2】:

前一种方式的问题是概念上不正确 您无法返回指向局部变量的指针,bc 局部变量存在于堆栈中 你有两种方法 1)通过参数传递缓冲区(eout)及其大小,然后将其填充到函数内部 2)在函数内部分配缓冲区(eout),让调用者有责任在缓冲区完成后解除分配。 问候

【讨论】:

【参考方案3】:

您的问题是,当您在函数内声明 char eout[32] 时,分配给该数组的内存在堆栈上。在你的函数返回后,堆栈帧被弹出,之前分配给数组的内存地址可以重新分配给其他堆栈变量。正如您自己发现的那样,修复它的正确方法是 malloc() 数组的空间,以便在函数返回后它仍然存在。

【讨论】:

【参考方案4】:

请记住在完成后free()您的数组,这样您就不会发生内存泄漏。如果您使用的是 C++,则可以使用 boost::shared_array 代替,这样您就不必手动释放内存。 http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_array.htm

【讨论】:

以上是关于当返回指向本地数组的指针时,为啥它总是相同的值?的主要内容,如果未能解决你的问题,请参考以下文章

为啥函数返回的值总是 null 或 undefined?

当我们有常规数组时,为啥我们需要指向数组的指针?

当函数返回时,指向超出范围的对象的 C++ 指针 - 为啥会这样?

pyUSB read() 总是返回相同的值

定义了一个常数组,为啥能用指针改变数组元素的值?

C语言基础:指针相关概念(指针的算术运算 指针数组指向指针的指针 传递指针给函数 从函数返回指针 )为啥C 语言不支持在调用函数时返回局部变量的地址?