[C++ Primer]第二章 变量与基本类型

2.1 基本内置类型

包括

  • 算术类型
  • 空类型(void)

2.1.1 算术类型

  • 整型
    包括了char和bool
  • 浮点型

算术类型所占的大小在不同机器上有所差别

类型 h含义 最小尺寸(字节)
bool 未定义
char 1
wchar_t 宽字符 2
char16_t Unicode字符 2
char32_t Unicode字符 4
short 2
int 2
long 4
long long 8
float 6位有效数字
double 10位有效数字
long double 10位有效数字

带符号类型和无符号类型

  • singed
  • unsinged
    只能表示大于等于0的数

对于char(注意)

  • char
    具体为有符号还是无符号由编译器决定
  • singed char
  • unsigned char

类型选择的建议

  • 非负选用unsigned
  • 若数值超过了int的范围,选用long long, 因为long一般情况下和int大小一样
  • char不要用于算术运算, 因为它在有些机器上是有符号的,一些是无符号的
  • 浮点运算用double, float精度不够,且通常float和double的计算代价相差不大

2.1.2 类型转换

  • bool \rightarrow 非bool类型
    • true \rightarrow 1
    • false \rightarrow 0
  • 非bool类型 \rightarrow bool
    • 0 \rightarrow false
    • 非0 \rightarrow true
  • 赋给无符号数超出范围的值
    结果为该值对能表示的最大值取模后的余数
  • 赋给有符号数超出范围的值
    结果是未知的

含有无符号类型的表达式

  • 同时含有无符号类型和有符号类型的时候,有符号类型会转换成无符号类型
  • 从无符号数中减去一个数,必须保证结果非负
  • 无符号数做for循环计数变量也会出现问题
    当u为0时,--u得到的是取模后的余数,为正数,而不会是-1
for(unsigned int u = 10;u >= 10;--u)
  cout << u << endl;
//改为
while(u > 0)
{
  u--;//必须先减再输出
  cout << u << endl;
}

2.1.3 字面值常量

每个字面值常量都对应一种数据类型,字面值常量的形式和值决定了它的数据类型

整型和浮点型字面值

整型

  • 进制问题
    • 20---十进制
    • 024---八进制(0开头)
    • 0x14---十六进制(0x开头)
  • 符号问题
    • 十进制字面值是带符号数
    • 八进制和十六进制数字面值可能是带符号数也可能是无符号的
  • 类型问题
    • 十进制字面值为int, long, long long中能容下它的最小的一个
    • 八进制和十六进制字面值为int, unsigned int, long, unsigned long, long long, unsigned long long中能容纳其数值的最小的一个
    • short没有字面值

浮点型

  • 浮点型字面值是double

字符和字符串字面值

  • 字符字面值

    ‘a’

  • 字符串字面值

    "abc"

转义序列

常用的有

  • \n换行
  • \t制表符

指定字面值的类型

字符和字符串字面值前缀

前缀 含义 类型
u Unicode16字符 char16_t
U Unicode32字符 char32_t
L 宽字符 wchar_t
u8 UTF-8字符串(用于字符串) char

整型浮点型字面值后缀

后缀 含义 类型
u or U unsigned能匹配的最小类型 无符号
l or L 至少为long long
ll or LL 至少为long long long long
f or F float float
l or L(浮点型) long double long double

布尔字面值和指针字面值

布尔

  • true
  • false

指针

  • nullptr

2.2 变量

2.2.1 变量定义

初始值

double price = 109.99;

列表初始化(C++11)

//等价于 int sold = 0;
int sold = {0};
int sold{0};
int sold(0);

默认初始化

  • 内置类型的全局变量

    初始化为0

  • 内置类型的局部变量

    不被初始化

2.2.2 变量声明和定义的关系

为了支持分离式编译(拆分为多个文件), C++将声明和定义区分开来。要在多个文件里使用同一个变量,必须将声明和定义分离。

声明(Declaration)

使得名字为程序所知(可以声明别处定义过的变量,进行使用)

定义(Definition)

负责创建与名字关联的实体

extern int i; //只声明而不定义i
int j; //声明并且定义j
extern double pi = 3.14 //extern语句如果包含初始值就不再只是声明,包括了定义(函数体内部这么做会报错)

2.2.3 标识符

  • 不能为保留字
  • 必须以下划线或者字母开头
  • 不能连续出现两个下划线
  • 不能下划线紧接着大写字母开头
  • 定义在函数体外的标识符不能以下划线开头

2.2.4 名字的作用域

  • 定义于所有花括号之外的为全局作用域

    在整个程序范围内都可以使用

  • 定义在花括号内拥有块作用域

    只在该花括号内有效

  • 嵌套的作用域

    int a = 1;
    void func1()
    {
        int a = 2;
        cout << a << endl;
        //输出2,内层覆盖外层作用域
        cout << ::a << endl;
        //输出1,使用域操作符来使用全局变量
    }
    

2.3 复合类型

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

2.3.1 引用

引用为对象其了另外一个名字。使用&d来定义引用类型

int a = 100;
int &ref = a;//ref 指向 a
//int &ref;错误,引用必须被初始化
  • 引用必须被初始化(绑定)

  • 无法令引用重新绑定到另外一个对象

  • 引用本身不是一个对象, 不能定义引用的引用

  • 引用的类型必须与其绑定的对象严格匹配

  • 引用只能绑定在对象上,不能绑定在字面值上

    int &ref = 10;//错误
    

2.3.2 指针

指针是指向另外一种类型的复合类型,通过*d来定义

int a = 1;
int *pointer = &a;

指针与引用的区别

  • 指针本身是一个对象
  • 指针可以先后指向不同的对象
  • 指针不需要赋初值
  • 由于引用不是对象, 所以不能定义指向引用的指针

获取对象的地址

通过取地址运算符&

指针也需要与其被指对象的类型严格匹配(有两个例外的情况)

int a = 1;
int *pointer = &a;//取地址运算符&

空指针与野指针

  • 空指针即为nullptr,不指向任何对象

    int *p1 = nullptr;//为C++11新标准
    int *p2 = 0;//也是空指针
    int *p3 = NULL;//NULL是一个预处理变量,不属于命名空间std,由预处理器负责管理,可以直接使用
    
  • 野指针即未被初始化的指针(指向未知地址)

利用指针访问对象

使用解引用符*

int a = 1;
int *pointer = &a;//取地址运算符&
cout << *pointer << endl;

其他指针操作

  • 非空指针可以转化为true, 空指针转化为false

    int *p1 = nullptr;
    if(p1)
    {
        cout << "p1 is not nullptr" << endl;
    }
    
  • 指针比较

    通过==来比较两个指针(两个指针都为空,也是相等)

void*指针

可以存放任意类型对象的地址,但是在使用时必须进行类型转换才能使用

int a = 1;
void *p1 = &a;//合法
cout << *p1 << endl;//不合法
int *p2 = (int *)p1;
cout << *p1 << endl;//合法

2.3.3 理解复合类型的声明

变量的声明

  • 由基本数据类型 + 声明符组成,声明符中可以加上类型修饰符
int *p;
int a;
int &ref = a;
// *, &在这里为类型修饰符

指向指针的指针

通过*的个数来区别指针的级别

int a = 1;
int *pi = &a;//一级指针
int **pii = &pi;//二级指针
//也是由于使用了不同的类型修饰符

绑定指针的引用

由于指针是对象,所以可以用引用绑定指针

int i = 42;
int *p = &i;
int *&ref = p;//绑定int *指针的引用

2.4 const限定符

const限定符用来声明常量值

  • const变量一旦声明不可改变值
  • const变量必须赋初值
const int bufsize = 512;

const作用域

默认情况下,const对象仅在文件内有效

若想要让const对象在其他文件中也能访问到,必须在定义和声明时都添加extern关键字

extern const int bufsize = 125;//定义也要加上extern

extern const int bufsize;//声明加上extern

2.4.1 const的引用

可以将const对象绑定到引用上, 但是该引用必须也用const修饰

const int a = 125;
const int &ref = a;

初始化和对const的引用

在两种情况下,引用绑定的对象可以不和引用类型匹配

  • 常量引用绑定的对象能够转化为引用的类型
  • 允许一个常量引用(注意必须是被const修饰的引用)绑定非常量对象
int i = 42;//非常量对象
const int &ref1 = i;//绑定非常量对象,注意必须为const
double dval = 3.14;//浮点数
const int &ref2 = dval;//绑定类型不匹配的对象,但是浮点数可以转化为int
/*
实际上发生的事情为,创建了一个临时变量,该引用绑定到了该临时变量上
如果该引用不是const的,修改该引用修改的是临时变量,而不是原来的变量,所以必须为const的
const int temp = dval;
const int &ref2 = temp;
*/

2.4.2 指针和const

类似于常量引用,一样可以定义指向常量的指针,但是指针必须用const修饰

const double pi = 3.14;
double *ptr = &pi; //错误,必须用const修饰
const double *ptr = &pi;

const指针

代表的意思为不能改变该指针所指向的对象.注意const的位置

int *const pointer;

const指针必须初始化

int a = 0;
int b = 0;
const int *ptr = &a;
ptr = &b; //错误

2.4.3 顶层const

顶层const

对于指针来说表示指针本身是个常量

一般的,顶层const可以表示任意的对象是常量

底层const

对于指针来说表示指针所指的对象是个常量

一般的,底层const则与指针和引用等符合类型的基本类型部分有关(所指的东西)

2.4.4 constexpr和常量表达式

常量表达式指不会改变,且在编译过程中就能计算得到的表达式

  • 字面值是常量表达式
  • 常量表达式初始化的const对象也是常量表达式

constexpr常量

c++11新标准规定, 可以用constexpr来声明一个常量表达式变量(是一个常量)

constexpr int mf = 20; //是常量表达式
constexpr int m1 = size();//不是常量表达式,不行

字面值类型

  • 自定义类, IO库, string类型不属于字面值类型不能定义为constexpr
  • 指针类型变量要定义为constexpr必须满足
    • 要么被初始化为nullptr
    • 要么是存储于某个固定地址中的对象
      • 定义于函数体内的变量一般来说不是存储在固定的地址
      • 定义于所有函数体外的对象地址固定不变

指针和constexpr

用constexpr修饰指针,表达的意思使该指针为常量指针(即该指针本身不能改变)

2.5 类型别名

使用类型别名可以简化类型书写

2.5.1 类型别名

typedef

typedef double wages; //wages i = 0.0; 即为声明一个double类型的变量
typedef int *p;//p为int *的同义词
typedef int p[10];//p为int arr[10]的同义词

别名声明(c++11)

using SI = Sales_item; //SI是Sales_item的同义词

指针、常量和类型别名

typedef int *p;//p为int *的同义词
const p i = 0; //i为指向char的常量指针(注意不是指向常量 的指针)

不能简单的将类型别名替换为他原来的名字

const int *i = 0;//这就变成了指向const int常量的指针了,而不是常量指针

2.5.2 auto类型说明符

C++11新标准允许用auto类型说明符让编译器替我们去分析表达式所属的类型

int i1 = 0;
float i2 = 1.2;
auto var = i1 + i2;//var为float

复合类型、常量和auto

编译器推断出来的类型和初始值类型有时不完全一样,编译器会做适当的调整

  • 使用引用来初始化时,会使用被引用的对象的类型作为auto的类型

    int i = 0, &r = i;
    auto a = r;//a的类型为int 而不是 int &
    
  • auto会忽略顶层const, 保留底层const

    const int ci = i, &cr = ci;
    auto b = ci;//b为int, 忽略了顶层const
    auto c = cr;//c为int, cr为引用这时候要看所引用对象,而const int ci为顶层const所以忽略const
    auto d = &i;//d为int *
    auto e = &ci;//e是const int * ???????这里不怎么理解
    

如果希望推断出auto类型为顶层const,可以加上const

const auto f = ci;

还可以将引用类型设置为auto

auto &g = ci;

2.5.3 decltype类型指示符

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容