C++面试速通宝典——9

170. 简述数组和指针的区别?

‌‌‌‌  答:数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。

1. 修改内容上的区别

char a[] = “hello”;
a[0] = ‘X’;
char * p = “world”; //注意 p 指向常量字符串
p[0] = ‘X’; // 编译器不能发现该错误,运行时错误

2. 用运算符sizeof可以计算出数组的容量(字节数)。sizeof§,p是指针,得到的是一个指针变量的字节数,而不是p所指的内存容量。

解释

‌‌‌‌  数组和指针是C/C++编程中的两个非常重要的概念,尽管它们有很多相似之处,但它们本质上是不同的东西。以下是数组和指针的一些主要区别:

数组和指针的定义

数组(Array)

  • 数组是一个具有相同数据类型的元素的有序集合。在内存中,数组元素是连续存储的。
  • 数组的大小在声明时是固定的,不能在运行时动态改变。

指针(Pointer)

  • 指针是一个变量,用于存储另一个变量的内存地址。
  • 指针可以指向不同类型的数据,并且可以在运行时改变指向的地址。

区别点

1. 内存分配
  • 数组: 在编译时分配,大小固定。例如 int arr[5]; 分配5个 int 类型的连续内存空间。
  • 指针: 可以在运行时分配,大小可以动态变化。例如 int *ptr = (int*)malloc(5 * sizeof(int));分配5个 int 类型的连续内存空间。
2. 声明和初始化
  • 数组: 声明数组会自动分配指定大小的内存。例如 int arr[5];
  • 指针: 必须手动指定分配内存,初始化时通常需要一个已有的地址,例如 int *ptr = NULL; 或 int *ptr = (int*)malloc(5 * sizeof(int));
3. 访问方式
  • 数组: 可以使用数组下标直接访问元素,例如 arr[2]
  • 指针: 可以使用指针算术操作和解引用访问元素,例如 *(ptr + 2) 或者 ptr[2]
4. 类型信息
  • 数组: 类型包含了数组的大小。例如 int arr[5]; 是包含 5 个 int 类型元素的数组。
  • 指针: 类型只包含指向的数据类型,不包含大小信息。例如 int *ptr 是指向 int 类型数据的指针,但不包含指向多少个 int 元素的信息。
5. 存储方式
  • 数组: 数组名代表数组的地址,但类型上也包含了数组长度的信息(仅在声明时)。
  • 指针: 指针变量独立存在,可以指向不同的数据地址,不包含长度信息。

示例代码

#include <stdio.h>
#include <stdlib.h>int main() {// 数组示例int arr[5] = {1, 2, 3, 4, 5};printf("数组的第二个元素: %d\n", arr[1]);// 指针示例int *ptr;ptr = (int*)malloc(5 * sizeof(int));if (ptr == NULL) {printf("内存分配失败\n");return -1;}// 分配值for (int i = 0; i < 5; i++) {ptr[i] = i + 1;  // 等同于 *(ptr + i) = i + 1;}printf("指针的第二个元素: %d\n", ptr[1]);// 释放内存free(ptr);return 0;
}

总结

  • 数组是具有固定大小的连续内存块,声明时自动分配和初始化,可以用下标直接访问。
  • 指针是一个变量,存储其他变量的地址,可以动态分配和修改内存地址,通过指针算术和解引用来访问数据。

171. C++函数中值的传递方式

‌‌‌‌  值传递、指针传递、引用传递。

解释
‌‌‌‌  在C++中,函数参数的传递方式主要有三种:值传递Pass by Value)、指针传递Pass by Pointer)和引用传递Pass by Reference)。每种传递方式都有其各自的特点和适用场景。下面逐一进行介绍:

1. 值传递(Pass by Value)

特点:

  • 当函数参数使用值传递时,会在调用函数时将实际参数的值拷贝一份传递给函数。函数内部对参数的任何修改都不会影响到原变量。
  • 主要用于传递简单的数据类型,如基本数据类型(int、char、float等)。

示例代码:

#include <iostream>void increment(int value) {value++;std::cout << "Inside function: " << value << std::endl;
}int main() {int num = 10;increment(num);std::cout << "Outside function: " << num << std::endl;return 0;
}

输出:

Inside function: 11
Outside function: 10

‌‌‌‌  在这个例子中,increment函数接收到的是num的一个拷贝,因此对value的修改不会影响到num本身。

2. 指针传递(Pass by Pointer)

特点:

  • 当函数参数使用指针传递时,传递的是实际参数的地址。函数内部通过指针可以直接访问和修改实际参数的值。
  • 适用于需要在函数内部修改参数值的情况

示例代码:

#include <iostream>void increment(int *value) {(*value)++;std::cout << "Inside function: " << *value << std::endl;
}int main() {int num = 10;increment(&num);std::cout << "Outside function: " << num << std::endl;return 0;
}

输出:

Inside function: 11
Outside function: 11

‌‌‌‌  在这个例子中,increment函数接收到的是num的地址,因此通过解引用指针*value可以直接修改num的值。

3. 引用传递(Pass by Reference)

特点:

  • 当函数参数使用引用传递时,传递的是实际参数的引用(别名)。函数内部对参数的任何修改都会直接影响到原变量。
  • 比指针传递更安全,语法上也更简洁
  • 使用引用传递的参数在函数体内像普通变量一样使用,但实际上是对原始数据的引用。

示例代码:

#include <iostream>void increment(int &value) {value++;std::cout << "Inside function: " << value << std::endl;
}int main() {int num = 10;increment(num);std::cout << "Outside function: " << num << std::endl;return 0;
}

输出:

Inside function: 11
Outside function: 11

‌‌‌‌  在这个例子中,increment函数直接接收到num的引用,因此对value的任何修改都会反映到num上。

总结

  • 值传递: 函数接收到的是实际参数的一份拷贝,函数内部对参数的修改不会影响原变量。
  • 指针传递: 函数接收到的是实际参数的地址,函数内部可以通过指针直接修改原变量的值。
  • 引用传递: 函数接收到的是实际参数的引用,函数内部对参数的修改会直接影响原变量,用法上更简单且安全。

‌‌‌‌  这三种传递方式各有优劣,选择哪种方式取决于具体的应用场景和需求。如果需要在函数中修改实际参数的值,推荐使用指针传递或引用传递;而对于传递大对象时,引用传递通常比值传递和指针传递更高效。

172. 内存的分配方式有哪几种?

答:有三种。

  1. 静态存储区:是在程序编译时就已经分配好的,在整个运行期间都存在,如全局变量、常量。
  2. 栈上分配:函数内的局部变量就是从这分配的,但分配的内存容量有限。
  3. 堆上分配:也称动态分配,如我们使用new、malloc分配内存,用delete、free来释放内存。

解释

‌‌‌‌  在讨论内存分配方式时,通常提到的三种方式(静态存储区、栈上分配和堆上分配)主要是指程序在运行时分配和管理内存的机制,而代码区的内存分配则是在程序加载时已经确定的,并且不在程序运行时动态分配或释放。因此,代码区的分配方式一般不包含在这三种运行时内存分配方式的讨论中。具体原因如下:

  1. 静态存储区:静态存储区分配的是全局变量和静态变量的内存,这些变量在程序加载时分配,并在程序整个运行期间保持不变。静态存储区的分配和代码区一样,是在程序加载时确定的,但它主要用于存储数据,而不是代码。

  2. 栈上分配:栈上分配用于存储函数的局部变量和函数调用的上下文信息(如返回地址、参数等)。栈上的内存分配是动态的,在函数调用时分配,函数返回时释放。这是一种运行时的内存管理机制。

  3. 堆上分配:堆上分配用于动态分配内存,例如通过mallocnew等函数分配的内存。堆上的内存分配和释放是由程序员在运行时显式管理的,适用于需要动态管理生命周期的对象。

代码区的分配:代码区的内存分配是由操作系统在程序加载时完成的,并且是只读的。在程序运行期间,代码区的内容不会改变,也不会像栈或堆那样动态分配或释放内存。因此,代码区的分配属于程序加载时的静态分配,与运行时的内存分配机制有所不同。

综上所述,代码区的内存分配是在程序加载时完成的静态分配,与运行时的内存分配方式有所区别,因此通常不在讨论运行时内存分配方式时被提及。

‌‌‌‌  代码区的分配是在程序编译和链接的过程中完成的。具体来说,代码区(又称文本区)存储的是程序的可执行指令,这些指令在程序运行时是只读的。代码区的分配过程可以概括为以下几个步骤:

  1. 编译阶段:在源代码编译时,编译器将源代码翻译成机器代码,并生成目标文件(通常是.o或.obj文件)。这些目标文件中包含了程序的机器指令和一些元数据。

  2. 链接阶段:链接器将一个或多个目标文件与库文件链接,生成最终的可执行文件。在这个过程中,链接器将所有目标文件中的代码段合并,并安排它们在最终可执行文件中的位置。

  3. 加载阶段:当程序被加载到内存中运行时,操作系统的加载器将可执行文件中的代码段加载到内存中的一个专门区域,这个区域就是代码区。加载器负责将代码段映射到内存中的一个只读区域,以确保代码在运行时不会被修改。

总结起来,代码区的分配是在编译和链接过程中由编译器和链接器完成的,最终在程序加载到内存时由操作系统的加载器负责实际的内存分配和映射。

173. extern"C"有什么作用?

答:
‌‌‌‌  Extern"C"是由C++提供的一个连接交换指定符号,用于告诉C++这段代码是C函数。这是因为C++编译后库中函数名会变得很长,与C生成的不一致,造成C++不能直接调用C函数,加上extern"C"后,C++就能直接调用C函数了。

‌‌‌‌  Extern"C"主要使用正规DLL函数的引用和导出,在C++包含C函数或头文件的时候使用。使用时在前面加上extern "C"关键字即可。可以用一句话概括extern"C"这个声明的真实目的:实现C++与C以及其它语言的混合编程。

174. 用什么函数开启新线程、进程?

答:
‌‌‌‌  新线程:CreateThread / AfxBegin Thread 等。
‌‌‌‌  新进程:CreateProcess 等。

175. SendMessage 和 PostMessage 有什么区别?

答:
‌‌‌‌  SendMessage阻塞的,等消息被处理后,代码才能走到SendMessage的下一行。
‌‌‌‌  PostMessage非阻塞的,不管消息是否已经被处理,代码马上走到PostMessage下一行。

解释

‌‌‌‌  这段话描述了SendMessagePostMessage在消息处理机制中的不同行为,特别是在Windows编程中。这两者都是用来将消息发送到指定的窗口或线程,但它们在执行时的行为有所不同。

SendMessage

‌‌‌‌  SendMessage函数是同步的(阻塞的),这意味着它会将消息发送到目标窗口,并等待该消息被处理完毕之后,才返回并继续执行下一行代码。具体来说:

  1. SendMessage将消息发送到目标窗口的消息队列
  2. 目标窗口的窗口过程(Window Procedure)接收并处理该消息。
  3. 处理完消息之后,SendMessage返回结果。
  4. 代码继续执行SendMessage之后的代码行。

‌‌‌‌  因为SendMessage会等待消息被处理完毕,所以它是阻塞的。这意味着如果消息处理需要很长时间,调用SendMessage的线程会被阻塞,直到消息处理完成。

PostMessage

‌‌‌‌  PostMessage函数是异步的(非阻塞的),这意味着它将消息放入目标窗口的消息队列后,立即返回并继续执行下一行代码,而不等待消息被处理。具体来说:

  1. PostMessage将消息放入目标窗口的消息队列。
  2. PostMessage立即返回,不等待消息处理结果。
  3. 代码继续执行PostMessage之后的代码行。
  4. 目标窗口的消息队列会在合适的时间调度并处理该消息。

因为PostMessage不等待消息被处理,所以它是非阻塞的。这意味着调用PostMessage的线程可以继续执行,而不会因为消息处理的时间而被阻塞。

理解的关键点

  • 阻塞和非阻塞SendMessage是阻塞的,调用线程必须等待消息被处理完才会继续执行。PostMessage是非阻塞的,调用线程无需等待消息处理结果,可以立即继续执行。
  • 消息处理机制SendMessage要求同步处理消息,适合需要立即获得处理结果的场景。PostMessage则是异步处理消息,适合不需要立即获得处理结果,或者希望减少线程等待时间的场景。

示例代码

‌‌‌‌  下面是一个简化的示例代码,展示了SendMessagePostMessage的不同行为:

// SendMessage 示例
SendMessage(hWnd, WM_COMMAND, wParam, lParam);
// 只有在消息处理完成后,才会执行下一行代码
printf("SendMessage 后的代码");// PostMessage 示例
PostMessage(hWnd, WM_COMMAND, wParam, lParam);
// 立即返回并执行下一行代码,而不等待消息处理
printf("PostMessage 后的代码");

‌‌‌‌  在SendMessage的情况下,只有当消息被处理完毕,才会打印"SendMessage 后的代码";而在PostMessage的情况下,消息一发送就立即打印"PostMessage 后的代码",不管消息是否被处理。

176. CMemoryState 的主要功能是什么?

‌‌‌‌  CMemoryState查看内存使用情况,解决内存泄露的问题

解释

‌‌‌‌  CMemoryState 是 MFC(Microsoft Foundation Class)库中的一个类,用于内存调试。它主要用于检测和报告内存泄漏。在调试版本的应用程序中,CMemoryState 可以保存内存的当前状态,并在需要时与另一状态进行比较,以检测内存的分配和释放情况是否一致。

CMemoryState 的主要功能

  1. 保存内存状态
    • 使用 CMemoryState::Checkpoint 方法保存当前的内存状态。
    • 通过保存多个内存状态,可以在不同的时间点记录内存使用情况。
  2. 比较内存状态
    • 使用 CMemoryState::Difference 方法比较两个内存状态。
    • 可以检测出两个检查点之间的内存泄漏情况。
  3. 报告内存泄漏
    • 使用 CMemoryState::DumpStatistics 方法报告内存状态,包括内存泄漏信息。
    • 可以输出内存泄漏的详细信息,帮助开发者定位和修复内存泄漏。

代码示例

以下是一个使用 CMemoryState 检测内存泄漏的简单示例:

#include <afx.h>
#include <iostream>void TestMemoryLeak()
{// 创建一个内存块用于测试char* pMemory = new char[100];// 注意,这里故意没有删除内存,以测试内存泄漏
}int main()
{// 检查点1:在调用函数之前保存内存状态CMemoryState oldState, newState, diffState;oldState.Checkpoint();// 调用可能产生内存泄漏的函数TestMemoryLeak();// 检查点2:在调用函数之后保存内存状态newState.Checkpoint();// 比较两个检查点之间的内存状态if (diffState.Difference(oldState, newState)){std::cout << "Memory leaks detected:" << std::endl;diffState.DumpStatistics();}else{std::cout << "No memory leaks detected." << std::endl;}return 0;
}

代码解释

  1. 初始化内存状态
    • CMemoryState oldState, newState, diffState; 创建三个 CMemoryState 对象,用于保存不同时间点的内存状态。
  2. 保存内存状态
    • oldState.Checkpoint(); 在调用 TestMemoryLeak 之前保存当前的内存状态。
    • newState.Checkpoint(); 在调用 TestMemoryLeak 之后保存当前的内存状态。
  3. 比较内存状态
    • diffState.Difference(oldState, newState); 比较两个检查点之间的内存状态。
    • 如果检测到内存泄漏,Difference 方法将返回 TRUE,并且 diffState 将包含泄漏的详细信息。
  4. 报告内存泄漏
    • diffState.DumpStatistics(); 输出内存泄漏的详细信息。

通过这种方式,CMemoryState 可以帮助开发者在调试阶段检测和修复内存泄漏,确保应用程序的内存管理更加健壮和高效。

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

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

相关文章

毕设分享 基于协同过滤的电影推荐系统

文章目录 0 简介1 设计概要2 课题背景和目的3 协同过滤算法原理3.1 基于用户的协同过滤推荐算法实现原理3.1.1 步骤13.1.2 步骤23.1.3 步骤33.1.4 步骤4 4 系统实现4.1 开发环境4.2 系统功能描述4.3 系统数据流程4.3.1 用户端数据流程4.3.2 管理员端数据流程 4.4 系统功能设计 …

【Android 源码分析】Activity生命周期之onStop-2

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

信息安全工程师(28)机房安全分析与防护

前言 机房安全分析与防护是一个复杂而细致的过程&#xff0c;涉及到物理安全、环境控制、电力供应、数据安全、设备管理、人员管理以及紧急预案等多个方面。 一、机房安全分析 1. 物理安全威胁 非法入侵&#xff1a;未经授权的人员可能通过门窗、通风口等进入机房&#xff0c;…

【LeetCode】每日一题 2024_10_10 优质数对的总数 I(暴力/哈希)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动&#xff01; 题目&#xff1a;优质数对的总数 I 代码与解题思路 简单题先暴力~ 直接对着题意模拟即可&#xff0c;力扣上只要是标着简单标签的题目&#xff0c;不用犹豫&#xff0c;直接对他使用暴力吧&#xff01; …

亮度(luminance)

亮度&#xff08;luminance&#xff09;的单位是坎德拉每平方米&#xff08;cd/m&#xff09;。它是用来描述光源或物体表面发出的光在某个方向上的亮度程度。亮度可以简单理解为人眼感知的物体表面在某一特定方向上发出的光强。 亮度的理解&#xff1a; 亮度的概念&#xff…

LabVIEW混合控制器质量检测

随着工业自动化水平的提高&#xff0c;对控制器的精度、稳定性、可靠性要求也在不断上升。特别是在工程机械、自动化生产、风力发电等领域&#xff0c;传统的质量检测方法已无法满足现代工业的高要求。因此&#xff0c;开发一套自动化、精确、可扩展的混合控制器质量检测平台成…

【Linux】常用系统命令

Linux 系统中有许多常用的命令&#xff0c;适用于不同的任务和场景。以下是一些基础且常用的 Linux 命令&#xff1a; 1. **文件和目录操作** - ls&#xff1a;列出目录内容。 - cd&#xff1a;改变当前目录。 - pwd&#xff1a;打印当前工作目录。 - mkdir&#…

Redis 数据类型string(字符串)

目录 1 基本特性 2 主要操作命令 2.1 设置键值 2.1.1 SET key value [EX seconds] [PX milliseconds] [NX|XX] 2.1.2 MSET key value [key value ...] 2.1.3 SETEX key seconds value 2.1.4 PSETEX key milliseconds value 2.1.5 APPEND key value 2.2 获取键值 …

Pikachu-Cross-Site Scripting-xss盲打

xss盲打&#xff0c;不是一种漏洞类型&#xff0c;而是一个攻击场景&#xff1b;在前端、或者在当前页面是看不到攻击结果&#xff1b;而是在后端、在别的页面才看到结果。 登陆后台&#xff0c;查看结果&#xff1b;

Extreme Compression of Large Language Models via Additive Quantization阅读

文章目录 Abstract1. Introduction2. Background & Related Work2.1. LLM量化2.2. 最近邻搜索的量化 3.AQLM:Additive Quantization for LLMs3.1. 概述3.1.0 补充**步骤说明****举例说明** 3.2. 阶段1&#xff1a;代码的波束搜索3.3. 阶段2&#xff1a;码本更新3.4. 阶段3&…

Qt Creator 通过python解释器调用*.py

全是看了大佬们的帖子&#xff0c;结合chatGPT才揉出来。在此做个记录。 安装python在Qt Creator *.pro 文件中配置好环境来个简单的example.py调用代码安装pip添加opencv等库调用包含了opencv库的py代码成功 *.pro配置&#xff1a; INCLUDEPATH C:\Users\xuanm\AppData\Lo…

wordpress在页面中调用另外一个页面的内容

在WordPress中&#xff0c;一个页面调用另一个页面的内容通常不是WordPress设计的直接功能&#xff0c;因为WordPress的页面和内容通常是独立管理的。不过&#xff0c;你可以通过几种方法来实现这一需求&#xff1a; 1. 使用WordPress的短代码(Shortcodes) 你可以创建一个自定…

操作系统中的并发控制——使用条件变量同步

本期主题&#xff1a; 操作系统中的并发控制&#xff0c;条件变量 往期链接&#xff1a; linux设备驱动中的并发操作系统中的多线程问题——原子操作、自旋锁的底层实现操作系统并发控制——使用互斥锁实现同步 操作系统并发控制之条件变量同步 1. 问题描述2. 条件变量的API讲…

Netty的线程模型

Netty的线程模型是其核心特性之一&#xff0c;主要包括以下几个方面&#xff1a; 线程模型概述 作用与重要性&#xff1a;线程模型决定了代码在操作系统、编程语言和框架中的执行方式&#xff0c;对于处理多线程相关的问题至关重要。在网络编程中&#xff0c;合理的线程模型可…

云栖实录 | Hologres3.0全新升级:一体化实时湖仓平台

本文根据2024云栖大会实录整理而成&#xff0c;演讲信息如下&#xff1a; 演讲人&#xff1a; 姜伟华 | 阿里云智能集团资深技术专家、Hologres 负责人 丁 烨 | 阿里云智能集团产品专家、Hologres 产品负责人 活动&#xff1a; 2024 云栖大会 - 商用大数据计算与分析平台论…

Python中的数据可视化:从入门到进阶

数据可视化是数据分析和科学计算中的重要环节&#xff0c;它通过图形化的方式呈现数据&#xff0c;使复杂的统计信息变得直观易懂。Python提供了多种强大的库来支持数据可视化&#xff0c;如Matplotlib、Seaborn、Plotly等。本文将从基础到进阶&#xff0c;详细介绍如何使用这些…

[单master节点k8s部署]31.ceph分布式存储(二)

Ceph配置 Ceph集群通常是一个独立的存储集群&#xff0c;可以部署在 Kubernetes 集群之外。Ceph 提供分布式存储服务&#xff0c;能够通过 RADOS、CephFS、RBD&#xff08;块存储&#xff09;、和 RGW&#xff08;对象存储&#xff09;等方式与 Kubernetes 集成。即使 Ceph 部…

逼近理论及应用精解【9】

文章目录 全卷积模型定义数学原理与公式架构典型结构应用优点挑战例题 ANNSENet&#xff08;Squeeze-and-Excitation Networks&#xff09;定义数学原理与公式计算定理架构例子例题 ResNet&#xff08;残差网络&#xff09;定义数学原理与公式计算定理算法过程架构例子例题 参考…

PostgreSQL学习笔记五:数据库基本操作

在 PostgreSQL 中&#xff0c;您可以执行一系列基础操作来管理数据库、备份和恢复数据。以下是一些常用的命令和步骤&#xff1a; 创建数据库 使用以下命令创建新数据库&#xff1a; CREATE DATABASE database_name;您也可以在创建时指定数据库所有者和其他参数&#xff1a;…

基于深度学习的手势控制模型

关于深度实战社区 我们是一个深度学习领域的独立工作室。团队成员有&#xff1a;中科大硕士、纽约大学硕士、浙江大学硕士、华东理工博士等&#xff0c;曾在腾讯、百度、德勤等担任算法工程师/产品经理。全网20多万粉丝&#xff0c;拥有2篇国家级人工智能发明专利。 1. 项目简…