当前位置: 首页 > news >正文

突破编程_C++_面试(基础知识(5))

面试题9:什么是内存地址

内存地址是指计算机内存中存储变量或对象的地址。内存空间大小就是寻址能力,即能访问到多少个地址,比如 32 位机器内存空间大小就是 2^32 = 4294967296,也就是 4 GB 。每个变量或对象在内存中都有一个唯一的地址,通过该地址可以访问和操作该变量或对象。注意一 个内存地址对应一个字节,以 int 类型的变量为例,其占据 4 个内存地址,其中首个内存地址就是这个变量的地址。

#include <iostream>int main()
{int vals[4]{};printf("val1 address = %p\n", &vals[0]);printf("val2 address = %p\n", &vals[1]);printf("val3 address = %p\n", &vals[2]);printf("val4 address = %p\n", &vals[3]);return 0;
}

上面代码的输出为:

val1 address = 0000005420F6F978
val2 address = 0000005420F6F97C
val3 address = 0000005420F6F980
val4 address = 0000005420F6F984

为了能够说明 1 个 int 类型的变量占据 4 个内存地址,我们在上面的代码中使用占据连续内存的数组来做测试,由这个输出可以看出:数组 vals 的第一个元素所占据的内存地址由 0000005420F6F9780000005420F6F97B (再往下的一个地址就是第二个元素的首地址 0000005420F6F97C),刚好是 4 个内存地址,其首个内存地址 0000005420F6F978 就是这个数组 vals 的第一个元素的地址(同时也是这个数组变量 vals 的地址)。

面试题10:常量指针与指针常量的区别

常量指针(const pointer)和指针常量(pointer to const)是两个不同的概念,常量指针指的是其指向变量的值不可改变,但是指针本身是可以改变的,可以指向其他变量;指针常量指的是指针本身是常量,其不可以再指向其他变量。
常量指针的样例代码:

const int val1 = 1;
int *ptr1 = &val1;			//错误:必须使用常量指针
const int *ptr1 = &val1;	//OK
*ptr1 = 2;	

指针常量的样例代码:

int val1 = 1;
int val2 = 2;
int const *ptr1 = &val1;	//OK
*ptr1 = &val2;				//错误:指针本身是常量,其不可以再指向其他变量。

面试题11:野指针出现的原因

野指针出现的原因主要有以下三种:
(1)指针变量未初始化。局部指针变量的默认值是一个随机值,如果此时访问该指针则会引起程序崩溃。所以,指针变量在创建的同时应当被初始化,要么将指针设置为 nullptr ,要么让它指向合法的内存( new 出来的对象或者现有的一个对象)。
(2)释放内存后没有将指针设置为 nullptr 。不管是 free 还是 delete 在释放内存时,只是把指针所指的内存给释放掉了,但此时指针的值依然是之前内存空间的首地址。此时访问该指针则会引起程序崩溃。
(3)指针操作超越变量作用范围。栈内存在函数结束时会被释放,如果将其内存地址通过指针返回给调用者,此时再访问则会引起程序崩溃。

面试题12:使用 nullptr 的好处是什么

nullptr 关键字是在 C++11 标准中引入的,用于表示空指针。在 C++11 及以后的版本中,nullptr 替代了 C++98/03 中的 NULL 或 0 作为空指针的表示。该关键字可以避免函数重载问题,如下为样例代码:

void overLoadFunc(int* val);
void overLoadFunc(int val);int main()
{overLoadFunc( NULL );  // 期待调用 overLoadFunc(int* val); 但实际调用却是 overLoadFunc(int val);
}

上面代码中的 overLoadFunc( NULL ); 实际调用的是 overLoadFunc(int val); 。其原因是 NULL 本身就是整数 0 ,因此进入了整型参数的重载函数。

面试题13:什么是指针的指针

指针的指针是一个指向指针的指针。指针可以指向所有数据类型的变量(基本类型、结构体类型、类类型等),而指针自身也是一种变量,所以指针自然也可以指向指针。指针的指针通常用于处理二维数组、动态分配的二维数组或处理指针数组等。
如下样例可以帮助理解指针的指针:

#include <iostream>int main()
{int val1 = 1;int *ptr1 = &val1;int **ptr2 = &ptr1;printf("ptr1 address = %p\n", &ptr1);printf("ptr1 address = %p\n", &(*ptr2));printf("ptr2 value = %p\n", ptr2);return 0;
}

上面代码的输出为:

ptr1 address = 000000C4A839F758
ptr1 address = 000000C4A839F758
ptr2 value = 000000C4A839F758

由结果可以看出,指向指针的指针变量 ptr2 保存了指针变量 ptr1的地址( 000000C4A839F758 )。 其中代码第 10 行 int **ptr2 = &ptr1; 定义了一个指向指针的指针,这里用了两个星号*,其保存的值就是指针变量 ptr1的地址。
第 11、 12、 13 行代码尤为重要:
第 11 行代码 printf("ptr1 address = %p\n", &ptr1); ,其中的 &ptr1 是对指针变量 ptr1 做取地址操作。
第 12 行代码 printf("ptr1 address = %p\n", &(*ptr2)); ,其中的 (*ptr2) 是对指针变量 ptr2 做解引用操作,再对其做取地址操作,相当于直接对指针变量 ptr1 做取地址操作。
第 13 行代码 printf("ptr2 value = %p\n", ptr2); ,对指向指针的指针取值,直接用其变量名即可。
使用指针的指针来处理二维数组时,其对应内存的创建以及释放都需要使用循环:
(1)创建二维数组

int** vals = new int*[2];
for (size_t i = 0; i < 2; i++)
{vals[i] = new int[3]();
}

(2)释放二维数组的内存

int** vals = new int*[2];
for (size_t i = 0; i < 2; i++)
{vals[i] = new int[3]();
}for (size_t i = 0; i < 2; i++)
{delete[] vals[i];		//注意 delete 一定要加上中括号 []
}

这里尤其注意 delete[] 的使用。

http://www.lryc.cn/news/295046.html

相关文章:

  • 十分钟掌握Go语言==运算符与reflect.DeepEqual函数处理interface{}值的比较规则
  • Unity3d Shader篇(一)— 顶点漫反射着色器解析
  • WordPress主题YIA的文章页评论内容为什么没有显示出来?
  • 选择低代码应该注意什么?如何选择?
  • 橘子学linux调优之工具包的安装
  • 函数的连续与间断【高数笔记】
  • 游戏如何选择服务器
  • ubuntu20安装mysql8
  • 07 SB3之@HttpExchange(TBD)
  • Redis数据淘汰策略
  • Git的一些基本操作
  • Spring Boot中异步线程池@Async
  • ArcGIS学习(五)坐标系-2
  • 2024Node.js零基础教程(小白友好型),nodejs新手到高手,(五)NodeJS入门——http模块
  • sklearn.preprocessing 标准化、归一化、正则化
  • Windows系统编程(一) 文件与目录操作
  • 6-2、T型加减速计算简化【51单片机+L298N步进电机系列教程】
  • 配置Jenkins自动构建打包项目
  • 进阶C语言-通讯录的实现
  • STM32单片机的基本原理与应用(七)
  • LLM应用开发与落地:使用gradio十分钟搭建聊天UI
  • 智慧城市:打造低碳未来,引领城市数字化转型新篇章
  • ChatGPT之制作短视频
  • k8s学习(RKE+k8s+rancher2.x)成长系列之简配版环境搭建(二)
  • 智能优化算法 | Matlab实现合作优化算法(CSA)(内含完整源码)
  • mysql如何备份某些库的某些表
  • C++类和对象入门(三)
  • 【0255】揭晓pg内核中MyBackendId的分配机制(后端进程Id,BackendId)(一)
  • Python爬虫requests库详解
  • 【漏洞复现】EPON上行A8-C政企网关信息泄露漏洞