【c++】入门3

news2024/11/18 7:45:41

引用

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++有哪些技术替代宏
短小函数定义 换用内联函数

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

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

相关文章

数据库设计——DML

D M L \huge{DML} DML DML&#xff1a;数据库操作语言&#xff0c;用来对数据库中的数据进行增删改查。 增&#xff08;INSERT&#xff09; 使用insert来向数据库中增加数据。 示例&#xff1a; -- DML : 数据操作语言 -- DML : 插入数据 - insert -- 1. 为 tb_emp 表的 us…

烟花燃放如何管控?智能分析网关V4烟火检测保障烟火安全

一、方案背景 随着元旦佳节的热潮退去&#xff0c;春节也即将来临&#xff0c;在众多传统的中国节日里&#xff0c;烟花与烧纸祭祀都是必不可少的&#xff0c;一方面表达了人们对节日的庆祝的期许&#xff0c;另一方面也是一种对故者思念的寄托。烟花爆竹的燃放不仅存在着巨大的…

SparkSQL基础解析(三)

1、 Spark SQL概述 1.1什么是Spark SQL Spark SQL是Spark用来处理结构化数据的一个模块&#xff0c;它提供了2个编程抽象&#xff1a;DataFrame和 DataSet&#xff0c;并且作为分布式SQL查询引擎的作用。 我们已经学习了Hive&#xff0c;它是将Hive SQL转换成MapReduce然后提…

【springboot+vue项目(十一)】springboot整合EasyExcel

EasyExcel是阿里巴巴开源的一个Java库&#xff0c;用于操作Excel文件。它提供了简单易用的API&#xff0c;可以读取、写入和转换Excel文件&#xff0c;支持大量数据的导入和导出操作。 一、添加依赖&#xff08;版本3.2&#xff09; <!--easyexcel操作excel--> <depe…

风靡全网的Jmeter+ant+jenkins接口自动化测试框架

大致思路&#xff1a;Jmeter可以做接口测试&#xff0c;也能做压力测试&#xff0c;而且是开源软件&#xff1b;Ant是基于Java的构建工具&#xff0c;完成脚本执行并收集结果生成报告&#xff0c;可以跨平台&#xff0c;Jenkins是持续集成工具。将这三者结合起来可以搭建一套We…

Prometheus 不能访问k8s的中的一些metrics的问题(controller-manager、scheduler、etcd)

主要有三个点 controller-manager、scheduler、etcd 参考&#xff1a; https://www.cnblogs.com/ltaodream/p/15448953.html kube-scheduler 在每台master节点执行 vim /etc/kubernetes/manifests/kube-scheduler.yaml 将 --bind-address127.0.0.1 改为 --bind-address…

基于SSM框架的宠物商城系统

开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.9 功能模块&…

软件测试|一篇文章带你深入理解SQL约束

深入理解SQL约束&#xff1a;保障数据完整性和一致性的重要工具 SQL约束是在关系型数据库中用于保障数据完整性和一致性的重要工具。本文将深入探讨SQL约束的概念、类型以及应用&#xff0c;以帮助读者更好地理解和使用SQL约束来确保数据库中的数据质量。 SQL约束 约束&…

vue动态组件、保持存活

加 component :is 引入组件名称 <component :is"tabcom"></component> keep-alive 保持存活 <keep-alive> <component :is"tabcom"></component></keep-alive> 保持存活&#xff1a;切换组件后&#xff0c;不重…

人机交互主板定制_基于MT8735安卓核心板的自助查询机方案

人机交互主板是一种商显智能终端主板&#xff0c;广泛应用于广告机、工控一体机、教学一体机、智能自助终端、考勤机、智能零售终端、O2O智能设备、取号机、计算机视觉、医疗健康设备、机器人设备等领域。 人机交互主板采用联发科MTK8735芯片平台&#xff0c;四核Cortex-A53架构…

Sectigo与Geotrust ov多域名证书的区别

Sectigo和Geotrust都是比较知名的CA认证机构。其中&#xff0c;Sectigo原名Comodo&#xff0c;在2018年整合SSL证书业务&#xff0c;改名为Sectigo&#xff0c;旗下的SSL证书产品根证书也变为Sectigo。Geotrust则是另一个备受信任的数字证书品牌&#xff0c;现在是Digicert旗下…

Python Gradio构建简单的交互界面

Gradio 是一个用于构建机器学习和数据科学的交互式应用程序的 Python 库&#xff0c;但是我们可以用它来构建一些简单的交互界面&#xff0c;其代码之简单令人震惊 文本输入输出 import gradio as grdef szu(text):return textinterface gr.Interface(fnszu, inputs"text…

43 tmpfs/devtmpfs 文件系统

前言 在 linux 中常见的文件系统 有很多, 如下 基于磁盘的文件系统, ext2, ext3, ext4, xfs, btrfs, jfs, ntfs 内存文件系统, procfs, sysfs, tmpfs, squashfs, debugfs 闪存文件系统, ubifs, jffs2, yaffs 文件系统这一套体系在 linux 有一层 vfs 抽象, 用户程序不用…

keras 深度学习框架实现 手写数字识别

阅读本文之前&#xff0c;请先参考--------win10搭建keras深度学习框架 安装运行环境 阅读本文之前&#xff0c;请先参考--------keras人工智能框架 MNIST 数据集 随机展示 查看训练图片 完整代码如下图&#xff1a; 在sublimeText中 使用ctrlB运行代码&#xff0c;结果如…

没有一家车企能绕开「数据闭环」

作者 |张祥威 编辑 |德新 2023年&#xff0c;在比亚迪那次公布智驾数据规模后&#xff0c;智能化下半场的战斗就正式打响了。 如今&#xff0c;自动驾驶正在沿着特斯拉提出的「BEVTransformer」急速推进&#xff0c;这条技术路线短短几年就得到了验证&#xff0c;随着智驾起较…

报表控件Stimulsoft 2023回顾:都做了哪些产品的改变?

在2023年过去一年中&#xff0c;报表控件Stimulsoft 针各类控件都做了重大改变&#xff0c;其中新增了某些产品、同时加强了很多产品的性能和UI设计&#xff0c;更加符合开发者需求&#xff0c;下面就跟随小编一起来回顾&#xff0c;具体都有哪些↓↓↓ Stimulsoft Ultimate &…

静图如何做成动态gif图?手把手教你一招制作

我们在跟小伙伴聊天时&#xff0c;都会发送gif动图&#xff0c;能够让我们的心情更加开心。当我们找不到合适的图片时&#xff0c;就可以自己制作专属于自己的gif动图&#xff0c;那么怎能操作呢&#xff1f;很简单&#xff0c;通过使用gif在线生成&#xff08;https://www.gif…

MIT_线性代数笔记:第 24 讲 马尔可夫矩阵;傅里叶级数

目录 马尔可夫矩阵 Markov matrices傅里叶级数 Fourier series 本讲学习马尔可夫矩阵和傅里叶级数&#xff0c;两者是关于特征值和投影矩阵的应用。 马尔可夫矩阵 Markov matrices A [ 0.1 0.01 0.3 0.2 0.99 0.3 0.7 0 0.4 ] A \begin{bmatrix} 0.1 & 0.01 & 0.3 \\…

Python爬虫实战技巧:如何在爬取过程中动态切换代理IP

目录 前言 第一步&#xff1a;获取代理IP列表 第二步&#xff1a;测试代理IP的可用性 第三步&#xff1a;动态切换代理IP 总结 前言 在进行爬虫开发的过程中&#xff0c;有时候需要使用代理IP来访问目标网站&#xff0c;以避免被封IP或者降低访问频率的限制。本文将介绍如…

菜单显示博客页

结果图 难点及其实现 滚动条自定义&#xff1a; .card::-webkit-scrollbar { width: 4px;} .card::-webkit-scrollbar-thumb { border-radius: 8px; box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); background: #666666; } .card::-webkit-scrollbar-thumb:hover { backgr…