变量和基本类型

一、基本内置类型

1.除去布尔类型和扩展的字符型外,其他整型可以分为带符号的和无符号的。

2.与其他整型不同,字符型被分为了三种:char、signed char 和 unsigned char。

其中类型char会表现为带符号和无符号其中的一种,具体由编译器决定。

3.执行浮点数运算一般选用double,这是因为float通常精度不够而且单精度浮点数

和双精度浮点数的计算代价相差无几。事实上,某些机器上双精度更快。long double

一般没必要,它带来的运行时消耗不容忽视。

4.切勿混用带符号类型和无符号类型:如果表达式里既有带符号类型又有无符号类型,当

带符号类型取值为负时会出现异常结果,这是因为带符号数会自动转换为无符号数。

5.十进制字面值是带符号数,八进制和十六进制字面既可能是带符号的也可能是无符号的。

十进制字面值的类型是int、long 和 long、long 中尺寸最小的那个。类型short没有对应

的字面值。

6.字符串字面值的类型实际上是由常量字符构成的数组。编译器在每个字符串的结尾处添加

一个空字符('\0'),字符串字面值的实际长度要比它的内容多1。如果两个字符串字面值紧

邻且仅由空格、缩进和换行符进行分隔,则它们实际上是一个整体。

7.指定字面值的类型:

1)L'a'        //wchar_t

2)u8"hello"    //utf-8字符串字面值

3)88ULL       //无符号整型字面值,类型是unsinged long long

......

8.nullptr是指针字面值

二、变量

1.变量提供一个具名的、可供程序操作的存储空间。C++中的每个变量都有其数据类型,

数据类型决定着变量所占内存空间大小和布局方式以及变量能参与的运算。对C++程序员

来说,“变量”和“对象”一般可以互换使用。

2.很多程序员对于使用等号=来初始化变量的方式倍感困惑,这种方式让人认为初始化是

赋值的一种。事实上在C++语言中初始化和赋值是两个完全不同的操作:初始化---创建

变量时赋予其一个初始值,赋值---把对象的当前值擦除,而以一个新值来代替。

3.C++11标准中,可以用花括号初始化变量:

int a{};
double b{1.22}

这种初始化形式被称为列表初始化。

4.变量的声明和定义:

为了允许把程序拆分成多个逻辑部分来编写,C++语言支持分离式编译机制,该机制允许将程序

分割为若干个文件,每个文件可以被独立编译。如果将程序分割为多个文件,则需要有在文件间

共享代码的方法。为了支持分离式编译,C++将声明和定义区分开来。

声明:使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。

定义:负责创建与名字关联的实体,申请存储空间,也可能为变量赋初始值。

extern int i;               //声明i而非定义i
int j; //声明并定义j
extern int k = ; //赋值了,定义

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

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

如果要在多个文件中使用同一个变量,就必须将声明和定义分离。此时,变量的

定义必须出现且只能出现在一个文件中,而其他用到该变量的文件必须对其进行声明,却绝对不能重复定义。

三、复合类型

复合类型:基于其他类型定义的类型。

1. 引用

引用(reference):为对象起另外一个名字,引用类型引用(refers to)另外一种类型。

通过将声明写为&name形式来定义引用类型,例如:

int a = ;
int &refA = a; //指向a,即a的另外一个名字
int &refB; //引用必须被初始化

无法另引用重新绑定到另外一个对象,因此引用必须初始化。

定义了一个引用后,对其进行的所有操作都是在与之绑定的对象上进行的。

因为引用本身不是一个对象,所以不能定义引用的引用。

引用只能绑定在对象上,而不能与字面值或某个表达式的计算结果绑定在一起。

2. 指针

指针(pointer)是"指向"另外一种类型的复合类型。指针与引用的不同点:

1)指针本身就是一个对象,允许对指针的赋值和拷贝,而且在指针的声明周期内它可以先后指向几个不同的对象;

2)指针无需在定义时赋初始值;

定义指针的方法:

int *ip1, *ip2;
double dp, *dp2;

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

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

因为引用不是对象,没有实际地址,所以不能定义指向引用的指针。

除了两种例外情况,其他所有指针的类型都要和它所指向的对象严格匹配:

double dval;
double *pd = &dval; //正确:初始值是double型对象的指针
double *pd2 = pd; //正确:初始值是指向double对象的指针 int *pi = pd; //错误:类型不匹配

指针值:

指针的值应属下列4种状态之一:

1.指向一个对象;

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

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

4.无效指针,上述情况的其他值。

试图拷贝或以其他方式访问无效指针都将引发错误。编译器并不负责检查此类错误。

尽管第2种和第3种形式的指针是有效的,但其使用同样受到限制。显然这些指针没有

指向任何具体对象,所有试图访问此类指针(假定的)对象的行为不被允许。

使用解引符来访问指针指向的对象:

int ival = ;
int *p = &ival;
cout << *p; //输出42
*p = ;
cout << *p; //输出0

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

int *p1 = nullptr;
int *p2 = ;

nullptr是一种特殊类型的字面值,它可以被转换为其他的指针类型。

int zero = ;
int *p = zero; //错误

应该尽量初始化所有指针。有时候想要搞清楚赋值语句到底是改变了指针的值还是改变了指针所指对象的值不太容易,

最好的办法就是记住赋值永远改变的是等号左侧的对象。

p = &val;             //p的值被改变,现在指向了ival
*p = ; //ival的值被改变,指针p并没有变

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

double obj = 3.14, *pd = &obj;
void *pv = &obj;
pv = pd;

利用void*指针能做的事比较有限:拿它和别的指针做比较、作为函数的输入和输出,或者赋值

给另外一个void*指针。不能直接操作viod*指针所指的对象,因为我们并不知道这个对象到底是什么类型。

易误解的声明方式:

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

指向指针的指针 

指针是内存中的对象,像其他对象一样也有自己的地址,因此允许把指针的地址再放到另一个指针中。

int val = ;
int *pi = &val;
int **ppi = &pi; //ppi指向一个int型的指针
cout << **p << endl;

引用本身不是一个对象,因此不能定义指向引用的指针。但指针是对象,所以存在对指针的引用。

int i = ;
int *p;
int *&r = p; //r是一个对指针p的引用
r = &i; //r引用了一个指针,因此给r赋值&i就是令p指向i
*r = ; //将i的值改为0

要理解r的类型到底是什么,最简单的方法是从右向左阅读r的定义。离变量名最近的符号(此例中是&r的&)

对变量有最直接的影响,因此r是一个引用。声明符的其余部分用以确定r引用的类型是什么,此例中的*说明r是一个指针。

四、const限定符

使用关键字const对变量的类型加以限定,使其成为一个常量:

const int a = ;
a = ; //引发错误

const对象必须初始化。默认情况下,const对象被设定为仅在文件内有效。

对于变量不管是声明还是定义都添加extern关键字,这样只需要定义一次就可以了,其他文件都可见。

extern const int a = ;

const的引用:

可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用。

与普通的引用不同,对常量的引用不能被用作修改它所绑定的对象:

const int ci = ;const int &r1 = ci;          //正确,引用及其对应的对象都是常量
r1 = ; //错误
int &r2 = ci; //错误:试图让一个非常量引用指向一个常量对象

指针和const 

指向常量的指针,不能用于改变所指对象的值。

const double pi = 3.14;                        //常量,不能改变其值
double *ptr = &pi; //错误
const double *cptr = &pi; //正确
*cptr = 3.1415; //错误:不能给*cptr

例外:

double dval = 222.22;
cptr = &dval; //正确:但是不能通过cptr改变dval的值

const 指针: 

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

int errNumb = ;
int *const curErr = &errNumb; //curErr将一直指向errNumb
const double pi = 3.14;
const double *const pip = &pi; //pip是一个指向常量对象的常量指针

指针本身是一个常量并不意味着不能通过指针修改其所指对象的值。

用名词顶层const表示指针本身是一个常量,而用名词底层const表示指针所指的对象是一个常量。

constexpr 和常量表达式

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

显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。

const int sz = get_size();   //常量sz的具体值要到运行时才能获取到,所以不是常量表达式。

将变量声明为 constexpr 类型以便由编译器来验证变量的值是否是一个常量表达式。

constexpr int mf = ;
constexpr int sx = size(); //只有当size是一个constexpr函数时,才是一条正确的声明语句

函数体内定义的变量一般来说并非存放在固定地址中,因此constexpr指针不能指向这样的变量。

五、处理类型

1.类型别名

类型别名是一个名字,他是某种类型的同义词。定义类型别名的两种方法:

1)使用typedef关键字

typedef double wages;
typedef wages base, *p; //base是double的同义词,p是double*的同义词

2)使用别名声明:

using SI = Sale_item;           //SI是Sales_item的同义词
typedef char *pstring;           //pstring 实际上是char*的别名
const pstring cstr = ; //cstr是指向char的常量指针
const pstring *ps; //ps是一个指针,它的对象是指向char的常量指针

2. auto类型说明符

auto类型说明符能让编译器帮助我们分析表达式的类型。

auto定义的变量必须有初始值

auto  a = b + c;
auto i = , *p = &i; //正确:i 是整数、p是整型指针
auto sz = , pi = 3.14; //错误,类型不一致

编译器推断出来的类型有时候和初始值的类型并不完全一样,编译器会适当地改变结果类型使其符合初始化规则。

int i = , &r = i;
auto a = r; //a是一个整数(r是i的别名,而i是整数)

auto会忽略掉顶层const,同时底层const会保留下来,比如当初始值是一个指向常量的指针时:

int i = ;
const int ci = i, &cr = ci;
auto b = ci; //b是整数(ci的顶层const特性被忽略掉了)
auto c = cr; //c是整数(cr是ci的别名,ci本身是一个顶层const)
auto d = &i; //d是一个整型指针(整数地址就是指向整数的指针)
auto e = &ci; //e是一个指向整数常量的指针

auto类型是一个顶层const:

const auto f = ci;             //ci的推演类型是int, f 是 const int

将引用类型设为auto,此时原来的初始化规则任然适用:

auto &g = ci;                     //g是一个整型常量引用,绑定到ci
auto &h = ; //错误:不能为非常量引用绑定字面值
const auto &j = ; //正确:可以为常量引用绑定字面值

六、自定义数据结构

定义Sales_data类型:

struct Sales_data {
std::string bookNo; //数据成员
unsigned units_sold = ;
double revenue = 0.0;
};

C++入门笔记(二)变量和基本类型的更多相关文章

  1. 《C++ Primer》读书笔记(二)-变量和基本类型

    bool类型与其他类型转换时,0为false,1为true 浮点数赋值给整数的时候,进行近似处理,结果仅保留浮点数小数点之前的部分 整数赋值给浮点数的时候,小数部分记为0,如果该整数超过了浮点类型的容 ...

  2. (C/C++学习笔记) 二十三. 运行时类型识别

    二十三. 运行时类型识别 ● 定义 运行时类型识别(Run-time Type Identification, RTTI) 通过RTTI, 程序能够使用基类的指针或引用来检查(check)这些指针或引 ...

  3. C#笔记(二)变量

    C#把数据类型分为两种 ● 值类型 ● 引用类型 从概念上看:其区别是值类型直接存储其值,而引用类型存储对值的引用 这两种类型存储在内存的不同地方:值类型存储在堆栈中,而引用类型存储在托管堆上 如果变 ...

  4. (C/C++学习笔记) 九. 变量的存储类型

    九. 变量的存储类型 ● 变量的存储类型(见附页) ● 注释 ①对于自动变量,它属于动态存储方式. 但是也可以用static定义它为静态自动变量,或称静态局部变量,从而成为静态存储方式.由此看来,一个 ...

  5. C++ Primer 学习笔记_5_变量和基本类型(续2)

     变量和基本类型 七.枚举 枚举不但定义了整数常量集,并且还把它们聚集成组. 枚举与简单的const常量相比孰优孰劣, 通过以下一段代码. 一看便知: enum {input, output, a ...

  6. Go语言学习笔记(二) [变量、类型、关键字]

    日期:2014年7月19日 1.Go 在语法上有着类 C 的感觉.如果你希望将两个(或更多)语句放在一行书写,它们 必须用分号分隔.一般情况下,你不需要分号.   2.Go 同其他语言不同的地方在于变 ...

  7. 精读《javascript高级程序设计》笔记二——变量、作用域、内存以及引用类型

    变量.作用域和内存问题 执行环境共有两种类型——全局和局部 作用域链会加长,有两种情况:try-catch语句的catch块,with语句. javascript没有块级作用域,即在if,for循环中 ...

  8. Scala入门笔记二

    [TOC] 标识符 可用的字符 处理括号类字符,分隔符之外,其他所有的可打印的ASCII字符,如字母,数字,下划线和美元符号($)均可出现在Scala标识符中 插入符包括了(,) [,] {,and} ...

  9. C#入门笔记2 变量

    变量关系到数据的存储,一个供程序操作的存储区的名字,每一个变量都一个特定的类型,类型决定变量的内存大小和布局. 注:必须一定要先声明,赋值后,才能使用. 变量声明 三种声明方式: 1.先声明,后赋值. ...

  10. 02.第二章_C++ Primer学习笔记_变量和基本类型

    2.1  基本内置类型 2.1.1  算术类型 算术类型包括两类:整型和浮点型 2.2  变量 2.3  复合类型 2.4  const限定符 2.5  处理类型 2.6  自定义数据结构

随机推荐

  1. python魔法方法之构造和析构

    python的类实例化的时候会默认执行该类的构造方法_init_ class Rectangle: def __init__(self,x,y): self.x=x self.y=y def getA ...

  2. 四五月份:关键词是沟通、绘画和SQL

    例行总结一下四五月份的感受. 关键词有三个:沟通.绘画和SQL. 整体来说,这两个月在努力跟这三个关键词死磕,略有些进展,因此汇报一下. 虽然这三个关键词从重要度来说是从左到右的,但从叙述来讲,还是先 ...

  3. HDU-6031 Innumerable Ancestors(二分+树上倍增)

    题意 给一棵树,$m$次询问,每次询问给两个点集问从两个点集中各取一个点的$LCA$的最大深度. 思路 二分答案.对于某个二分过程中得到的$Mid$,如果可行则两个点集在$Mid$所在的深度存在公共的 ...

  4. Linux二进制安装apache2.4.25

    Linux二进制安装apache2.4.25 安装环境:CentOS 6.2 先检查是否安装了Apache 如通是通过rpm包安装的话直接用下面的命令:rpm -q httpd 也可以使用如下两种方法 ...

  5. javaFX的控制台实现

    最近做了个javaFX的工具,想弄个控制台输出信息,准备用TextArea来模拟console,但直接操纵console对象的话不依赖这个项目的地方就无法输出信息到控制台了,至于log,以前弄过一个输 ...

  6. Ubuntu下 MySql忘记密码解决方案

    1.在终端输入 sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf 2.在文件内搜索skip-external-locking,在下面添加一行: skip-gran ...

  7. Nginx开启gzip压缩解决react打包文件过大

    用create-react-app创建的react应用打包之后的build js有1M之多. 采用gzip打包传输,可以节约70%左右的带宽 nginx采用gzip打包方式 在nginx配置中添加如下 ...

  8. Spring 基于注解的AOP实现

    在本文开始之前,我要引入一张图,这张图的来源 https://blog.csdn.net/chenyao1994/article/details/79708496 ,版权归原作者所有,我借鉴了原作者的 ...

  9. 拷贝本地文件到docker容器

    查找所有容器 docker ps -a 查找容器长ID docker inspect -f '{{.ID}}' python 拷贝本地文件到容器 docker cp 本地路径 容器长ID:容器路径

  10. ssh登录,爬坑系列

    最近在实验室弄ssh登录,结果被虐了,要注意以下: 1.主机名不能包括   -     _    !  等非法字符. 2.如果hadoop格式化时,报:“SHUTDOWN_MSG: Shutting ...