C语言向C++过渡的基础知识(三)

news2024/11/20 13:45:49

目录

auto类型变量(C++11标准支持)

auto关键字介绍

auto关键字的使用

auto关键字基本使用

auto关键字配合指针和引用

auto关键字不可以推导的场景

基于范围的for循环(C++11标准支持)

基于范围的for循环基础使用

基于范围的for循环使用条件

空指针值(C++11标准支持)


声明:本篇时C语言向C++过渡的基础知识的最后一篇

auto类型变量(C++11标准支持)

auto关键字介绍

随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在:

  1. 类型难于拼写
  2. 含义不明确导致容易出错

例如下面的代码中

#include <string>
#include <map>
int main()
{
    std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange", 
"橙子" }, 
                                       {"pear","梨"} };
    std::map<std::string, std::string>::iterator it = m.begin();
    while (it != m.end())
    {
        //....
    }
    return 0;
}

可以用typedef来处理上面的问题,但是typedef也有别的问题

#include <string>
#include <map>
typedef std::map<std::string, std::string> Map;
int main()
{
    Map m{ { "apple", "苹果" },{ "orange", "橙子" }, {"pear","梨"} };
    Map::iterator it = m.begin();
    while (it != m.end())
    {
        //....
    }
    return 0;
}

考虑下面的问题

typedef char* pstring;
int main()
{
    const pstring p1;    // 编译失败,展开后为char* const p1,作为const修饰的变量为常量,只有一次赋值的机会,故需要初始化
    const pstring* p2;   // 编译通过
    return 0;
}

auto关键字的使用

auto关键字基本使用

在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量

在C++11标准中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得

使用auto关键字创建变量的语法如下:

auto 变量名;

auto创建的变量有自动推导类型的特点,例如下面的代码中

//auto关键字
#include <iostream>
using namespace std;

int main()
{
    int a = 0;
    auto b = a;//b自动推导为int类型
    double c = 0.0;
    auto d = c;//c自动推导为double类型

    cout << "a变量的类型为:" << typeid(a).name() << endl;
    cout << "b变量的类型为:" << typeid(b).name() << endl;
    cout << "c变量的类型为:" << typeid(c).name() << endl;
    cout << "d变量的类型为:" << typeid(d).name() << endl;

    return 0;
}
输出结果:
a变量的类型为:int
b变量的类型为:int
c变量的类型为:double
d变量的类型为:double

在上面的代码中,创建了两个普通对象ac,使用auto关键字创建了两个对象bd,分别自动匹配了ac的类型为intdouble,使用typeid.name()查看变量类型

需要注意的是,使用auto创建的变量一定要初始化,否则编译器无法推导该变量的类型从而报错

//auto关键字
#include <iostream>
using namespace std;

int main()
{
    auto e;// 报错

    return 0;
}
报错信息:
“e”: 类型包含“auto”的符号必须具有初始值设定项

所以,auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型

使用auto关键字可以同时创建多个变量,但是必须保证一个auto关键字创建的多个变量匹配一种类型,不可以auto匹配多个类型

#include <iostream>
using namespace std;

int main()
{
    auto a = 1, b = 2, c = 3, d = 4;//所有变量匹配为int类型
    auto f = 2.0, g = 2;//不可以同时匹配多个类型

    return 0;
}
报错信息:
在声明符列表中,“auto”必须始终推导为同一类型

auto关键字配合指针和引用

auto关键字创建的变量也可以自动推导为指针和引用类型,也可以直接将auto关键字创建的变量指定为指针和引用类型,用auto声明指针类型时,用autoauto*没有任何区别,但用auto声明引用类型时则必须加&

如下

//auto关键字配合指针和引用
#include <iostream>
using namespace std;

int main()
{
    int a = 0;
    int* p = &a;
    auto p1 = p;//自动推导为int*类型
    auto* p2 = p;//指定为int*类型
    //auto* p3 = a;//不可以推导
    auto r1 = a;//自动推导为int类型
    auto& r2 = a;//指定为引用类型

    return 0;
}

编译器指示如下:

auto关键字不可以推导的场景

  • auto关键字创建的变量不可以作为函数形参
void test(auto a)
{

}

#include <iostream>
using namespace std;

int main()
{
    test(1);
    return 0;
}
报错信息:
参数不能为包含“auto”的类型
  • auto不能直接用于声明数组
#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1,2,3,4,5 };
    auto arr1[] = { 1,2,3,4,5 };//不可以直接用来创建数组

    return 0;
}
报错信息:
“auto”类型不能出现在顶级数组类型中

但是可以获取到数组的地址

#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1,2,3,4,5 };
    auto arr1 = arr;//可以将已经创建的数组给auto创建的变量,自动匹配为int*
    cout << "arr1:" << typeid(arr1).name() << endl;
    for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
    {
        cout << "arr1[i]:" << arr1[i] << endl;
    }

    return 0;
}
输出结果:
arr1:int * __ptr64
arr1[i]:1
arr1[i]:2
arr1[i]:3
arr1[i]:4
arr1[i]:5

基于范围的for循环(C++11标准支持)

基于范围的for循环基础使用

在C++98中需要按照常规方式进行数组的遍历,例如

#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1,2,3,4,5 };
    for (int i = 0; i < sizeof(arr)/sizeof(int); i++)
    {
        cout << arr[i] << " ";
    }

    return 0;
}
输出结果:
1 2 3 4 5

但是在C++11中可以按照下面的方式进行遍历

#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1,2,3,4,5 };

    for (int num : arr)
    {
        cout << num << " ";
    }

    return 0;
}

在上面的for循环中,创建了一个num变量,将数组中的元素给num变量,再打印num变量

鉴于上面的过程说明,如果想用上面的方式修改数组中的元素则不会成功

#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1,2,3,4,5 };

    for (int num : arr)
    {
        num *= 2;
        cout << num << " ";
    }
    cout << endl;
    for (int num : arr)
    {
        cout << num << " ";
    }

    return 0;
}
输出结果:
2 4 6 8 10
1 2 3 4 5

此时可以配合引用进行原数组内容的修改

#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1,2,3,4,5 };

    for (int& num : arr)
    {
        num *= 2;
        cout << num << " ";
    }
    cout << endl;
    for (int num : arr)
    {
        cout << num << " ";
    }

    return 0;
}
输出结果:
2 4 6 8 10
2 4 6 8 10

📌

与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环

基于范围的for循环也可以使用auto创建循环变量

#include <iostream>
using namespace std;

int main()
{
    int arr[] = { 1,2,3,4,5 };

    for (auto num : arr)
    {
        cout << num << " ";
    }
    cout << endl;
    for (auto& num : arr)
    {
        num *= 2;
        cout << num << " ";
    }

    return 0;
}
输出结果:
1 2 3 4 5
2 4 6 8 10

基于范围的for循环使用条件

for循环迭代的范围必须是确定的

#include <iostream>
using namespace std;
void test(int* arr)
{
    for (auto num : arr)
    {
        cout << num << " ";//不可以遍历,因为无法确定范围,数组在传参时只会传递第一个元素的地址
    }
}

int main()
{
    int arr[] = { 1,2,3,4,5 };
    test(arr);
    return 0;
}

空指针值(C++11标准支持)

在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,基本都是按照如下方式对其进行初始化:

void TestPtr()
{
 int* p1 = NULL;
 int* p2 = 0;
 
 // ……
}

NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

在上面的宏定义中,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量,不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如在函数重载中可能会使编译器匹配参数为整型的函数,而不是参数为指针类型的函数:

#include <iostream>
using namespace std;

void test(int a)
{
    cout << "匹配int类型形参" << endl;
}

void test(int* a)
{
    cout << "匹配int*类型形参" << endl;
}

int main()
{
    test(0);
    test(NULL);
    return 0;
}
输出结果:
匹配int类型形参
匹配int类型形参

此时为了使形参匹配到指针类型,必须将NULL或者0强制转换为(void*)类型

void test(int a)
{
    cout << "匹配int类型形参" << endl;
}

void test(void* a)
{
    cout << "匹配int*类型形参" << endl;
}

int main()
{
    test(0);
    test((void*)NULL);
    return 0;
}

为了解决上面的问题,C++11标准中提出了nullptr用于指定指针空值

#include <iostream>
using namespace std;

void test(int a)
{
    cout << "匹配int类型形参" << endl;
}

void test(int* a)
{
    cout << "匹配int*类型形参" << endl;
}

int main()
{
    test(0);
    //test((void*)NULL);
    test(nullptr);
    return 0;
}
输出结果:
匹配int类型形参
匹配int*类型形参

在使用nullptr时注意下面的三点:

  1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
  2. 在C++11中,sizeof(nullptr)sizeof((void*)0)所占的字节数相同。
  3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr
#include <iostream>
using namespace std;

int main()
{
    cout << "sizeof(NULL):" << sizeof(NULL) << endl;
    cout << "sizeof(nullptr):" << sizeof(nullptr) << endl;
    cout << "sizeof((void*)0):" << sizeof((void*)0) << endl;
    return 0;
}
输出结果:
sizeof(NULL):4
sizeof(nullptr):8
sizeof((void*)0):8

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

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

相关文章

语音识别:whisper部署服务器(远程访问,语音实时识别文字)

Whisper是OpenAI于2022年发布的一个开源深度学习模型&#xff0c;专门用于语音识别任务。它能够将音频转换成文字&#xff0c;支持多种语言的识别&#xff0c;包括但不限于英语、中文、西班牙语等。Whisper模型的特点是它在多种不同的音频条件下&#xff08;如不同的背景噪声水…

【Linux杂货铺】进程的基本概念

目录 &#x1f308;前言&#x1f308; &#x1f4c1;进程的概念 &#x1f4c2;描述进程-PCB &#x1f4c2; 查看进程 &#x1f4c2; 查看正在运行的程序 &#x1f4c2;杀死进程 &#x1f4c2;通过系统调用获取进程标识符 &#x1f4c2;通过系统调用创建进程 &#x1f…

HCIA——TCP协议详解

目录 1、TCP概念及协议头部格式 1.1TCP特点 1.2TCP协议协议头部格式 1.3字段进行介绍 1.3.1源端口和目的端口 1.3.2序号(seq) 1.3.3确认序号(ack) 1.3.4数据偏移 1.3.5标志位 1.3.6窗口 1.3.7校验和 1.3.8紧急指针 2、TCP的可靠性 2.1 TCP可靠性的保障 2.2排序机…

论文阅读_参数微调_P-tuning_v2

1 P-Tuning PLAINTEXT 1 2 3 4 5 6 7英文名称: GPT Understands, Too 中文名称: GPT也懂 链接: https://arxiv.org/abs/2103.10385 作者: Xiao Liu, Yanan Zheng, Zhengxiao Du, Ming Ding, Yujie Qian, Zhilin Yang, Jie Tang 机构: 清华大学, 麻省理工学院 日期: 2021-03-18…

unityprotobuf自动生成C#

Release Protocol Buffers v3.19.4 protocolbuffers/protobuf GitHub 导入Source code 里面的 csharp/src/Google.Protobuf 进入Unity 拷贝其他版本的 System.Runtime.CompilerServices.Unsafe进入工程 使用protoc-3.19.4-win32 里面的exe去编译proto文件为C# using Sys…

软件测试相关内容第四弹 -- 测试用例与测试分类

写在前&#xff1a;我们已经掌握了关于软件测试的相关内容&#xff0c;知道了基本的测试过程&#xff0c;在做了一段时间的基础测试&#xff0c;熟悉了相关的业务后&#xff0c;测试人员会进行测试用例的编写&#xff0c;在日常测试中&#xff0c;也需要补充测试用例到现有的案…

HCIP —— 交换 (VLAN)

VLAN --- 虚拟局域网 在 HCIA 中 &#xff0c;已经学过交换机的一些基础配置&#xff0c;下面进行回顾一些简单的内容。 1.创建VLAN VLAN ID --- 区别和标识不同的VLAN 使用范围&#xff1a;0-4095 &#xff0c; 由12位二进制构成。 0 和 4095 作为 保留的VLAN。 …

静默安装OGG21.3微服务版本FOR ORACLE版本

静默安装OGG21.3微服务版本FOR ORACLE版本 silent install ogg21.3 for oracle 某度找来找去都没有找到一份可靠的静默安装OGG21.3微服务版本的案例&#xff0c;特别难受&#xff0c;为此将自己静默安装的步骤一步步贴出来分享给大家&#xff0c;请指点&#xff0c;谢谢。 至…

【生态适配】亚信安慧AntDB数据库与龙芯3C5000L完成兼容互认

日前&#xff0c;亚信安慧AntDB数据库系统V6.2在龙芯3C5000L平台上完成兼容性测试&#xff0c;功能与稳定性良好&#xff0c;被授予龙架构兼容互认证书。 图1&#xff1a;产品兼容性证明 随着“互联网”的纵深发展&#xff0c;数字技术创新成果与经济社会各领域深度融合&#…

电玩体验店怎么计时,佳易王ps5计时计费管理控制系统操作教程

电玩体验店怎么计时&#xff0c;佳易王ps5计时计费管理控制系统操作教程 一、前言 以下软件操作教程以 佳易王电玩计时计费管理系统软件V17.9为例说明 件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、电玩体验馆管理软件在计时的同时可以设置定时提醒&…

Java两周半速成之路(第十六天)

一、网络编程 1.概述&#xff1a; 就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换 2.网络模型 3.网络参考模型图 4.网络通信三要素 4.1IP地址 InetAddress类的使用&#xff1a; 注意&#xff1a;通过API查看&#xff0c;此类没有构造方法&#xff0c;如…

Spring Boot Starter: 快速简明地创建Spring应用

Spring Boot Starter是Spring Boot的核心功能之一&#xff0c;它帮助开发人员快速简明地创建、配置和运行Spring应用。在本文中&#xff0c;我们将详细介绍Spring Boot Starter以及如何使用它创建一个Spring Boot应用。 文章目录 什么是Spring Boot Starter?为何使用Spring B…

jetson nano——编译一些包的网址导航,pyside2,qt(持续更新)

目录 1.PySide2下载地址2.tesserocr下载地址3.Qt下载地址4.OpenSSL官网5.latex编译器下载地址5.1MikTex5.2TeX Live 1.PySide2下载地址 https://download.qt.io/official_releases/QtForPython/pyside2/ 如下图&#xff1a; 2.tesserocr下载地址 https://github.com/simonflue…

【送书福利第五期】:ARM汇编与逆向工程

文章目录 &#x1f4d1;前言一、ARM汇编与逆向工程1.1 书封面1.2 内容概括1.3 目录 二、作者简介三、译者介绍&#x1f324;️、粉丝福利 &#x1f4d1;前言 与传统的CISC&#xff08;Complex Instruction Set Computer&#xff0c;复杂指令集计算机&#xff09;架构相比&#…

进入docker容器中安装软件失败解,国外源慢,时间不同步,执行命令权限不够等问题解决办法

进入docker容器中安装软件失败解&#xff0c;时间不同步, 国外源慢&#xff0c;执行命令权限不够 等问题解决办法 首先我进入docker容器中&#xff0c;为了安装一个软件&#xff0c;引出了很多报错问题&#xff0c;报错如下&#xff1a; 1、无法用 ifconfig 或者 ip addr 的方…

Ansible自动化运维Inventory与Ad-Hoc

前言 自动化运维是指利用自动化工具和技术来简化、自动化和优化IT基础设施的管理和运维过程&#xff0c;从而提高效率、降低成本&#xff0c;并减少人为错误。在当今复杂的IT环境中&#xff0c;自动化运维已经成为许多组织和企业提高生产力和保证系统稳定性的重要手段。Ansibl…

Kubernetes operator系列:kubebuilder 实战演练 之 开发多版本CronJob

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes operator学习 系列文章&#xff0c;本节会在上一篇开发的Cronjob基础上&#xff0c;进行 多版本Operator 开发的实战 本文的所有代码&#xff0c;都存储于github代码库&#xff1a;https://github.c…

three.js 元素周期表,可鼠标控制

一些文章里的元素周期表,能显示,但控制器却无法使用,周期表没法旋转 后来发现是three.js版本问题, 旧版本在调试状态下是可以旋转的。新版本只要在正常页面打开状态下就能鼠标控制 <!DOCTYPE html> <html> <head> <meta charset="utf-8"&…

网盘聚合工具:统筹管理所有网盘资源 | 开源日报 No.203

alist-org/alist Stars: 35.6k License: AGPL-3.0 alist 是一个支持多存储的文件列表/WebDAV 程序&#xff0c;使用 Gin 和 Solidjs。 该项目的主要功能、关键特性、核心优势包括&#xff1a; 支持多种存储方式易于部署和开箱即用文件预览&#xff08;PDF、markdown、代码等&…

Jmeter文件上传不成功问题

前言 最近好忙呀&#xff0c;项目上线然后紧接着又客户培训了&#xff0c;由于项目有个模块全是走配置的&#xff0c;所以导致问题不断&#xff0c;近期要培训为了保障培训时客户同时操作的情况&#xff0c;所以把我从功能端抽出来做压测了&#xff0c;之前安排了2个同事写压测…