C++中文版本primer 第二章变量和基本类型 学习笔记

2.2变量

2.2.1 变量定义

列表初始化

  • 定义一个名字为units_sold的int变量并初始化为0
int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
  • C++11 用花括号来初始化变量,上面这个步骤也称之为列表初始化。这种初始化有一个重要的特点,如果在初始化信息的时候存在丢失信息的风险那么编译器就会报错。丢失信息,是指在逆类型转换的时候,丢失数据的精度。
long double ld = 3.241592653;int a {ld}, b = {ld}; //错误,转化未执行,因为存在丢失信息的风险int c(ld), d = ld;    //正确,转换执行,但是会丢失部分数值

默认初始化

  • 如果定义变量没有指定初始值,则变量会默认初始化。初始化是由于变量的类型(标准类型/自定义类型)和所处的位置所决定的。定义在任何函数体之外的变量会被初始化为0。
  • 定义在函数体之内的变量不会被初始化,其数值是未被定义的,如果试图拷贝或者以其他方式来访问这个数值是会引发错误。
  • 类的对象如果没有显示的初始化,则其数值由类确定。

2.2.2 变量声明和定义的关系

  • C++使用分离式编译机制,该机制允许将程序分割为若干个文件,每个文件都可以被独立的编译。简单的例子就是,头文件的使用,使得程序代码之间可以互相共享代码。如引用头文件iostream,调用输入输出函数std::out。
  • 为了支持分离式编译机制,C++将声明和定义区分开来。声明使得程序的名字被程序所知,定义负责创建与名字相互关联的实体。变量声明规定了变量的类型和名字,这一点上定义与之相同。除此之外,定义还申请存储空间,也可能会给变量赋予一个初始化的数值。
  • 如果想声明变量但不定义它,在变量的名字之前使用extern关键字,而且不要显示的初始化变量。
extern int i; //声明i,并非定义i
int j;  //声明并未定义了j
  • 任何包含了显示初始化的声明就会变成了定义。当然也可以使用extern标记的变量赋一个初始化的数值,这就会抵消了extern的作用,一旦初始化就叫定义。
  • 变量只可以被定义一个,但是可以多次声明。

2.2.3 标识符

  • 用户自定义的标识符不可以连续出现两个下划线,也不可以使用下划线紧连大写字母开头,定义函数体外的标识符也不可以以下划线开头。

变量的命名规范

  • 标识符要体现实际的含义
  • 变量名使用小写
  • 用户自定义的类名一般使用大写
  • 如果用户定义的标识符由多个单词组成,则单词之间要有明显的区分。

名字的作用域

  • 作用域是程序的一部分,一般使用花括号进行分割。同一个名字在不同的作用域里面,可能指向不同的实体。名字的有效作用域始于名字的声明语句,结束于声明语句所在的作用域末端。

2.3 符合类型

2.3.1 引用

  • 引用为对象起了另外一个名字,引用类型引用另外一种类型。通过将声明符号写成&d的形式来引用类型,其中d是声明的变量名字。初始变量的时候,初始数值会被拷贝到新建的对象中。定义引用的时候,程序把引用和初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和他的初始值绑定在一起。因为无法使引用重新绑定到另外一个对象,因此引用必须要初始化。
  • 引用并非对象,它只是为一个已经存在的对象所起的另外一个名字。
  • 引用不是一个对象,因此无法定义引用的引用。
  • int &a = 10; //错误,引用类型的初始值必须是一个对象
  • double dav = 3.15; int &rte = dav;错误,引用类型和被引用的对象的类型必须是一致的。
int ival = 1024;
int &refVal = ival;// refVal指向ival(是ival的另外一个名字)
int &refVal2 ;//错误,引用必须被初始化

2.3.2 指针

  • 指针是指向的另外一种类型的符合类型。和引用是类似的,指针也实现了对于其他对象的间接访问。
  • 指针本身就是一个对象,允许对于指针赋值和拷贝,而且指针的生命周期内可以先后指向相同类型的不同对象;指针无需在定义的时候进行赋值,和其他类型是一样的,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的数值。
  • 引用不是对象,没有实际的地址,因此不能定义指向引用的指针。
double dval;
double *pd = &dval;// 正确,初始值是double类型的对象地址
double *pd2 = pd;//   正确,初始值是指向double对象的指针

指针值

指针的值(即地址)应属于以下几种状态之一

  • 指向一个对象
  • 指向紧领对象所占空间的下一个位置
  • 空指针,意味着指针没有指向任何对象
  • 无效指针,也就是上面所述情况之外的其他数值

利用指针指向对象

  • 如果指针指向了一个对象,则可以允许使用解引用符*来访问该对象
  • 解引用操作适用于那些确定了指向某个对象的有效指针
int val = 42;
int *p = &val;//p存放着变量val的地址,或者说p是指向变量val的指针
cout << *p;   //由符号*得到指针p所指的对象,输出42

空指针

  • null pointer不指向任何对象,在试图使用一个指针之前的代码可以首先检查指针是否为空。以下是检查指针是否为空的方法

int *p1 = nullptr; //等价于int *p1 = 0;
int *p2 = 0;       //直接将p2初始化字面常量0
int *p3 = NULL;    //需要首先使用#include<cstdlib>  等效于int *p3 = 0
  • 使用nullptr字面值来初始化指针,这是一种特殊类型的字面值,可以被转化为任意其他的指针类型。另一种方法就如对p2的定义一样,也可以将指针初始化为字面值0来生成指针。

void*指针

  • void*是一个特殊的指针类型,用于存放人以对象的地址。一个void*指针可以存放一个地址,这个和其他地址是类似的。

  • void*指针的功能单一,拿他和别的指针比较、作为函数的输入和输出、或者赋值给另外一个void*指针,但是不可以直接操作这个void*所指的对象。

2.3.3 理解复合类型的声明

定义多个变量

  • int * p1,p2;//p1是指向int的指针,p2是单纯的int

指向指针的指针

指向指针的引用

2.4  const限定符

  • const对象一旦创建后其数值就不会被再次改变,因此const对象必须初始化。
  • const对象只在文件中有效
  • 在不同的文件中使用不同的const来定义不同的常量,那么每个文件定义的变量只会在自己所属的文件中有效。如果想让多个文件共享同一个const变量,那么使用关键字extern即可

2.4.1 const的引用

把引用绑定到const对象上,就像绑定到其他对象上一样,称之为对于常量的引用。和普通信用不同,对于常量的引用不能被用于修改它所绑定的对象。

const int ci = 1024;
const int &r1 = ci;//正确,引用及其对应的对象都是常量
r1 = 42;          //错误,r1是对于常量的引用
int &r2 = ci;     //错误,试图让一个非常量去引用一个常量对象  
  • 因为不允许直接为ci赋值,当然也不可以通过引用去改变ci,因此,对于r2的初始化是错误的,假设初始化合法,就可以通过r2来改变他引用的对象的数值,这显然是不正确的。

初始化和对const的引用

  • 引用的类型必须和其所引用对象的类型是一致的,但是有两个例外。1,初始化常量引用时候允许用任意表达式来作为初始化的数值,只要该表达式结果可以转化为引用的类型即可。尤其,允许一个常量引用绑定非常量的对象、字面值甚至是一个一般表达式。

    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是一个普通的非常量的引用

对const引用可能引用一个并非const的对象

  • 常量的引用仅仅对于可以引用可以参与的操作进行了限定,对于引用的对象的本身是不是一个常量未做限定。因为对象也可能是一个非常量,所以可以通过其他途径来改变它的值。

    int i = 42;int &r1 = i; //引用r1绑定对象iconst int &r2 = i;//r2也绑定对象i,但是不允许通过r2来修改i的数值r1 = 0; //r1并非常量,i的数值修改为0r2 = 0; //错误,r2是一个常量的引用,因此不可以修改引用的元素的数值

 

 

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

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

相关文章

内存池中的嵌入式指针

嵌入式指针 可以union改struct 内存分配后 next指针就没用了 直接作为数据空间比较省内存 因为对指针指向的内存存储的时候 编译器是不管你是什么类型的 &#xff0c;这里有道练习题可以对指针的概念稍微理解一下&#xff1a; #include <iostream> using std::cout; us…

C++ 标准程序库std::string 详解

现在一般不再使用传统的char*而选用C标准程序库中的string类&#xff0c;是因为string标准程序和char*比较起来&#xff0c;不必担心内存是否足够、字符串长度等等&#xff0c;而且作为一个类出现&#xff0c;集成的操作函数足以完成大多数情况下(甚至是100%)的需要。比如&…

内存池的实现4 alloc内存池

alloc 内存池 优点: &#xff1a;本质是定长内存池的改进&#xff0c;分配和释放的效率高。可以解决一定长度内存分配的问题。 缺点 &#xff1a;存在内碎片的问题&#xff0c;且将一块大内存切小以后&#xff0c;申请大内存无法使用&#xff0c;别的FreeList挂了很多空闲的内存…

C++primer第15章节详解面向对象程序设计

前言 面向程序设计基于三个基本概念&#xff1a;数据抽象、继承和动态绑定。继承和动态绑定可以使得程序定义与其他类相似但是不完全相同的类&#xff1b;使用彼此相似的类编写程序时候&#xff0c;可以在一定程度上忽略掉他们的区别。 OOP概述 oop&#xff08;面向程序的设…

内存池的线程安全问题

malloc/free 据说老版本libc 有俩个版本&#xff0c;当你连接 pthread库的时候它就链接的是线程安全版&#xff0c;否则不是。在glic 2.2 以上无论怎么都是线程安全的。 new/delete new/delete 封装的 malloc/free , 如果malloc/free 是它们就是线程安全的。

C++11命名空间的using说明

std::cin 表示从标准输入读取内容&#xff0c;此处的作用域操作符::是指编译器应该从左侧名字所示的作用域中寻找右侧那个名字。因此std::sin表示使用命名空间std中的cin。 每个名字都需要有独立的using的声明 每一个using声明引入命名空间中的一个成员&#xff0c;比如可以将…

c语音的一些特殊关键字

PRETTY_FUNCTION C语言中获取函数名 C语言中的__LINE__用以指示本行语句在源文件中的位置信息

C++ primer三章二节标准库类型string

标准库类型string 标准库类型string表示可变长的字符序列&#xff0c;使用#include<string>引入头文件&#xff0c;string定义在命名空间std中。 定义和初始化string对象 如何初始化类的对象是由类的本身决定的&#xff0c;类可以定义很多初始化对象的方式&#xff0c;…

vim 不常见但好用的命令

● 跳跃 ○ 向前跳跃是 f ○ 向后跳跃是 F ● 继续 ○ 保持方向是 ; ○ 改变方向是 , ● 可以加上 [count] 来加速 ● ^ 是到本行第一个非空字符 ● 0 是到本行第一个字符&#xff0c;不管是不是空格 ● g_ 是到本行最后一个非空字符 ● 两个按键要依次按下 ● $ 跳到本行最后…

加密机组会 会议纪要

2020年9月28日 1&#xff0c;使用基类继承的机制&#xff0c;调用写好的函数接口 1&#xff0c;不要 使用Content&#xff08;封装数据&#xff0c;本质是一个json字符串&#xff09;&#xff0c;1&#xff0c;因为每次使用这个需要对里面的内容进行序列化&#xff0c;转化成…

c++为什么没有垃圾回收

垃圾回收 内存清理的另一个方面是垃圾回收。在支持垃圾回收的环境中&#xff0c;程序员几乎不必显式地释放与对象关联的 内存。运行时库会在某时刻自动清理没有任何引用的对象。 与C#和Java不一样&#xff0c;在C语言中没有内建垃圾回收。在现代C中&#xff0c;使用智能指针管理…

C++ Vecctor容器浅析

Vector的定义 向量&#xff08;Vector&#xff09;是一个封装了动态大小数组的顺序容器&#xff08;Sequence Container&#xff09;。跟任意其它类型容器一样&#xff0c;它能够存放各种类型的对象。可以简单的认为&#xff0c;向量是一个能够存放任意类型的动态数组。vector…

C++primer第二章2.4节对于const限定符相关内容进行详解

const限定符 const对象一旦创建后其数值就不会被再次改变&#xff0c;因此const对象必须初始化。const对象只在文件中有效在不同的文件中使用不同的const来定义不同的常量&#xff0c;那么每个文件定义的变量只会在自己所属的文件中有效。如果想让多个文件共享同一个const变量…

二分法的常见问题

mid(leftright)/2; mid (high - low) / 2 low; 这样写可以防止left right溢出 ,不过数足够大是时候该溢还是溢 为什么要取右边中间数呢&#xff1f;这是因为在区间里 只有 2 个元素的时候&#xff0c;把[left…right]划分成[left…mid - 1]和[mid…right]这两个区间&#x…

演示IPFS的一个完整的流程以及针对部分概念的详解

整体的流程 1&#xff0c;创建ipfs节点 通过ipfs init在本地计算机建立一个IPFS节点本文有些命令已经执行过了&#xff0c;就没有重新初始化。部分图片拷贝自先前文档&#xff0c;具体信息应以实物为准 $ ipfs init initializing IPFS node at /Users/CHY/.ipfs generating 2…

c++ 算法的时间复杂度

一般ACM或者笔试题的时间限制是1秒或2秒。 在这种情況下&#xff0c;C代码中的操作次数控制在 10^7为最佳。 下面给出在不同数据范国下&#xff0c;代码的时间复杂度和算法该如何选择&#xff1a; 1.n≤ 30,指数级别&#xff0c;dis剪枝&#xff0c;状态压缩dp 2.n < 100 &g…

简单工厂模式实现计算器

#include <iostream> #include <vector> #include <string> #include <iostream> #include <map> using namespace std; #define __THROW_ZERO do {cerr << "The dividend is 0" << endl; exit(1);}while(0);/* 简单工厂处…

TDengine安装教程

TDengine安装教程 前言 TDengine的安装十分简单&#xff0c;可以有以下三种安装方式&#xff0c;源码安装、通过Docker容器进行安装、通过安装包进行安装。但是使用源码安装较为复杂&#xff0c;通过docker的方式最为简单&#xff0c;但是需要一定docker相关的知识&#xff0…

C++中size_t的学习

size_t的定义 size_t是一种数据相关的无符号类型&#xff0c;它被设计得足够大以便能够存储内存中任意对象的大小。设计 size_t 就是为了适应多个平台&#xff0c;size_t等效于unsigned short int 或者 unsigned long int 类型&#xff0c;这个过程是动态匹配的。在需要通过数…

策略模式解决商店打折问题

#include <bits/stdc.h> using namespace std; /*策略模式解决商店打折问题*/class Cashsuper { private:/* data */ public:virtual double addcash(double cash) 0;double Getresult(double money){return addcash(money);} };class Cashnormal : public Cashsuper {p…