【c++】入门3

引用

1.swap交换两个变量值的时候可以用引用
2.例题中通过前序遍历数组构建二叉树,可以用引用传别名.


#include <stdio.h>
#include <stdlib.h>
typedef struct BinaryTreeNode {
    char data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
} BTNode;
BTNode* BinaryTreeCreate(char* a, int* pi)
{if(a[*pi]=='#')
{   (*pi)++;
    return NULL;}
BTNode* newnode=(BTNode*)malloc(sizeof(BTNode));
newnode->data=a[(*pi)++];
newnode->left=BinaryTreeCreate(a,pi);
newnode->right=BinaryTreeCreate(a,pi);
return newnode;

}
void  InOrder(BTNode* root)
{if(root==NULL)
return ;
InOrder(root->left);
printf("%c ",root->data);
InOrder( root->right);

}

int main() {
    char arr[100];
    scanf("%s",arr);
    int i=0;
   BTNode*bk= BinaryTreeCreate(arr,&i);
    InOrder(bk);
}

i变量是在main函数栈帧中创建的,在调用BinaryTreeCreate(arr,&i);完不会被销毁,可以用引用.
修改如下:

#include <stdio.h>
#include <stdlib.h>
typedef struct BinaryTreeNode {
    char data;
    struct BinaryTreeNode* left;
    struct BinaryTreeNode* right;
} BTNode;
BTNode* BinaryTreeCreate(char* a, int& pi)
{if(a[pi]=='#')
{   pi++;
    return NULL;}
BTNode* newnode=(BTNode*)malloc(sizeof(BTNode));
newnode->data=a[pi++];
newnode->left=BinaryTreeCreate(a,pi);
newnode->right=BinaryTreeCreate(a,pi);
return newnode;

}
void  InOrder(BTNode* root)
{if(root==NULL)
return ;
InOrder(root->left);
printf("%c ",root->data);
InOrder( root->right);

}

int main() {
    char arr[100];
    scanf("%s",arr);
    int i=0;
   BTNode*bk= BinaryTreeCreate(arr,i);
    InOrder(bk);
}

用到引用的地方都是输出型参数


引用做返回值

在这里插入图片描述
注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
下面代码输出什么结果?为什么?

#include<iostream>
using namespace std;
int& Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int& ret = Add(1, 2);
	Add(3, 4);
	cout << "Add(1, 2) is :" << ret << endl;
	return 0;
}

分析:这个程序是不对的,我们刚才说过要使用引用的话,必须是输出型参数,也就是出了作用域不销毁的参数,而这里的c是局部变量,是临时变量,出了作用域要被销毁的。如果传引用回去的话,c地址上的值会被修改。因为c地址上的值随着栈帧的销毁而被修改。这里为什么会是7,因为再次调用同个函数时,用的是和上一个调用的add函数同样的栈帧,所以原地址上的c地址上的值会被新的值7覆盖,于是ret就是7了.

#include<iostream>
using namespace std;
int& Add(int a, int b)
{
	int c = a + b;
	return c;
}
int main()
{
	int& ret = Add(1, 2);
	//Add(3, 4);
	cout << "Add(1, 2) is :" << ret << endl;
	return 0;
}

如果删除一行,打印出来的值不一定是3,取决于不同的编译器。栈帧中变量空间是否被回收不知道.

传值返回
1.传参返回时不是直接返回,会产生临时变量.
2.静态变量出栈不会被销毁,也产生临时变量.

传引用返回
1.用于出了作用域。不销毁的变量.
2.减少了临时变量的拷贝.
3.调用者可以修改返回对象,比如上面的ret.
4.栈帧销毁,内存消除不确定.
5.出栈帧不存在的变量会出现错误,就不要用引用返回.
6.静态,全局,上一次栈帧,malloc来的变量可以用引用.
7.传引用返回比传值返回提高了效率,不用建立临时变量.


常引用

权限放大

#include<iostream>
using namespace std;

int main()
{
	const int c = 2;
	int& d = c;


}

将只读的变量c,使用引用,d变量的权限不能变成既能读,又能写.权限不能放大.
在举一个指针权限放大的:

#include<iostream>
using namespace std;

int main()
{
	const int* pi = NULL;
	int* p2 = p1;


}

同样也是权限放大,编译器会保错.


权限保持

只读-只读

#include<iostream>
using namespace std;

int main()
{
	const int* pi = NULL;
	const int* p2 = pi;


}

权限缩小

#include<iostream>
using namespace std;

int main()
{
	int x = 1;
	const int& y = x;


}

指针也一样

权限放大,缩小适用于指针和引用.

下面这个可以吗??

#include<iostream>
using namespace std;

int main()
{
	int i = 0;
	 double& rd = i;

}

强制类型转换是将i的值做强制类型转换后的值存在一个临时变量中,而这里的rd是临时变量的别名,而不是i的别名,临时变量具有常性,也就是只读,这里属于权限放大了,加上const的话属于权限平移.

#include<iostream>
using namespace std;

int main()
{
	int i = 0;
	const double& rd = i;

}

引用和指针的区别

在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间.在底层实现上实际是有空间的,因为引用是按照指针方式来实现的.

引用和指针的不同点:

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  4. 没有NULL引用,但有NULL指针
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全

内联函数

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。

内联函数的引出
我们之前学过宏定义函数

#include<iostream>
using namespace std;
#define ADD(a,b) ((a)+(b))
int main()
{
	int ret=ADD(1, 2);
	printf("%d", ret);

}

宏定义的函数不用创建栈帧.
但是宏定义的函数只能是死替换

#include<iostream>
using namespace std;
#define ADD(a,b) (a*b)
int main()
{
	int ret=ADD(1+2, 2+3);
	printf("%d", ret);

}

这样死套就会出错,内联函数的引入,也不会创建栈帧

#include<iostream>
using namespace std;
int add(int a, int b)
{
	int c = a + b;
	return c;

}
int main()
{
	int ret = add(1, 2);
	return ret;


	

}

在这里插入图片描述

对应汇编语言有call指令说明有创建栈帧.


使用inline函数是否创建栈帧
查看方式:

  1. 在release模式下,查看编译器生成的汇编代码中是否存在call Add
  2. 在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不
    会对代码进行优化,以下给出vs2013的设置方式)
    在这里插入图片描述
    使用inline函数后没有call指令,说明没有创建栈帧
    在这里插入图片描述
    inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
    inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性.
    在这里插入图片描述
#include<iostream>
using namespace std;
 inline int add(int a, int b)
{
	int c = a + b;
	c = a + b;
	c = a + b;
	c = a + b;
	c = a*b;
	c = a*b;
	c = a + b;
	c = a + b;
	return c;

}
int main()
{
	int ret = add(1, 2);
	return ret;


	

}

在这里插入图片描述
此函数没有liline展开成函数体,有call指令,创建了函数栈帧.


面试题

宏的优缺点?
优点:
1.增强代码的复用性。
2.提高性能。

缺点:
1.不方便调试宏。(因为预编译阶段进行了替换)
2.导致代码可读性差,可维护性差,容易误用。
3.没有类型安全的检查 。

C++有哪些技术替代宏
短小函数定义 换用内联函数

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gz-hamonic 安装提示缺少许多依赖无法安装

在软件更新源中增加gz-hamonic的软件源&#xff0c; 点击添加&#xff0c;在输入框中填入如下语句&#xff1a; deb http://packages.osrfoundation.org/ubuntu jammy main 如图所示&#xff1a; 然后执行 sudo apt -get install gz-hamonic即可安装。 如下图 在终端中输入…

FFmpeg调用MediaCodec解码

在前面的博文中我们介绍了关于使用NDK编译FFMpeg6.0的一些坑以及相关的解决方法。 详情请参考&#xff1a;NDK编译ffmpeg6.0与x264的坑 在写《NDK编译ffmpeg6.0与x264的坑》一文的时候就说过了&#xff0c;我们编译FFmpeg6.0的目的就是为了体验一下它NDK式的MediaCodec硬解码…

密码学:一文看懂初等数据加密一对称加密算法

文章目录 对称加密算法简述对称加密算法的由来对称加密算法的家谱数据加密标准-DES简述DES算法的消息传递模型DES算法的消息传递过程和Base64算法的消息传递模型的区别 算法的实现三重DES-DESede三重DES-DESede实现 高级数据加密标准一AES实现 国际数据加密标准-IDEA实现 基于口…

启发式算法解决TSP、0/1背包和电路板问题

1. Las Vegas 题目 设计一个 Las Vegas 随机算法&#xff0c;求解电路板布线问题。将该算法与分支限界算法结合&#xff0c;观察求解效率。 代码 python代码如下&#xff1a; # -*- coding: utf-8 -*- """ Date : 2024/1/4 Time : 16:21 Author : …

Java爬虫获取省市区镇村5级行政区划

公司有个项目需要五级行政区划,没有现成的数据,写了一段代码,从gj统计j获取的数据。记录一下。 1.引入maven解析html <!-- jsoup --> <dependency><groupId>org.jsoup</groupId><artifactId>jsoup</artifactId><version>1.11.3&…

微信小程序自动化测试实战,支持录制回放、智能遍历

​为了满足小程序性能、功能等方面的测试需求&#xff0c;微信团队上线 小程序云测服务&#xff0c;提供丰富的自动化测试能力。其中 智能化 Monkey 服务 凭借着零代码、低成本的优势吸引不少开发者使用。 在服务使用过程中&#xff0c;我们发现开发者有更多的进阶需求&#x…

OAI openair3代码结构整理

openair3代码框架结构 OAI&#xff08;OpenAirInterface&#xff09;是一个开源的5G网络软件平台&#xff0c;用于研究和开发5G网络技术。OpenAir3是OAI项目中的一个子项目&#xff0c;专注于5G核心网络的功能实现。 一、OpenAir3的代码主要包括以下几个部分&#xff1a; NAS…

Proxmox VE 8 安装开源监控平台Centreon 23

作者&#xff1a;田逸&#xff08;formyz&#xff09; 非常好用的开源监控系统Centreon从版本号21.40以后&#xff08;包括Centreon 21.40这个版本&#xff09;&#xff0c;不在提供ISO一键式安装包&#xff0c;取而代之的是在线脚本安装和VMware虚拟机或者Oracle VirtualBox 虚…

初识MySQL

一、什么是数据库 数据库&#xff08;Database&#xff0c;简称DB&#xff09;&#xff1a;长期存放在计算机内&#xff0c;有组织、可共享的大量数据的集合&#xff0c;是一个数据“仓库”。 数据库的作用&#xff1a; 可以结构化存储大量的数据&#xff0c;方便检索和访问…

2024最新Java基础面试题大全(一)

1、String可以被继承&#xff1f; 不能被继承&#xff0c;因为String类有final修饰符&#xff0c;而final修饰的类是不能被继承的。 public final class String implements java.io.Serializable, Comparable<String>, CharSequence {// 省略...  }2、常见集合类 Java…

ChatGPT到底能做什么呢?

1、熟练掌握ChatGPT提示词技巧及各种应用方法&#xff0c;并成为工作中的助手。 2、通过案例掌握ChatGPT撰写、修改论文及工作报告&#xff0c;提供写作能力及优化工作 3、熟练掌握ChatGPT融合相关插件的应用&#xff0c;完成数据分析、编程以及深度学习等相关科研项目。 4、…

深入理解Vue3中的自定义指令

Vue3是一个流行的前端框架&#xff0c;它引入了许多新特性和改进&#xff0c;其中之一是自定义指令。自定义指令是一种强大的功能&#xff0c;可以让开发者在模板中直接操作 DOM 元素。本文将深入探讨 Vue3中的自定义指令&#xff0c;包括自定义指令的基本用法、生命周期钩子函…

【fiddler】fiddler抓包工具的使用

前言&#xff1a;我们可以通过fiddler软件&#xff0c;捕获到http请求&#xff0c;并修改请求参数 修改返回内容 fiddler下载,官网如下图 启动fiddler软件,点击file 选择 Capture Traffic 修改入参 (我们以谷歌浏览器发起请求为例) 此时会出现一个向上的箭头&#xff0c;点击…

MediaPipeUnityPlugin Win10环境搭建(22年3月的记录,新版本已完全不同,这里只做记录)

https://github.com/homuler/MediaPipeUnityPlugin You cannot build libraries for Android with the following steps. 1、安装msys2配置系统环境变量Path添加 C:\msys64\usr\bin 执行 pacman -Su 执行 pacman -S git patch unzip 2、安装Python3.9.10 勾选系统环境变量 …

stm32学习总结:6、Proteus8+STM32CubeMX+MDK仿真蜂鸣器及ADC读取电压(Proteus标签整理原理图)

stm32学习总结&#xff1a;6、Proteus8STM32CubeMXMDK仿真蜂鸣器及ADC读取电压&#xff08;Proteus标签整理原理图&#xff09; 文章目录 stm32学习总结&#xff1a;6、Proteus8STM32CubeMXMDK仿真蜂鸣器及ADC读取电压&#xff08;Proteus标签整理原理图&#xff09;一、前言二…

智能革命:揭秘AI如何重塑创新与效率的未来

1.AI技术的发展与应用 1.1 AI技术的发展 人工智能&#xff08;AI&#xff09;的概念最早可以追溯到20世纪40年代和50年代&#xff0c;当时的计算机科学家开始探索如何创建能模仿人类智能的机器。最初的AI研究集中在问题解决和符号逻辑上&#xff0c;但随着时间的推移&#xf…

若依前后端分离版关联字典值查询数据工具类使用

场景 若依管理系统导出Excel时添加没有的列和关联码表显示中文进行导出&#xff1a; 若依管理系统导出Excel时添加没有的列和关联码表显示中文进行导出_若依的导出添加额外的字段信息-CSDN博客 上面通过关联表的方式实现查询字典值&#xff0c;若依本身提供了查询redis中缓存…

透明OLED屏的稳定性:从技术角度及应用案例解析

在显示技术日新月异的今天&#xff0c;透明OLED屏以其独特的透明特性和出色的显示效果&#xff0c;吸引了众多关注。然而&#xff0c;对于这种新型技术的稳定性&#xff0c;人们难免会有所疑虑。作为一名专注于OLED技术研发的工程师&#xff0c;尼伽小编将从专业角度出发&#…

阿里云大模型「让照片跳舞」刷屏朋友圈,有哪些信息值得关注?

介绍 大家好&#xff0c;我分享聊聊阿里通义千问APP中全民舞王功能。 网络热舞结合AI视频&#xff0c;这是以后不用学习跳舞&#xff1f; 可以尝试下效果&#xff0c;一张图片生成视频。 APP快速使用 搜索下载通义千问APP 打开APP&#xff0c;选中一张照片来跳舞。 这里…

css单位介绍

当我们在编写网页或应用程序时&#xff0c;选择合适的单位来描述元素的尺寸是非常重要的。在CSS中&#xff0c;我们常常会使用像素(px)、相对像素(rpx)、字号单位(em)、根元素字号单位(rem)、百分比(%)和视口百分比(vh、vw)等单位来描述元素的大小。 像素(px)是最常见的单位&a…