代码一:按值传递/按引用传递
按值传递是指,在函数调用时,将参数的值复制一份传递给函数,函数中对参数值的修改不会影响到原始值
对于指针类型的参数,在按值传递的情况下,传递给函数的是指针变量的值(即指针变量所存储的地址),而不是指针所指向的内存地址。因此,当在函数中对指针变量赋值时,只是修改了指针变量的值,而不是指针所指向的内存地址。
void GetMemory1(char* p) {
p = (char*) malloc(100);
}
char* str = NULL;
GetMemory1(str);
p 指向的是一个新分配的内存块,但是这个操作不会影响到原始指针 str,因为传递给函数的是指针 str 的副本,即指针变量的值,而不是指针所指向的内存地址
修改方案1:采用引用作为函数参数
void GetMemory1(char*& p) {
p = (char*) malloc(100);
}
修改方案2:指向指针的指针
void GetMemory2(char** p) {
*p、p = (char*) malloc(100);
代码二:作用域/内存释放
char *GetMemory2(void){
char p[] = "hello world";
return p;
}
void Test2(void){
char *str = NULL;
str = GetMemory2();
printf(str);
}
p
是在函数栈中分配的一个局部变量,存储在”栈内存“中,当函数执行完毕后,p
所在的栈帧将被弹出,p
所占用的内存空间也将被释放。因此,返回指向局部变量的指针是一种非常危险的做法,因为在调用 GetMemory2
函数后,p
所占用的内存空间已经被释放,返回的指针将指向一块未知的内存区域,这样的指针是不可靠的,对其进行访问将导致未定义行为。
修改方案:malloc
以使用动态内存分配函数(如 malloc()
)来分配一块动态内存,以存储需要返回的字符串,这样返回的指针将指向一块合法的内存区域,避免了使用指向局部变量的指针的风险
char* GetMemory3(void) {
char* p = (char*) malloc(12);
strcpy(p, "hello world");
return p;
}
void Test3(void) {
char* str = NULL;
str = GetMemory3();
printf("%s", str);
free(str); // 释放动态分配的内存
}
使用 malloc()
函数分配了一块 12 字节大小的内存,将字符串 "hello world" 复制到该内存中,并返回内存块的首地址。在 Test3
函数中,使用指针变量 str
来接收返回的指针,并在使用完毕后使用 free()
函数释放已分配的内存
代码三:free/内存泄漏
void GetMemory3(char** p, int num)
{
*p = (char*)malloc(num);
}
void Test3(void)
{
char* str = NULL;
GetMemory3(&str, 100);
strcpy(str, "hello");
printf(str);
}
修改方案:在text3中加入
free(str);
代码四:野指针
void Test4(void){
char *str = (char*2)malloc(100);
strcpy(str,"hello");
free(str);
if(str != NULL) {
strcpy(str,"world");cout << str << endl;
}
}
在调用 free
函数释放内存之后,str
指针变成了野指针,即指向已经释放的内存块的指针。即使 str
不为 NULL
,它也指向已经释放的内存块,因此在 strcpy
函数中将会访问非法的内存地址,同样会导致未定义行为。