C语言动态内存管理(二)经典笔试题

简介: C语言动态内存管理(二)经典笔试题

四、笔试题

1.请问运行Test函数会有什么样的结果?

void GetMemory(char* p)
{
  p = (char*)malloc(100);
}
void Test(void)
{
  char* str = NULL;
  GetMemory(str);
  strcpy(str, "hello world");
  printf(str);
}
int main() {
  Test();
  return 0;
}

结果:

结果运行出错的原因:

(1)

调用GetMemory函数的时候,str的传参为值传递,p是str的临时拷贝,所以在GetMemory函数内部将动态开辟空间的地址存放在p中的时候,不会影响str,所以GetMemory函数返回之后,str中依然是NULL指针。strcpy函数就会调用失败,原因是对NULL指针的解引用操作,程序会崩溃

(2)

GetMemory函数内部malloc申请的空间没有机会释放,造成了内存泄漏

本题目注意点:

(1)注意这个程序想释放也释放不了,无论是在主函数中释放还是在test函数内部。因为一旦返回,就没有人记得动态开辟的空间在哪里,动态开辟空间的地址带不出来。

(2)而这道题的本意是想把100个字节的地址放到str里面,然后把hello world拷贝到str指向的空间里。

改正该题目的错误:

正确修改1:(利用传值)
char* GetMemory(char* p) {
  p = (char*)malloc(100);
  return p;
}
void Test(void) {
  char* str = NULL;
  str = GetMemory(str);
  strcpy(str, "hello world");
  printf(str);
  free(str);
  str = NULL;
  return 0;
}
int main() {
  Test();
  return 0;
}

解释:

(1)这里也是利用传值,但是GetMemory函数返回的是指针,p所指向的是malloc出来的空间,是在堆上,除了函数不销毁这块空间,通过p返回的地址仍然可以找到这块空间。

与原题传值对比:

原题目中的p是函数的形参变量,形参变量是个临时变量,出了函数就销毁了。p销毁了,p这块空间还给操作系统,没人记得malloc申请的空间在哪里。

(2)使用完动态开辟的这块空间用free回收掉

正确修改2:(利用传址)
void GetMemory(char** p) {
  *p = (char*)malloc(100);
}
void Test(void) {
  char* str = NULL;
  GetMemory(&str);
  strcpy(str, "hello world");
  printf(str);
  free(str);
  str = NULL;
  return 0;
}
int main() {
  Test();
  return 0;
}

解释:

将指针str的地址传给GetMemory函数的形参,str是char类型的是一级指针,它的地址用二级指针**p接收,在GetMemory函数中的p存的就是str,这样的话不通过返回值也能把地址带回来

本题涉及知识点

关于printf打印字符的两种方式:

比如这句代码 char* p=“hehe\n”;

意思不是把字符串hehe\n放到p里面,而是把这个表达式字符串首地址h的地址放到p中

2.请问运行Test函数会有什么样的结果?

char* GetMemory(void)
{
  char p[] = "hello world";
  return p;
}
void Test(void)
{
  char* str = NULL;
  str = GetMemory();
  printf(str);
}
int main() {
  Test();
  return 0;
}

结果

出错原因:

返回栈空间地址的问题:

GetMemory函数内部创建的数组是临时的,虽然返回了数组的起始地址给str,但是数组的内存出了GetMemory函数就被回收了,而str依然保存了数组的起始地址,这时使用str,str就是野指针

通俗理解本题:

张三开了一间房,告诉李四明天来如家酒店302房间可入住,但是在李四来之前,张三已经把房间退了。等到李四根据张三提供的地址来到302时却无法入住,这间房也不属于李四。

这里的把房间退了相当于将空间还给操作系统,即使你有这个空间的地址信息,而这个空间确不属于你,且不能访问这个空间

教训:局部变量的地址不要随便返回

举例说明:

根据上面的讲解,这里打印的应该是随机值,而这里刚好打印出正确的结果,是怎么回事?难道这样写也正确吗?

答:这样写是错误的。之所以刚好打印出结果10,是因为恰好空间没有被改掉的情况。


当多打印个别的语句时,就可以发现此时*p的值改变成5了。

这里为什么多打印个hehe下面就变了?

答:因为栈帧空间会被覆盖

重点内容:注意区分在函数里什么时候可以返回

char* GetMemory(char* p) {
  p = (char*)malloc(100);
  return p;
}

3.请问运行Test函数会有什么样的结果?

void GetMemory(char** p, int num)
{
  *p = (char*)malloc(num);
}
void Test(void)
{
  char* str = NULL;
  GetMemory(&str, 100);
  strcpy(str, "hello");
  printf(str);
}

错误点:

malloc动态开辟的空间在使用完没有释放掉,造成内存泄漏

改正:

释放指针并将指针置为空

重点

free完之后的指针如果不是空指针,一定要置为空指针,避免野指针问题

4.请问运行Test函数会有什么样的结果?

void Test(void)
{
  char* str = (char*)malloc(100);
  strcpy(str, "hello");
  free(str);
  if (str != NULL)
  {
    strcpy(str, "world");
    printf(str);
  }
}

错误点:

(1)free完动态开辟的空间应该及时将指针置空,这里没有置空

(2)str指向的空间已经回收了,因为str没有置为空指针,还能找到刚开辟的那块空间,但是这块空间已经回收给操作系统了,不属于str,不能用,拷贝时形成非法访问,此时的str是野指针

改正:

5.Nice校招笔试题

指出下面哪段程序有问题,并说明问题是什么。

(1)

该题是返回栈空间地址的问题。

如果有人接收了这个函数返回的指针,就会造成野指针的问题。

(2)

指针ptr没有初始化,没有任何指向,里面是随机值。

不知道ptr指向谁,直接对它解引用

对野指针解引用,还把10放进去,非法访问内存。

结语:

本篇内容就到这里啦,关于动态内存管理的内容未完待续,请见下篇博客。如果对大家有帮助的话,希望友友们可以点赞收藏博客,关注后续的学习内容哦!❤️💕💕

相关文章
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
1月前
|
编译器 C语言
动态内存分配与管理详解(附加笔试题分析)(上)
动态内存分配与管理详解(附加笔试题分析)
49 1
|
21天前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
33 3
|
1月前
|
程序员 编译器 C语言
动态内存分配与管理详解(附加笔试题分析)(下)
动态内存分配与管理详解(附加笔试题分析)(下)
46 2
|
1月前
|
编译器 程序员 C语言
深入C语言:动态内存管理魔法
深入C语言:动态内存管理魔法
|
1月前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
23天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
19 0
|
1月前
|
C语言
保姆级教学 - C语言 之 动态内存管理
保姆级教学 - C语言 之 动态内存管理
19 0
|
1月前
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
|
1月前
|
C语言 C++
c语言回顾-内存操作函数
c语言回顾-内存操作函数
40 0