程序解析
- 以下程序中,主函数能否成功申请到内存空间?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getmemory(char *p){
p = (char *)malloc(100);
strcpy (p, "hello world");
}
int main()
{
char *str = NULL;
getmemory(str);
printf("%s\n", str);
free(str);
return 0;
}
主函数不能成功申请到内存空间。
-
在getmemory函数中,通过malloc函数申请了100字节的内存空间,并将其地址赋给p。然而,在主函数中调用getmemory函数时,传递的是str的值,而不是str的地址。因此,getmemory函数中的p只是一个局部变量,对其进行赋值并不会改变主函数中str的值。因此,在主函数中打印str时,仍然是NULL,而不是"hello world"。
-
同时,在主函数中使用free函数释放str所指向的内存空间是不正确的,因为str的值为NULL,没有成功申请到内存空间。
-
改正有如下俩种方法:
①传递的是二重指针,即str的指针
void getmemory(char **p)
{
*p = (char *)malloc(100);
strcpy(*p, "hello world");
}
②传递的是指针别名,即str的别名,C++中
void getmemory(char * &p)
{
p = (char *)malloc(100);
strcpy(p, "hello world");
}
-
在第一个修改中,getmemory函数的参数是一个二重指针,即指向指针的指针。通过传递str的地址给getmemory函数,可以在函数内部修改str的值。在getmemory函数中,使用p来访问str指向的地址,并将malloc函数分配的内存空间的地址赋值给p,然后使用strcpy函数将字符串"hello world"复制到这个内存空间中。这样,主函数中的str指向的内存空间就被成功分配,并且包含了字符串"hello world"。因此,在主函数中打印str时,会输出"hello world"。
-
在第二个修改中,getmemory函数的参数是指针别名,即传递str的别名给getmemory函数。在C++中支持指针别名,而在C语言中不支持。通过传递str的别名给getmemory函数,可以在函数内部直接修改str的值。在getmemory函数中,直接将malloc函数分配的内存空间的地址赋值给p,然后使用strcpy函数将字符串"hello world"复制到这个内存空间中。这样,主函数中的str指向的内存空间就被成功分配,并且包含了字符串"hello world"。因此,在主函数中打印str时,会输出"hello world"。
需要注意的是,第一个修改是在C语言中使用的,而第二个修改是在C++中使用的。在C语言中,不能直接传递指针的别名,只能通过二重指针的方式来修改指针的值。而在C++中,可以直接传递指针的别名来修改指针的值。
- 解释以下内容: 请问运行下面的Test()函数会有什么样的后果?
char *GetMemory(void){
char p[] = "hello world";
return p;
}
void Test(void) {
char *str = NULL;
str = GetMemory();
printf("%s\n", str);
}
-
运行上述代码会导致未定义的行为。原因是在函数GetMemory()中,定义了一个局部变量p,它是一个指向字符数组的指针。然后将p作为返回值返回给Test()函数中的str指针。但是,由于p是在GetMemory()函数的栈帧中分配的,当GetMemory()函数返回后,p所指向的内存将被释放,因此str指针将指向一个无效的内存地址。
-
在Test()函数中,当尝试打印str指针指向的字符串时,由于str指向的内存已经被释放,将会导致未定义的行为,可能会输出乱码或者程序崩溃。
-
为了解决这个问题,可以通过动态分配内存来存储字符串,并在使用完后手动释放内存。例如,可以使用malloc()函数来分配内存,并在使用完后使用free()函数释放内存。
请写出更改后的代码,并加以解释:
#include <stdio.h>
#include <stdlib.h>
char *GetMemory(void)
{
char *p = (char *)malloc(sizeof(char) * 12);
if (p != NULL) {
strcpy(p, "hello world");
}
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
if (str != NULL) {
printf("%s\n", str);
free(str);
}
}
以下是更改后的代码:
#include <stdio.h>
#include <stdlib.h>
char *GetMemory(void)
{
char *p = (char *)malloc(sizeof(char) * 12);
if (p != NULL) {
strcpy(p, "hello world");
}
return p;
}
void Test(void)
{
char *str = NULL;
str = GetMemory();
if (str != NULL) {
printf("%s\n", str);
free(str);
}
}
-
在修改后的代码中,我们使用了动态内存分配函数
malloc()来分配足够的内存来存储字符串"hello world"。通过sizeof(char) * 12来分配12个字节的内存,包括字符串中的每个字符和一个空字符'\0'。 -
在
GetMemory()函数中,我们首先检查malloc()是否成功分配内存。如果成功,则使用strcpy()函数将字符串"hello world"复制到分配的内存中。然后将指向该内存的指针p返回给Test()函数。 -
在
Test()函数中,我们首先将str指针初始化为NULL,然后调用GetMemory()函数来获取分配的内存。接下来,我们检查str是否为NULL,以确保内存分配成功。如果成功,则打印str指向的字符串,并使用free()函数释放分配的内存。
通过这种方式,我们确保了在使用完动态分配的内存后,手动释放内存,避免了悬空指针和内存泄漏的问题。
- 请问运行下面的 Test() 函数会有什么样的后果?
void Test(void)
{
char *str = (char *) malloc(100);
strcpy(str,"hello");
free(str);
if(str != NULL)
{
strcpy(str, "world");
printf("%s\n", str);
}
}
答案: 篡改堆区野指针指向的内容,后果难以预料,非常危险。
解读:
(1)free(str);之后,str成为野指针,没有置为NULL,if(str != NULL)语句不能阻止篡改操作。
(2)野指针不是NULL指针,是指向被释放的或者访问受限的内存的指针。
(3)造成野指针原因:
- ①指针变量没有被初始化,任何刚创建的指针不会自动成为NULL;
- ②指针被free或delete之后,没有置NULL;
- ③指针操作超越了变量的作用范围,比如要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放