如何判断指针指向的区域是在堆上还是在栈上?

craigyang 2008-11-27 08:36:13
为了实现这样一个功能:
str1是一个字符串指针,指向的内容可以在栈上,比如
char* str1 = "abc";
也可以是在堆上,比如
char str1 = new char[5];
for(int i = 0; i<5; i++)
{ str1[i] = ......; }
另外一个字符串str2,现希望将str2拷贝到str1中,如果str1指向的内容在堆上,如下的函数就可以实现

void mystrcpy(char* &str1, const char* str2)
{
delete []str1;
int len = strlen(str2);
str1 = new char[len+1];
for(int i =0; i<len; i++)
str1[i] = str2[i];
str1[len] = '\0';
}

但是如果str1指向的内容在栈上,函数中的delete语句就会出错.
如何能够判断指针指向的内容是在栈上还是在堆上, 或者上面的功能可以用其他方法解决?
...全文
1356 11 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
WingForce 2008-11-29
  • 打赏
  • 举报
回复
windows下的利用ntdll.dll的导出函数NtCurrentTEB获得TIB,TIB中包含线程栈的起始地址这个方法判地址是否在栈上还是可行的。


#include <iostream>
#include <process.h>
#include <Windows.h>

typedef NT_TIB* (NTAPI *FuncGetTIB)();

bool is_address_on_stack(void* address)
{
HINSTANCE ntdll = LoadLibrary(_T("ntdll.dll"));
if (ntdll == NULL) {
return false;
}

FuncGetTIB gettib = (FuncGetTIB)GetProcAddress(ntdll, "NtCurrentTeb");
if (gettib == NULL){
return false;
}

NT_TIB* tib = gettib();
if (tib == NULL){
return false;
}

return address < tib->StackBase && address > tib->StackLimit;
}

int main()
{
int stackobject = 0;
static int globalobject = 1;

auto_ptr<int> heapaddr(new int(2));
int* stackaddr = &stackobject;
int* globaladdr = &globalobject;

cout << "address " << stackaddr << " "
<< (is_address_on_stack(stackaddr) ? "is on stack" : "is not on stack")
<< endl;

cout << "address " << heapaddr.get() << " "
<< (is_address_on_stack(heapaddr.get()) ? "is on stack" : "is not on stack")
<< endl;

cout << "address " << globaladdr << " "
<< (is_address_on_stack(globaladdr) ? "is on stack" : "is not on stack")
<< endl;

system("PAUSE");
return 0;
}


输出:
address 0012FF54 is on stack
address 003B9BF0 is not on stack
address 00419004 is not on stack



brookmill 2008-11-29
  • 打赏
  • 举报
回复
堆内存的使用原则是“谁分配谁释放”
在一个函数里new而在另一个函数里delete,这种做法要尽量避免,因为它很难确保delete和new的对应关系。

判断指针指向的内容是在栈上还是在堆上,恐怕没有什么可靠的办法。
如果一定要判断,用5楼的方法多半可以蒙对,但是也不能保证100%正确
BaihowFF 2008-11-27
  • 打赏
  • 举报
回复
char* str1 = "abc";
这样其实是不对的初始化方法...为了兼容C才这样做的...C++如果和C没有关系的话...这样的话是会非法的...
因为这样等于让指针在栈上...而指针的空间指向了静态区常量...所以删除不了啊...压根就不是动态的...

另外...所有用new或者malloc分配的空间都在堆上...但是指向空间的指针一般在栈上...
当然也可以用指针的指针将指针分配到堆上...额...绕口吧...多读一边...

为什么会内存泄露...因为栈上的指针没了...但是堆上的空间没清除..所以泄露了...
deerwin1986 2008-11-27
  • 打赏
  • 举报
回复
在WINDOWS里面NEW的时候会在那个字节前面会有NEW的字节数 可以尝试用指针看下之前的字节数值
p_zyh 2008-11-27
  • 打赏
  • 举报
回复
从函数实现来看str1实际上是用来返回值的,因此改成如下设计会更合适

const char* mystrcpy(const char* str2)
{
int len = strlen(str2);
char* str1 = new char[len+1];
for(int i =0; i <len; i++)
str1[i] = str2[i];
str1[len] = '\0';
return str1;
}

const char* newstr = mystrcpy(oldstr);


如果函数原型不能改,则去掉delete调用,并在文档中要求传入空指针

void mystrcpy(char* &str1, const char* str2)
{
int len = strlen(str2);
str1 = new char[len+1];
for(int i =0; i <len; i++)
str1[i] = str2[i];
str1[len] = '\0';
}

const char* newstr = NULL;
mystrcpy(newstr, oldstr);
kiffa 2008-11-27
  • 打赏
  • 举报
回复
需要注意的是常量和局部静态变量在linux下位于0x08048000之后,位于堆变量之前。所以像char *p = "haha";这里的p和堆变量地址很相近。

windows下不知道具体如何,但堆地址和栈地址也应该有比较大的差别吧。
kiffa 2008-11-27
  • 打赏
  • 举报
回复
首先推荐用别的方法解决你的问题。其次单纯对于区分堆变量和栈变量这个问题,可以试试这样:

由于堆地址和栈地址一般差别比较大(比如linux下,堆地址位于0x08048000之后,堆变量地址一般为0x0804XXXX;而栈地址从0xc0000000开始向下增长,栈变量地址一般为0xbfffxxxx),所以可以利用这点来粗略进行区分,具体代码如下(假定地址为32位):

bool IsInStack(char *p)
{
int i;
// 判断p和栈变量i的地址,看其高8位是否相等,若相等则p指向栈变量.
if ( ((unsigned)&i >> 24) == ((unsigned)p >> 24) )
return true;
return false;
}



jackzhhuang 2008-11-27
  • 打赏
  • 举报
回复
难说,应用程序的内存空间没有明显的分界线
lann64 2008-11-27
  • 打赏
  • 举报
回复
[Quote=引用楼主 craigyang 的帖子:]
为了实现这样一个功能:
str1是一个字符串指针,指向的内容可以在栈上,比如
char* str1 = "abc";
也可以是在堆上,比如
char str1 = new char[5];
for(int i = 0; i <5; i++)
{ str1[i] = ......; }
另外一个字符串str2,现希望将str2拷贝到str1中,如果str1指向的内容在堆上,如下的函数就可以实现

void mystrcpy(char* &str1, const char* str2)
{
delete []str1;
in…
[/Quote]
你应该自己把空间分配和释放封装起来,不用char*类型,而是用一个类class。
xhs_lh04 2008-11-27
  • 打赏
  • 举报
回复
貌似不能,堆跟栈地址上并没有明显的界定,代码里无法区分啊
就呆在云上 2008-11-27
  • 打赏
  • 举报
回复
但是如果str1指向的内容在栈上,函数中的delete语句就会出错.
如何能够判断指针指向的内容是在栈上还是在堆上, 或者上面的功能可以用其他方法解决?

呵呵
这个问题吗,貌似没有办法吧

65,184

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧