错误方案
char* testfunc1(){
char chp[10] = "cpp";
return chp;
}
int main(int argc, const char * argv[]) {
// insert code here...
char *p = testfunc1();
printf("%s\n",p);
p = nullptr;
return 0;
}
在以上代码中,在函数中创建一个字符数组,直接将字符数组的名称作为char类型的指针作为返回值向外传递。
这种做法是错误的,编译器会弹出警告:Address of stack memory associated with local variable 'chp' returned。意思是将在栈上的局部变量返回了,这在c++中是不推荐的。
问题的原因在于,testfunc1中的字符数组chp属于局部变量,位于内存的栈区,因此指针*p指向的是栈里的局部变量。当函数运行结束后,该块内存是很有可能被其他代码使用,那个时候内存里存放的是什么内容就不是我们需要的了。
最后的结果是,*p一开始指向的确实是字符串数组chp所在的内存,当函数执行完,*p依旧指向那块内存,但是这块内存还是不是字符数组chp,就不一定了。
结论:c++函数不应该返回一个指向栈内变量的指针。
解决的思路也很简单,函数返回一个指向非栈内变量的指针就好了,除了栈,我们其实可以人为将变量放在其他地方。
方案一:返回指向堆内变量的指针
//将字符串放在堆里
char* testfunc2(){
char *p = new char(10*sizeof(char));
strcpy(p, "hello!");
return p;
}
int main(int argc, const char * argv[]) {
// insert code here...
char *p = testfunc2();
printf("%s\n",p);
delete p;
p = nullptr;
return 0;
}
函数testfunc2中在堆区开辟一块内存,并向其中存放字符串。这样该字符串的生命周期就与函数无关,即便函数执行完毕,*p照样指向的是该字符串。
需要注意的是堆里的数据需要手动回收,不然会造成内存泄漏。
方案二:返回指向静态变量的指针
//将字符串放在静态变量区
char* testfunc3(){
static char p[100];
strcpy(p, "hello!");
return p;
}
int main(int argc, const char * argv[]) {
// insert code here...
char *p = testfunc2();
printf("%s\n",p);
p = nullptr;
return 0;
}
函数testfunc3创建一个静态的字符串数组,该数组存放在静态变量区,生命周期与函数也无关,也能够解决问题。
需要注意的是,静态变量区的变量是唯一的,函数testfunc3被多个地方调用时用的是同一个变量,最好令该变量为常量。
方案三:返回指向全局变量的指针
//将字符串放在全局变量区
char pglobal[100];
char *testfunc4(char* s){
strcpy(s, "hello!");
return s;
}
int main(int argc, const char * argv[]) {
// insert code here...
char* p = testfunc4(pglobal);
printf("%s\n",p);
p = nullptr;
return 0;
}
使用全局变量,就更暴力了!