C++ Primer学习笔记 第2章 变量和基本类型

news2024/9/23 15:31:22

2.1 基本内置类型

2.1.2 类型转换

首先了解下取模和取余的区别!!![取模与取余的区别]

  1. 当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。如8bit大小的unsigned char 可以表示0到255区间内的值,当把-1赋给8bit大小的unsigned char所得到的结果是255.
  2. 当我们赋值给带符号类型一个超出它表示范围的值时,结果是未定义的。此时程序可能继续工作,可能崩溃,也可能产生垃圾数据。

提示:切勿混用带符号类型和无符号类型

2.1.3 字面值常量

2.2 变量

2.2.1 变量定义

初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来代替。

用花括号来初始化变量,这种初始化形式称为列表初始化。这种初始化形式有一个重要的特点:如果我们使用列表初始化且初始值存在丢失的风险,则编译器将报错。

long double ld = 3.1415926536;
int a{ld}, b = {ld}; //错误:转换未执行,因为存在丢失信息的风险
int c(ld), d = (ld); //正确:转换执行,确实丢失部分值

cout << a << " , " << b << endl;
cout << c << " , " << d << endl;

 但是使用不同的编译器会发生不同的处理情况:

VS 2019 msvc编译器:

VSCode MinGW-64 G++ 编译器:

 如果定义一个变量时没有指定初值,则变量被默认初始化。定义于任何函数体之外的变量被初始化为0。定义在函数体内部的变量将不被初始化。一个未初始化的变量的值是未定义的,如果试图拷贝或者以其他形式访问此类值将引发错误。

建议初始化每一个内置类型的变量。虽然并非必须这么做,但如果我们不能确保初始化后程序安全,那么这么做不失为一种简单可靠的办法。

2.2.2 变量声明与定义的关系

如果想声明一个变量而非定义它,就在变量名前加关键字extern,而且不要显示地初始化变量:
 

extern  int i; //声明i而非定义i

int j; //声明并定义j

extern  int pi = 3.1415926; //定义

在函数体内部,如果试图初始化一个由extern关键字标记的变量,将引发错误。

 变量能且只能被定义一次,但是可以多次被声明!

如果要在多个文件中使用同一个变量,就必须将声明和定义分离。此时,变量的定义必须出现在且只能出现在一个文件中,而其它用到该变量的文件必须对其进行声明,却绝对不能重复定义。

2.2.3 标识符

C++的标识符有数字,字母和下划线组成,其中必须以字母或下划线开头。用户自定义的标识符中不能连续出现两个下划线,也不能以下划线紧连大写字母开头。此外,定义在函数体外的标识符不能以下划线开头。

变量命名规范

- 标识符要能体现实际含义。

- 变量名一般用小写字母,如index,不要使用Index或INDEX

- 用户自定义的类名一般以大写字母开头,如Sales_item。

- 如果标识符有多个单词组成,则单词间应有明显区分,如student_loan 或 studentLoan

2.2.4 名字的作用域

2.3 复合类型

本章主要介绍其中的两种:引用和指针

2.3.1 引用

引用必须被初始化!

除了两种例外情况,其它所有引用的类型都要和与之绑定的对象严格匹配。而且,引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。

int &ref = 10; //错误,引用类型的初始值必须是一个对象
double dval = 3.14;
int &ref2 = dval; //错误,此处引用类型的初始值必须是int类型对象

特殊情况:

1. const int &r2 = 42; // ok: r1 is a reference to const

2. TO-DO

2.3.2 指针

第一,指针本身就是一个对象,允许对指针进行赋值和拷贝,而且指针的生命周期内它可以先后指向几个不同的对象。第二,指针无须在定义时赋初值。和其它内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。

获取对象的地址

指针存放某个对象的地址,要想获取该地址,需要使用取地址符(&):

int ival = 42;
int *p = &ival; // p存放变量ival的地址,或者说p是指向变量ival的指针

一般情况下,指针的类型和它所指向的对象严格匹配。

指针值

指针的值(即地址)应属于下列四种状态之一:

1. 指向一个对象。

2. 指向紧邻对象所占空间的下一个位置。

3. 空指针,意味着指针没有指向任何对象。

4. 无效指针,也就是上述情况之外的其他值。

利用指针访问对象

解引用符(操作符*)

空指针

空指针(null pointer)不指向任何对象。几个生成空指针的方法:

int *p1 = nullptr; //等价于 int *p1 = 0
int *p2 = 0; //直接将p2初始化为字面常量0
//需要首先#include cstdlib
int *p3 = NULL; //等价于 int *p3 = 0

得到空指针最直接的办法就是用字面值nullptr来初始化指针,这也是C++11新标准引入的一种方法。nullptr是一种特殊类型的字面值,它可以被转换成任意其他的指针类型。

过去的程序还会用到一个名为NULL的预处理变量来给指针赋值,这个变量在头文件cstdlib中定义,它的值就是0。

当用到一个预处理变量时,预处理器会自动地将它替换为实际值,因此用NULL初始化指针和用0初始化指针是一样的。在新标准下,C++程序最好用nullptr,同时尽量避免使用NULL。

建议:初始化所有指针!

在可能的情况下,尽量等定义了对象后再定义指向它的指针。如果实在不清楚指针应该指向何处,就把它初始化为nullptr和0,这样程序就能知道它没有指向任何具体的对象了。

赋值和指针

有时候想搞清楚一条赋值语句到底是改变了指针的值还是改变了指针所指对象的值不太容易,最好的办法就是记住赋值永远改变的是等号左侧的对象

int i = 42;

int *pi = &i;

pi = &val; //pi的值被改变,现在pi指向了val。意思是为pi赋予一个新的值,也就是改变了那个存放在pi内的地址值

*pi = 0; //val的值被改变,指针pi并没有改变。则*pi(也就是指针pi指向的那个对象)发生改变



void* 指针

void * 是一种特殊的指针类型,可用于存放任意对象的地址。

面试题 指针和引用的主要区别?

答:指针“指向”内存中的某个对象,而引用“绑定”到内存中的某个对象。二者主要区别在两个方面:

第一,指针本身就是一个对象,能够对指针赋值和拷贝,而且在指针生命周期内它可以指向几个不同的对象;引用不是一个对象,无法令引用重新绑定到另外一个对象。

第二,指针无须在定义时赋初值,和其它内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值;引用则必须在定义时赋初值。

2.3.3 理解复合类型的声明

面向一条比较复杂的指针或引用的声明时,从右往左阅读有助于理解它真实的含义。

2.4 const 限定符

const对象一旦创建后其值就不能改变,所以const对象必须初始化。

const int bufSize = 512; //输入缓冲区大小

默认状态下,const对象仅在文件内有效。

如果想在多个文件中之间共享const对象,必须在变量的定义之前添加extern关键字。

解决办法就是,对于const变量不管是声明还是定义都添加extern关键字,这样只需定义一次就可以了:

//file_1.cc 定义并初始化一个常量,该常量能被其它文件访问
extern const int bufSize = fcn();

//file_1.h头文件
extern const int bufSize; //与file_1.cc定义的bufSize 是同一个

2.4.1 初始化和对const的引用

引用的类型必须与其所引用对象的类型一致,但其一中例外情况就是在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能够转换成引用的类型即可。

允许为一个常量引用绑定非常量的对象,字面值,甚至是个一般表达式:

int i = 42;
const int &r1 = i; //允许将const int &绑定到一个普通int对象上
const int &r2 = 42; //r2是一个常量引用
const int &r3 = r1 * 2; //r3是一个常量引用
int &r4 = r1 * 2; //错误,r4是一个普通的非常量引用

double dval = 3.14;
const int &ri = dval; 

2.4.2 指针与const

指向常量的指针不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针:

const double pi = 3.14; //
double *ptr = &pi; //错误,ptr是一个普通指针
const double *cptr = &pi;//正确
*cptr = 42; //错误,不能给*cptr赋值

const指针

常量指针必须初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了。即不变的是指针本身的值而非指向的那个值。

int errNumb = 0;
int *const curErr = &errNumb; //curErr将一直指向errNumb 
*curErr = 1;//正确 注意这点!
const double pi = 3.14;
const double *const pip = &pi; //pip是一个指向常量对象的常量指针

2.4.3 顶层const

指针本身是一个对象,它又可以指向另一个对象。因此指针本身是不是常量以及指针所指的是不是一个常量就是两个相互独立的问题。用名词顶层const表示指针本身是个常量,而用名词底层const表示指针所指的对象是一个常量。

指针类型既可以是顶层const,又可以是底层const。

int i = 0;
int *const p1 = &i; //不能改变p1的值,这是一个顶层const
const int ci = 42; //不允许改变ci的值,这是一个顶层const
const int *p2 = &ci; //允许改变p2的值,这是一个底层const
const int *const p3 = p2; //靠右的const是顶层const,靠左的const是底层const

2.4.4 constexpr和常量表达式

常量表达式是指值不会改变并且在编译过程中就能得到计算结果的表达式。

指针和constexpr

在constexpr声明中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关:

const int *p = nullptr; //p是一个指向整型常量的指针
constexpr int *q = nullptr; //q是一个指向整数的常量指针

2.5 处理类型

2.5.1 类型别名

有两种方法可用于定义类型别名,传统的方法是使用关键字 typedef

typedef double wages;

新标准规定了一种新方法,使用别名声明。

using SI = Sales_Item;

指针,常量和类型别名

typedef char *pstring; 
const pstring cstr = 0; //cstr 是指向char的常量指针
const pstring *ps; //ps是一个指针,它的对象是指向char的常量指针

2.5.2 auto类型说明符

C++11 新标准引入了auto类型说明符,auto让编译器通过初始值来推算变量的类型。显然,auto定义的变量必须要有初始值:

auto一般会忽略掉顶层const,同时底层const会保留下来。

2.5.3 decltype类型指示符

//decltype的表达式如果是加上了括号的变量,结果将是引用
decltype((i)) d; //错误:d是int&,必须初始化
decltype(i) d; //正确:e是一个未初始化的int

面试题 说明由decltype和由auto指定类型有何区别?

auto和decltype的区别主要在三个方面:

第一,auto类型说明符用编译器计算变量的初始值来推断其类型,而decltype虽然也用编译器分析表达式并得到它的类型,但是不实际计算表达式的值。

第二,编译器推断出的auto类型有时和初始值的类型并不完全一样,编译器会适当改变结果类型使其更符合初始化规则。例如,auto一般会忽略掉顶层const,而把底层const保留下来。与之相反,decltype会保留变量的顶层const。

第三,与auto不同,decltype的结果类型与表达式形式密切相关,如果变量名加上了一对括号,则得到的类型与不加括号时会有不同。如果decltype使用的是一个不加括号的变量,则得到的结果就是该变量的类型;如果给变量加上了一层或多层括号,则编译器将推断得到引用类型。

2.6 自定义数据结构

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

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

相关文章

【C++ Primer Plus学习记录】循环和文本输入

目录 1.使用原始的cin进行输入 2.使用cin.get(char)进行补救 3.使用哪一个cin.get() 4.文件尾条件 循环完后的一项最常见、最重要的任务&#xff1a;逐字符地读取来自文件或键盘的文本。 cin对象支持3种不同模式的单字符输入&#xff0c;其用户接口各不相同。下面介绍如何…

低代码平台在数字化转型过程中的定位

内容来自演讲&#xff1a;郭昊东 | 上海外服 | 流程分析工程师 摘要 本文介绍了外服集团的 IT 共享中心在低代码平台应用开发方面的实践经验。他们选择低代码平台的原因包括开发成本低、快速看到实际产品以及能够解决数据孤岛和影子 IT 等问题。他们在应用开发中面临的挑战包括…

软考:2024年软考高级:软件工程

软考&#xff1a;2024年软考高级: 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的 &#xff08;1…

LeetCode Hot100 3.无重复字符的最长子串

题目&#xff1a; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的 最长子串 的长度。 代码&#xff1a; class Solution {public int lengthOfLongestSubstring(String s) {char[] arr s.toCharArray(); // 转换成 char[] 加快效率&#xff08;忽略带来的空间…

Ubuntu Server 20.04.6下Anaconda3安装Pytorch

环境 Ubuntu 20.04.6 LTS Anaconda3-2023.09-0-Linux-x86_64.sh conda 23.7.4 Pytorch 1.11.0 安装 先创建一个工作环境&#xff0c;环境名叫lia&#xff1a; conda create -n lia python3.8环境的使用方法如下&#xff1a; conda activate lia # 激活环境 conda deactiv…

centos8 下载

下载网址 Download 直接下载地址 https://mirrors.cqu.edu.cn/CentOS/8-stream/isos/x86_64/CentOS-Stream-8-20231127.0-x86_64-dvd1.iso 这个版本安装的时候方便

经典策略梯度算法

经典策略梯度算法 DDPG算法 DDPG 算法被提出的初衷其实是 DQN 算法的一个连续动作空间版本扩展。深度确定性策略梯度算法&#xff08; deep deterministic policy gradient&#xff0c;DDPG&#xff09;&#xff0c;是一种确定性的策略梯度算法。 由于DQN算法中动作是通过贪…

【MATLAB】EWT分解+FFT+HHT组合算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~也可转原文链接获取~ 1 基本定义 EWTFFTHHT组合算法是一种广泛应用于信号处理领域的算法&#xff0c;它结合了经验小波变换&#xff08;Empirical Wavelet Transform&#xff0c;EWT&#xff09;、快速傅里叶变换&#x…

EUREKA: HUMAN-LEVEL REWARD DESIGN VIACODING LARGE LANGUAGE MODELS

目录 一、论文速读 1.1 摘要 1.2 论文概要总结 相关工作 主要贡献 论文主要方法 实验数据 未来研究方向 二、论文精度 2.1 论文试图解决什么问题&#xff1f; 2.2 论文中提到的解决方案之关键是什么&#xff1f; 2.3 用于定量评估的数据集是什么&#xff1f;代码有…

【Openstack Train安装】七、glance安装

Glance是为虚拟机的创建提供镜像的服务&#xff0c;我们基于Openstack是构建基本的IaaS平台对外提供虚拟机&#xff0c;而虚拟机在创建时必须为选择需要安装的操作系统&#xff0c;Glance服务就是为该选择提供不同的操作系统镜像。Glance提供Restful API可以查询虚拟机镜像的me…

多路转接<select>和<poll>使用手册

select int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout); 参数说明 返回值 返回值>0 表示成功返回可访问的文件描述符个数&#xff0c;返回值0 表示标识等待时间到期返回值<0 表示出现错误…

lv11 嵌入式开发 轮询与中断13

1 CPU与硬件的交互方式 轮询 CPU执行程序时不断地询问硬件是否需要其服务&#xff0c;若需要则给予其服务&#xff0c;若不需要一段时间后再次询问&#xff0c;周而复始 中断 CPU执行程序时若硬件需要其服务&#xff0c;对应的硬件给CPU发送中断信号&#xff0c;CPU接收到中…

简历上的工作经历怎么写

通过了简历筛选&#xff0c;后续的面试官会仔细阅读你的简历内容。他们在找什么呢&#xff1f;他们希望搞清楚你在某一段经历中具体干了什么&#xff0c;并且判断你的能力具体达到了什么水平。 简历在线制作下载&#xff1a;百度幻主简历 面试官喜欢具体的经历 越具体&#x…

Springboot-注册注解【springboot常用注解】

1.组件注册 1.1 使用的注解 Configuration:普通配置类,替代以前的配置文件,配置类本身也是容器的组件|SpringBootConfiguration:Springboot配置类,与Configuration功能一样|Bean:替代以前的Bean标签,如果没有在Bean标签内定义名字,则默认组件的名字为方法名,可以直接修改注解…

简单好用!日常写给 ChatGPT 的几个提示词技巧

ChatGPT 很强&#xff0c;但是有时候又显得很蠢&#xff0c;下面是使用 GPT4 的一个实例&#xff1a; 技巧一&#xff1a;三重冒号 """ 引用内容使用三重冒号 """&#xff0c;让 ChatGPT 清晰引用的内容&#xff1a; 技巧二&#xff1a;角色设定…

数据收集与处理(爬虫技术)

文章目录 1 前言2 网络爬虫2.1 构造自己的Scrapy爬虫2.1.1 items.py2.1.2 spiders子目录2.1.3 pipelines.py 2.2 构造可接受参数的Scrapy爬虫2.3 运行Scrapy爬虫2.3.1 在命令行运行2.3.2 在程序中调用 2.4 运行Scrapy的一些要点 3 大规模非结构化数据的存储与分析4 全部代码 1 …

时间序列预测实战(二十一)PyTorch实现TCN卷积进行时间序列预测(专为新手编写的自研架构)

一、本文介绍 本篇文章给大家带来的是利用我个人编写的架构进行TCN时间序列卷积进行时间序列建模&#xff08;专门为了时间序列领域新人编写的架构&#xff0c;简单不同于市面上大家用GPT写的代码&#xff09;&#xff0c;包括结果可视化、支持单元预测、多元预测、模型拟合效…

homeassistant 随笔

1.使用mushroom-strategy自动生成ui&#xff0c;隐藏中文ares&#xff0c;名字为区域的拼音&#xff0c;例如显示厨房则真实名字为chu_fang 隐藏图片中的工作室 代码为&#xff1a;

【C++】string模拟

string讲解&#xff1a;【C】String类-CSDN博客 基本框架 #pragma once #include <iostream> using namespace std; ​ namespace wzf {class string{public:// 默认构造函数string(): _str(new char[1]), _size(0), _capacity(0){_str[0] \0; // 在没有内容时仍要有终…

Windows + docker + python + vscode : 使用容器docker搭建python开发环境,无需本地安装python开发组件

下载docker for Windows docker window下载 如果没有翻墙工具&#xff0c;可以该网盘中的docker 链接&#xff1a;https://pan.baidu.com/s/11zLy3e5kusZR-4m_Fq_cqg?pwdesmv 提取码&#xff1a;esmv 安装docker docker的安装会重启电脑&#xff0c;不要惊讶&#xff0c;且…