如何知道指针是指向动态还是静态分配的内存

Posted

技术标签:

【中文标题】如何知道指针是指向动态还是静态分配的内存【英文标题】:How to know pointer is pointing to dynamically or static allocated memory 【发布时间】:2015-08-20 11:04:50 【问题描述】:

有没有办法知道指针是指向动态分配的内存还是静态分配的内存?

数组作为函数指针传递

void func (int* p)

  if( p )
  
    cout << p[0] << p[1] ;
   ...
   // func has a responsibility to deallocate what p is pointing
  


int main()

  int a[] = 10, 20, 30, 50;
  func(a);
  ...
  return 0;

如果解除分配的所有权转移给 func. func p 如何知道 'p' 是指向动态分配的内存还是静态分配的内存?

【问题讨论】:

你不可能知道这个。 请选择C和C++之一。这两种是不同的语言。 是什么让您认为“func 有责任释放 p 指向的内容”? 如果你想转移所有权,你可以使用智能指针。 是的。在你的函数中注释掉你传递了一个动态分配的数组! 【参考方案1】:

你不能知道这一点。这是根据您的功能定义的。更喜欢使用智能指针,否则您必须在函数文档中明确说明它会接管您传递的对象或数组的所有权。

【讨论】:

【参考方案2】:

没有可移植的方法来确定指针是指向动态分配的内存还是静态分配的内存。通过仔细检查指针是否指向您在程序中加载的任何二进制库和共享库的数据或 bss 段之一,可能可以推断出此信息。即便如此,静态分配内存和动态分配内存之间的界限仍然很模糊:您认为共享库中的内存是稍后加载的动态还是静态的?

【讨论】:

【参考方案3】:

首先,调用者有责任使用带有合适参数的函数,而编码人员有责任明确说明该函数会尝试释放作为参数传递的指针。

其次,让一些算法函数管理内存并不是一个好习惯。主要原因是您可能希望在输入的子集上使用它。例如,如果您计算一个数组的总和,您可能希望能够计算从索引 3 开始的子数组的总和。

管理内存是调用者的工作,而不是你的。只是不要将任何解除分配放在执行其他操作的函数中。

反正你可以检测地址是否在栈上,见1 但是请注意,不在堆栈上并不意味着它是在堆上分配的,它可能指向一些静态数据,例如字符串文字。

【讨论】:

【参考方案4】:

你说不出来。

您应该在分配内存的“相同位置”释放内存。从广义上讲,这意味着如果函数的调用者分配了内存,那么调用者应该释放它。同样,如果你提供一个函数来分配内存,那么提供另一个函数来释放它。

有些人喜欢在函数中分配内存,并让调用者负责释放它。但这可能会导致问题,特别是如果函数是单独编译给调用者的;例如在 dll 或共享对象中。

您的建议是:删除在调用者中分配的函数中的内存是最糟糕的。 不要这样做

【讨论】:

【参考方案5】:

不仅你不能真正知道它,你甚至无法判断一个指针是否有效。

int* x = 0xDEADBEEF;

显然,大多数情况下指针甚至都没有指向有效的内存地址。

但并非全部丢失。你可以做各种各样的技巧来实现这个目标,至少是部分的。 其中一些包括:

    创建一个内存池并强制从那里分配任何动态的东西。然后,通过简单的指针算法,您可以找出内存地址是否存在 重载全局newdelete。除非您的某些类重载 newdelete 运算符,否则您可以捕获大部分动态分配。如果您使用的是malloc,这将不起作用。 如果您在 windows 上,并且您是 winapi 专家,您可以尝试挂钩 HeapAlloc,从而跟踪一些内存地址。

【讨论】:

【参考方案6】:
//***************************************************************//
//******************  try something like this  ******************//
//***************************************************************//

#include <stdlib.h>
#include <stdio.h>

// define one of these
// define LINUX
#define MACOS
// #define WINDOWS

#if defined LINUX || defined WINDOWS
#include <malloc.h>
#endif
#ifdef MACOS
#include <malloc/malloc.h>
#endif


// prototypes
int     freeable(void *ptr);
void    safe_free(void *ptr, const char *function, int line);


inline int freeable(void *ptr)

    size_t    sz;
#ifdef MACOS
    sz = malloc_size(ptr);
#endif
#ifdef LINUX
    sz = malloc_usable_size(ptr);
#endif
#ifdef WINDOWS
    sz = _msize(ptr);
#endif

    // fprintf(stderr, "freeable bytes = %ld\n", sz);
    if (sz)
        return(TRUE);

    return(FALSE);



void    safe_free(void *ptr, const char *function, int line)

    if (freeable(ptr) == FALSE) 
        if (ptr == NULL)
            fprintf(stderr, "%s(): Attempting to free NULL object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);
        else
            fprintf(stderr, "%s(): Attempting to free unallocated, statically allocated, or previously freed object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);
        return;
    

    free(ptr);

    fprintf(stderr, "%s(): Successfully freed object [called from function %s(), line %d]\n\n", __FUNCTION__, function, line);

    return;



int main(int argc, char *argv[])

    void    *ptr;
    size_t  sz;

    ptr = NULL;
    fprintf(stderr, "\nfree NULL ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) "string";
    fprintf(stderr, "free static string:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) 0x0123456789BCDEF;
    fprintf(stderr, "free unallocated ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    ptr = (void *) malloc(10);
    fprintf(stderr, "free allocated ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    fprintf(stderr, "free previously freed ptr:\n");
    safe_free(ptr, __FUNCTION__, __LINE__);

    return(0);

【讨论】:

这并不总是有效。 safe_free((int*)malloc(1024)-1) 为我崩溃:gcc.godbolt.org/z/j35fvcdhj

以上是关于如何知道指针是指向动态还是静态分配的内存的主要内容,如果未能解决你的问题,请参考以下文章

动态链表和静态链表

静态链表和动态链表的区别

智能指针和动态内存

12354

如何分配动态静态多维数组

C语言试题189之编写一个程序,按照下图中的样子创建数据结构,最后三个对象都是动态分配的结构。第一个对象则可能是一个静态的指向结构的指针