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

news2024/11/27 9:48:31

第二篇内容为大家详细剖析关于动态内存管理的几个经典笔试题

目录

  • 四、笔试题
    • 1.请问运行Test函数会有什么样的结果?
      • 结果:
      • 结果运行出错的原因:
      • 本题目注意点:
      • 改正该题目的错误:
        • 正确修改1:(利用传值)
        • 正确修改2:(利用传址)
      • 本题涉及知识点
    • 2.请问运行Test函数会有什么样的结果?
      • 结果
      • 出错原因:
      • 通俗理解本题:
      • 教训:局部变量的地址不要随便返回
      • 重点内容:注意区分在函数里什么时候可以返回
    • 3.请问运行Test函数会有什么样的结果?
      • 错误点:
      • 改正:
      • 重点
    • 4.请问运行Test函数会有什么样的结果?
      • 错误点:
      • 改正:
    • 5.Nice校招笔试题
      • (1)
      • (2)

四、笔试题

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放进去,非法访问内存。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780285.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Electron入门学习_使用预加载脚本

学习网址: https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-preload 1.什么是预加载脚本 Electorn 的主进程是一个拥有完全操作系统访问权限的Node.js ,除了Electron 模组,之外,您也可以访问Node.js 内置模块和所有通过npm安装…

质效两全:媒体服务的创新“顶设”

做媒体服务,一定要有刻入骨髓的抽象思维。 视频化浪潮汹涌、生成式人工智能AIGC极速迭代、体验需求和应用场景愈发多样......面对“视频生产力”的变革,我们能否透过纷繁复杂的表象,洞察音视频行业的“真正需求”? 是否存在一套…

【mysql数据库】MySQL7在Centos7的环境安装

说明: 安装与卸载中,用户全部切换成为root,⼀旦安装,普通用户就能使用。初期练习,mysql不进行用户管理,全部使⽤root进⾏,尽快适应mysql语句,后⾯学了用户管理,在考虑新…

matlab dot()函数求矩阵内积,三维 ,多维 详解

matlab dot()函数求矩阵内积,三维 ,多维 详解 Cdot(A,b,X),这个参数X 只能取1,或者2。1 表示按列,2表示按行,如果没有参数。默认按列。 1)按列优先计算 Cdot(A,B)dot(A,B,1)[a1*b1a4*b4 ,a2*b2a5*b5 ,a…

html,css初学

安装VSCODE ,插件&#xff1a;live server &#xff0c;html support html 然后为了更好地理解&#xff0c;请逐步输入&#xff0c;并及时查看效果 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>D…

A--自动收小麦机--2023河南萌新联赛第(二)场:河南工业大学

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 示例1 输入 4 1 2 1 1 4 5 2 2 2 3 4 输出 10 说明 在第4格放出水流后&#xff0c;水流会流向第3格&#xff0c;由于第3格高度比第4格低&#xff0c;所以水流继续向左流向第2格&#xff0…

爬虫的编解码方式

get请求的quote方法 我们在对爬取一个网页的时候&#xff0c;我们复制了这个网页的地址&#xff0c;但我们发现在将他粘贴下来以后不会是汉字&#xff0c;而是一串字符&#xff0c;这时候&#xff0c;我们需要去对字符进行编码&#xff0c;以便于我们能够继续去爬取网页。 例…

markdown编写数学公式

在计算机这一块&#xff0c;我们肯定会接触到数学&#xff0c;数学中又包含很多公式&#xff0c;但是到现在&#xff0c;手写这些公式应该不陌生&#xff0c;但是如果让你电脑敲出来&#xff0c;你绝对很懵逼&#xff0c;这也造成了我们有时候写笔记时一些公式没办法在电脑上像…

ffmpeg离线安装ffmpeg-4.1.4-amd64-static.tar.xz

1.下载离线包 John Van Sickle - FFmpeg Static Builds 找历史版本&#xff1a;Index of /ffmpeg/old-releases 我选择是的4.1.4版本 2.解压 tar -xvJf ffmpeg-4.1.4-amd64-static.tar.xz 3.移动文件到opt目录下 4.添加全局链接 ln -s /opt/ffmpeg-4.1.4-amd64-static/ffm…

【C++基础(五)】类和对象(上)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C初阶之路⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 类和对象-上 1. 前言2. 类的引入3. 类的定义4. 类的…

代码随想录-回溯(组合问题)|ACM模式

目录 前言&#xff1a; 77.组合 题目描述&#xff1a; 输入输出示例&#xff1a; 思路和想法&#xff1a; 216. 组合总和 III 题目描述&#xff1a; 输入输出示例&#xff1a; 思路和想法&#xff1a; 17. 电话号码的字母组合 题目描述&#xff1a; 输入输出描述&a…

MODBUS TCP转CCLINK IE协议网关profinet接口和以太网接口的区别

你是否曾经遇到过需要将不同的设备连接到一个统一的网络中&#xff1f;或者你是否曾经遇到过设备之间的通讯协议不兼容的问题&#xff1f;远创智控的YC-CCLKIE-TCP通讯网关就是为解决这些问题而设计的。 YC-CCLKIE-TCP通讯网关是一款自主研发的CCLINK IE FIELD BASIC从站功能…

OpenAI报错 time out:HTTPSConnectionPool(host=‘api.openai.com‘, port=443)

项目场景&#xff1a; 使用openai的api调用chatGPT报错&#xff0c;同样的代码在另一台机器没有问题 问题描述 使用官方示例 import openaiopenai.api_key sk-xxxx def chat_gpt(prompt):prompt promptmodel_engine "text-davinci-003"completion openai.Comp…

【Default config not found for ApplicationConfig】的一种解决方案

&#x1f4a7; 记录一下今天遇到的 b u g \color{#FF1493}{记录一下今天遇到的bug} 记录一下今天遇到的bug&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算…

vue项目之《 搭建路由系统 》

author&#xff1a;德玛玩前端 date&#xff1a;2023-07-22 今天&#xff0c;在工作中拿到了架构师的前端框架&#xff0c;是一个vue2elementui搭建的单页面架构&#xff0c;没有路由系统&#xff0c;需要自己搭建&#xff0c;因为以往拿到的框架都是路由系统已经搭建好&#x…

数据结构初阶--单链表

目录 一.单链表的定义 二.单链表的分类 2.1.不带头结点的单链表 2.2.带头结点的单链表 三.单链表的功能实现 3.1.单链表的定义 3.2.单链表的打印 3.3.单链表的结点的创建 3.4.单链表的尾插 3.5.单链表的头插 3.6.单链表的尾删 3.7.单链表的头删 3.8.单链表的查找 …

【Vue3】Vue3核心内容(上)

&#x1f380;个人主页&#xff1a;努力学习前端知识的小羊 感谢你们的支持&#xff1a;收藏&#x1f384; 点赞&#x1f36c; 加关注&#x1fa90; 文章目录 常用的Composition APIsetup函数ref函数reactive函数vue3中的响应式原理vue2的响应式Vue3的响应式 reactive对比Refse…

数据结构---手撕图解七大排序(含动图演示)

文章目录 插入排序直接插入排序希尔排序 选择排序选择排序堆排序 交换排序冒泡排序快速排序hoare版挖坑法前后指针法快速排序的递归展开图快速排序的优化三数取中法 快速排序的非递归实现 归并排序 插入排序 插入排序分为直接插入排序和希尔排序&#xff0c;其中希尔排序是很值…

xxl-job分布式任务调度器的学习

先看一下原生的任务调度器 package com.xxl.job.executor.service.jobhandler;import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;Compone…

3.Docker网络和资源控制

文章目录 Docker操作二Docker网络实现原理端口映射查看日志 网络模式host模式container模式none模式bridge模式自定义网络 Docker资源控制CPU资源控制设置CPU使用率上限设置CPU资源占用比&#xff08;设置多个容器才有效&#xff09;设置容器绑定指定CPU 内存使用限制设置磁盘I…