请教char *s和char s=new char[n]的差别,用delete为何会出错

zxphxh 2016-12-06 12:37:51

void f1(char *s)
{
if (s)
{
printf("s=%s\n",s);
delete[] s;
}
}

int _tmain(int argc, _TCHAR* argv[])
{
printf("start .... \n\n");
char *s1 = new char[10];
memset(s1, '\0', 10);
memmove(s1, "123456789", 9);

printf("start f1(s1)\n");
f1(s1);
printf("end f1(s1)\n\n");

char *s2 = "ABCDEFG";
printf("start f1(s2)\n");
f1(s2);
printf("enf f1(s2)\n");
}


编译后执行如下

并出现异常,定位异常:
void __CRTDECL operator delete(void* const block) noexcept
{
#ifdef _DEBUG
_free_dbg(block, _UNKNOWN_BLOCK);
#else
free(block);
#endif
}


我的本意是写一个函数f(char *s),其中有一个语句if(s) delete []s; 发现如果char *s=new char[10];这样定义调用f(s),ok。但是如果定义char *s="123456789";调用f(s),出现异常。请问如何处理这种情况?
...全文
680 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
ooolinux 2016-12-06
  • 打赏
  • 举报
回复
引用 15 楼 u010165006 的回复:
《深入理解C指针》
推荐
ooolinux 2016-12-06
  • 打赏
  • 举报
回复
《深入理解C指针》
zxphxh 2016-12-06
  • 打赏
  • 举报
回复
引用 12 楼 jianwen0529 的回复:
[quote=引用 4 楼 zxphxh 的回复:] 可能我的基本意思没有表达清楚: 我想写个这样的函数: char *f(char *s) { if(s==NULL) return NULL; // 此处对s进行处理,得到一个新的字符串t // .......... // 用s返回新的字符串 // 如果s占用内存,则需要释放空间 if(s) delete [] s; s=t; return t; } 调用函数f(s)时参数s有两种可能情况: (1)char *s="123456789"; (2)char *s=new char[10]; 请问如何处理这两种情况?
那你为什么要在函数内释放? 基本的原则就是谁申请的内存就谁负责释放(某些特别需求除外) 你在函数调用处new了字符串,那就调用之后 不再使用的时候 delete 你这种情况,我建议两种办法: 1. 使用string std::string f(std::string s) 2. 参数返回结果 void f(char *s, char *result) // result作为返回结果[/quote] 明白!非常感谢!
paschen 版主 2016-12-06
  • 打赏
  • 举报
回复
只有是你自己用new申请得到的地址才应拿去delete,否则自然是会出错 char *s1 = new char[10]; 这里s1是指向动态分配的空间,这个空间是在堆上,用完应该delete char *s2 = "ABCDEFG"; 这里s2是指向常量区的字符串,用完不需要delete
幻夢之葉 2016-12-06
  • 打赏
  • 举报
回复
引用 4 楼 zxphxh 的回复:
可能我的基本意思没有表达清楚: 我想写个这样的函数: char *f(char *s) { if(s==NULL) return NULL; // 此处对s进行处理,得到一个新的字符串t // .......... // 用s返回新的字符串 // 如果s占用内存,则需要释放空间 if(s) delete [] s; s=t; return t; } 调用函数f(s)时参数s有两种可能情况: (1)char *s="123456789"; (2)char *s=new char[10]; 请问如何处理这两种情况?
那你为什么要在函数内释放? 基本的原则就是谁申请的内存就谁负责释放(某些特别需求除外) 你在函数调用处new了字符串,那就调用之后 不再使用的时候 delete 你这种情况,我建议两种办法: 1. 使用string std::string f(std::string s) 2. 参数返回结果 void f(char *s, char *result) // result作为返回结果
jiht594 2016-12-06
  • 打赏
  • 举报
回复
引用 10 楼 jiht594 的回复:
[quote=引用 6 楼 zxphxh 的回复:] [quote=引用 5 楼 sunyongliang118 的回复:] char *s2 = "ABCDEFG"; 这个是在常量存储区内存中存放的,释放不需要你手动执行什么的。
我调用函数f(s)时,有以下情况: 此时s可能是new分配的,也可能是char *s="ABCD";也就是通过调用f(s)之后,s的值已变化了。在函数f(s)中需要不需要释放s原来的空间(如果是new分配的)?[/quote] 谁申请谁释放。不是f函数申请的,f不负责释放。 [/quote] 删掉f中的 delete语句
jiht594 2016-12-06
  • 打赏
  • 举报
回复
引用 6 楼 zxphxh 的回复:
[quote=引用 5 楼 sunyongliang118 的回复:] char *s2 = "ABCDEFG"; 这个是在常量存储区内存中存放的,释放不需要你手动执行什么的。
我调用函数f(s)时,有以下情况: 此时s可能是new分配的,也可能是char *s="ABCD";也就是通过调用f(s)之后,s的值已变化了。在函数f(s)中需要不需要释放s原来的空间(如果是new分配的)?[/quote] 谁申请谁释放。不是f函数申请的,f不负责释放。
小灸舞 2016-12-06
  • 打赏
  • 举报
回复
堆内存的使用原则是“谁分配谁释放”
在一个函数里new而在另一个函数里delete,这种做法要尽量避免,因为它很难确保delete和new的对应关系。

判断指针指向的内容是在栈上还是在堆上,恐怕没有什么可靠的办法。
如果一定要判断,用以下的方法多半可以蒙对,但是也不能保证100%正确:

由于堆地址和栈地址一般差别比较大(比如linux下,堆地址位于0x08048000之后,堆变量地址一般为0x0804XXXX;而栈地址从0xc0000000开始向下增长,栈变量地址一般为0xbfffxxxx),所以可以利用这点来粗略进行区分,具体代码如下(假定地址为32位):
SK_AJIE 2016-12-06
  • 打赏
  • 举报
回复
引用 4 楼 zxphxh 的回复:
可能我的基本意思没有表达清楚:
我想写个这样的函数:
char *f(char *s)
{
if(s==NULL) return NULL;
// 此处对s进行处理,得到一个新的字符串t
// ..........
// 用s返回新的字符串
// 如果s占用内存,则需要释放空间
if(s) delete [] s;
s=t;
return t;
}

调用函数f(s)时参数s有两种可能情况:
(1)char *s="123456789";
(2)char *s=new char[10];
请问如何处理这两种情况?


这个参数s在函数内是不能判断是否是动态内存(不晓得判断地址是否可行,毕竟栈和堆的内存是分开的,估计可行度很低),需要经过外层去处理(记住:谁申请内存,谁释放),若是想要释放内存,再传进去一个标志位表明动态申请需要释放,需要进行内存释放,另外记住:函数内部的变量是临时的,想要永久就动态申请
赵4老师 2016-12-06
  • 打赏
  • 举报
回复
无new,无对应delete
zxphxh 2016-12-06
  • 打赏
  • 举报
回复
引用 5 楼 sunyongliang118 的回复:
char *s2 = "ABCDEFG"; 这个是在常量存储区内存中存放的,释放不需要你手动执行什么的。
我调用函数f(s)时,有以下情况: 此时s可能是new分配的,也可能是char *s="ABCD";也就是通过调用f(s)之后,s的值已变化了。在函数f(s)中需要不需要释放s原来的空间(如果是new分配的)?
振翅高飞 2016-12-06
  • 打赏
  • 举报
回复
char *s2 = "ABCDEFG"; 这个是在常量存储区内存中存放的,释放不需要你手动执行什么的。
zxphxh 2016-12-06
  • 打赏
  • 举报
回复
可能我的基本意思没有表达清楚: 我想写个这样的函数: char *f(char *s) { if(s==NULL) return NULL; // 此处对s进行处理,得到一个新的字符串t // .......... // 用s返回新的字符串 // 如果s占用内存,则需要释放空间 if(s) delete [] s; s=t; return t; } 调用函数f(s)时参数s有两种可能情况: (1)char *s="123456789"; (2)char *s=new char[10]; 请问如何处理这两种情况?
幻夢之葉 2016-12-06
  • 打赏
  • 举报
回复
引用 2 楼 jianwen0529 的回复:
char *s="123456789" 不是对内的数据通过new分配 是不应该 delete 的 在外面分配就在外面维护数据吧,例如这样子修改
void f1(char *s)
{
    if (s)
    {
        printf("s=%s\n", s);
    }
}

int main(int argc, char* argv[])
{
    printf("start .... \n\n");
    char *s1 = new char[10];
    memset(s1, '\0', 10);
    memmove(s1, "123456789", 9);

    printf("start f1(s1)\n");
    f1(s1);
    printf("end f1(s1)\n\n");

    delete [] s1; //不再需要的时候销毁掉
    s1 = NULL; // 赋值为NULL,防止后续使用到垂悬指针

    char *s2 = "ABCDEFG";
    printf("start f1(s2)\n");
    f1(s2);
    printf("enf f1(s2)\n");
}
修正下第一句话 char *s="123456789" 不是对内的数据通过new分配 是不应该 delete 的 修正后 char *s="123456789" 不是在堆中通过 new 分配的,所以不应该进行 delete 你可以搜索下 “C++ 堆和栈” 和 “C++ new delete”
幻夢之葉 2016-12-06
  • 打赏
  • 举报
回复
char *s="123456789" 不是对内的数据通过new分配 是不应该 delete 的 在外面分配就在外面维护数据吧,例如这样子修改
void f1(char *s)
{
    if (s)
    {
        printf("s=%s\n", s);
    }
}

int main(int argc, char* argv[])
{
    printf("start .... \n\n");
    char *s1 = new char[10];
    memset(s1, '\0', 10);
    memmove(s1, "123456789", 9);

    printf("start f1(s1)\n");
    f1(s1);
    printf("end f1(s1)\n\n");

    delete [] s1; //不再需要的时候销毁掉
    s1 = NULL; // 赋值为NULL,防止后续使用到垂悬指针

    char *s2 = "ABCDEFG";
    printf("start f1(s2)\n");
    f1(s2);
    printf("enf f1(s2)\n");
}
振翅高飞 2016-12-06
  • 打赏
  • 举报
回复
char s=new char[n] 这个代表什么?char是占一个字节的内存,楼主new创建一个含有n个字节的内存段??? 创建内存段,返回的就是内存首地址,首地址肯定是指针形式的。 char值本身也是个数值,但是这个值能等同于开辟的内存首地址吗?

64,637

社区成员

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

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