1、如果函数的参数是一个指针,不要用该指针去申请动态内存
using namespace std;
void GetMemory( char * p, int num)
{
p=(char *)malloc(sizeof(char) * num);
}
void Test( void )
{
char *str=NULL;
GetMemory(str,100); //str仍然为NULL
strcpy(str,"hello");//运行错误
}
int main()
{
Test();
return 0;
}
上面的代码在编译无错误的,可是在执行时,出现了错误。调试发现,str仍然为NULL。str并没有指向GetMemory()所申请的内存,在函数被调用时,编译器会为被调用函数的参数产生一个副本p,如果函数体内修改p的内容,那么导致参数p的内容作相应的修改,这就是指针可以作为输出参数的原因。在本例中,str的副本p重新申请了一块内存,只是把p所指的内存地址改变了,但是str丝毫未变。所以GetMemory并不能返回任何东西。所以str仍然为NULL,导致程序运行错误。事实上,每执行一次GetMemory(),就会造成内存的泄露,这是因为申请的内存得不到有效释放,结果是内存一直被独占,最终造成内存泄漏。
下用图示说明:
如果要用指针参数申请内存,使用指向指针的指针可以完成此功能:
using namespace std;
void GetMemory( char ** p, int num)
{
*p=(char *)malloc(sizeof(char) * num);
}
void Test( void )
{
char *str=NULL;
GetMemory(&str,100); //注意参数是&str,而不是str
strcpy(str,"hello");cout<<*str<<endl;
cout<<str<<endl;cout<<&str<<endl;
free(str);
}
int main()
{
Test();
return 0;
}
分别打印*str,str,和&str可以发现,结果分别是h,hello,0012fef0;【&str和*p的地址是等同的】
2、函数返回值传递动态内存
using namespace std;
char * GetMemory( int num)
{
char *p=(char *)malloc(sizeof(char) * num);
return p;
}
void Test( void )
{
char *str=NULL;
str=GetMemory(100);
strcpy(str,"hello");
cout<<str<<endl;
free(str);
}
int main()
{
Test();
return 0;
}
函数的返回值传递动态内存,内存不能为栈内存,因为该内存再函数结束时自动消亡。
using namespace std;
char * GetMemory( void )
{
char *p="hello world";
//书上说,这句话编译器应该提出警告,但是vc6没有
return p;
}
void Test( void )
{
char *str=NULL;
str=GetMemory(); //书上说str的内容是垃圾
cout<<str<<endl;
}
int main()
{
Test();
return 0;
}
3、字符数组与字符指针
char *strA()
{
char str[]="hello world";
return str;
}
//这个str里存的地址是函数strA栈帧里"hello world"的首地址。函数调用完成,栈帧恢复到调用strA之前的状态,临时空间被充值,堆栈"回缩",strA栈帧不在属于应该访问的范围。这段程序可以正确输出结果,却违背了函数的栈帧机制。(栈帧也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构
从逻辑上讲,栈帧就是一个函数执行的环境:函数参数、函数的局部变量、函数执行完后返回到哪里 … 。
实现上有硬件方式和软件方式(有些体系不支持硬件栈)
缓冲区溢出攻击主要是利用栈帧的构成机制,利用疏忽的程序破坏栈帧从而使程序转移到攻击者期望或设定的代码上。)
//如果想获得正确的函数,可以改成:
const char* strA()
{
char *str="hello world";
return str;
}
//char c[]="hello world";是分配了一个局部数组
//char *c="hello world";是分配了一个全局数组
//全局区域的值是不能进行修改的,如
char *c="hello world";
*c='t';//false
char c[]="hello world";
c[0]='t';//ok
//若想修改,也可以这样做
const char* strA()
{
static char str[]="hello world";
return str;
}//通过static开辟一段静态存储空间