C++ primer 5th 第二章

1 算数类型

基本数据类型包括 算术类型(arithmetic type)和空类型(void)
算数类型 分为 整型(integral type,包括字符和布尔类型)和浮点型
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.1整型和字符型

我们以0开头的整型表示八进制,以0x或0X开头的表示十六进制

20/*十进制*/         024/*八进制*/         0x14/*十六进制*/

1.2字符和字符串字面值

'a' //字符字面值
"hello world" //字符串字面值

字符串字面值会在结尾添加一个空字符(’\0’),因此字符串字面值的实际长度要比它的内容多1,比如’A’表示当初字符A,而"A"表示一个字符的数组,包含字母A和一个空字符。
在这里插入图片描述

2 变量

2.1列表初始化

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

列表初始化(list initialization)用花括号来初始化

int a = 0;
int a = {0};
int a{0};
int a(0);

以上都可以完成初始化

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

默认初始化
如果定义变量时没有指定初值,则变量会被默认初始化(default initialized)
如果是内置类型的变量 在任何函数体之外的变量初始化为0。定义在函数体内部的内置类型变量将不被初始化。一个未被初始化的内置数据类型变量的值是未定义的,不可以访问或以其他形式访问此值

2.2变量声明和定义的关系

声明(declaration)使得名字为程序所知,一个文件如果想使用别处定义的名字则必须包含对那个名字的声明。而定义(definition)负责创建与名字相关的实体。

extern int j;//声明j而非定义j
int i; //声明并定义i
#include<iostream>
using namespace std;
 extern int a = 10;//正确但是会有警告 此时就抵消了extern的作用  warning: 'a' initialized and declared 'extern'
int main()
{
    extern int b = 10; //error: 'b' has both 'extern' and initializer
    cout << a << endl;
    return  0;
}
备注:变量能且只能被定义一次,但是可以被多次声明

extern c
如: extern “C” void fun(int a, int b);则告诉编译器在编译fun这个函数名时按着C的规则去翻译相应的函数名而不是C++的,C++的规则在翻译这个函数名时会把fun这个名字变得面目全非,可能是fun@aBc_int_int#%$也可能是别的,这要看编译器的"脾气"了(不同的编译器采用的方法不一样),为什么这么做呢,因为C++支持函数的重载.

2.3 标识符(identifier)

命名规范:老生常谈了,就不多说了

2.4 名字的作用域(scope)

1 全局作用域(global scope)
2 块作用域(block scope)
内存作用域会覆盖外层作用域一样的变量等

3 复合类型

一条声明语句有一个基本数据类型和紧随其后的一个声明符列表组成。

3.1 引用

此处只介绍左值引用
引用(reference)为对象起了一个名字,引用类型引用(refers to)另一种类型。通过声明将生声明符写成&d的形式来定义引用类型,其中d是声明的变量名:

int a = 10;
int &b = a;//b指向a

引用必须初始化

3.2指针(pointer)

和其他内置数据类型一样,再块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。

#include<iostream>
using namespace std;

int main()
{
    int a = 10;
    int *b = &a; //&取地址
    cout << *b << endl;//*解引用
    return 0;
}
指针的值(即地址)应属下列4种状态之之一:
1.指向一个对象。
2.指向   紧邻对象所占空间  的下一个位置。
3.空指针,意味着指针没有指向任何对象。
4.无效指针,也就是上述情况之外的其他值。
空指针
c++11 新标准nullptr
以前是使用NULL的预处理变量
不可以int类型的变量(值为0)来赋值给指针
void*
概括说来,以void*的视角来看内存空间也就仅仅是内存空间,
没办法访问内存空间中所存的对象
#include<iostream>
using namespace std;

int main()
{
    int val = 1024;
    int *p= &val;
    int **pi = &p;
    cout << *p <<" "<< **pi << endl;//pi是指向指针的指针
    cout << *pi << endl; //p的值是个地址
    int *&r = p; //指针p的引用 
    *r = 10; //修改了val的值
    cout << val << endl;
    return 0;
}
面对一条比较复杂的指针或引用的声明语句时,从右向左阅读有助于弄清楚它的真实含义。

4 const限定符

防止程序不小心改变了变量的值,可以用关键字const进行限定
const对象一旦创建后就不能在改变,所以const对象必须初始化

默认情况下,const对象仅在本文件内有效
//file.c定义并初始化了一个常量,该常量能被其它文件访问
extern const int buffsize() = fcn();
//file.h 声明  也用extern做了限定,其作用是指明buffsize并非本文件独有 ,它的定义在别处出现
extern const int buffszie
如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字

4.1const的引用

#include<iostream>
using namespace std;

int main()
{
    double val = 3.14;
    const int &b = val; //正确  相当于 const int temp = val; const int &b = temp
    int &r = val;//错误 无法用 "double" 类型的值初始化 "int &" 类型的引用(非常量限定)
    return 0;
}

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

#include<iostream>
using namespace std;

int main()
{
    int i = 20;
    int &r1 = i;//引用r1绑定对象i
    const int &r2 = i;//r2也绑定对象i 只是不允许使用r2修改i的值
    r1 = 0;// r1非常量,i的值可以被修改
    r2 = 0;// 错误:r2是一个常量引用
    return 0;
}

4.2 指针和const

const double v = 10.31;
double *p1 = &v;//错误 const double *" 类型的值不能用于初始化 "double *" 类型的实体
const double *p2 = &v;
*p2 = 12;//错误 表达式必须是可修改的左值

指针是对象而引用不是,因此就像其他对象类型-样,允许把指针本身定为常量。常量指针(const pointer)必须初始化,而且一旦初始化完成,则它的值(也就是存放在指针中的那个地址)就不能再改变了。把*放在const关键字之前用以说明指针是一个常量,这样的书写形式隐含着一层意味,即不变的是指针本身的值而非指向的那个值。

int a = 10;
int b = 12;
const int *p = &a;//只表示p所指向的对象的值不可以变,但是p本身存放的地址是可以改变的
p = &b;//正确
const int *const p2 = &a;//const指针
p2 = &b;//错误 表达式必须是可修改的左值 

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

constexpr和常量表达式
常量表达式(const expression) 是指值不会改变并且在编译过程就能得到计算结果的表达式。显然,字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。

int v = 10;
constexpr int a = 10;//正确
constexpr int b = a + 1;//正确
constexpr int d = v; //表达式必须含有常量值 -- 变量 "v"的值不可用作常量
C++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。
声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化。
尽管不能使用普通函数作为constexpr变量的初始值,但是正如6.5.2节(第214页)将要介绍的
新标准允许定义一种特殊的constexpr函数。这种函数应该足够简单以使得编译时就可以计算其结果,这样就能用constexpr函数去初始化constexpr变量了。
#include<iostream>
using namespace std;
int b = 10;
constexpr int *pp = &b; //正确
constexpr int *pi = nullptr;//正确
constexpr int *pii = 0;//正确
int main()
{
    int a = 10;
    constexpr int *p = &a;//表达式必须含有常量值 -- 变量 "a" (已声明 所在行数:7) 的指针或引用不可用作常量
    return 0;
}
const int *p = nullptr; //p是一个指向整型常量的指针
constexpr int *p1 = nullptr//p1是一个指向整数的常量指针

p和p1的类型相差甚远,p是一个指向常量的指针,而p1是一一个常量指针,其中的关键在于constexpr把它所定义的对象置为了顶层const。

5 处理类型

5.1类型别名(type alias)

两种方法
1 typedef
2 using

#include<iostream>
using namespace std;
int main()
{
    typedef double wages;
    typedef wages base, *p;
    using heh = int;
    wages v1 = 3.14;//wages和 base都表示double
    p pv = &v1; //p 表示double*
    heh v2 = 3;//heh表示int
    cout << v1 << " " << *pv << " " << v2 << endl;
    return  0;
}

结果

3.14 3.14 3

指针、常量和类型别名

typedef int *pint;
int v1 = 10;
int v2 = 12;
const pint p = &v1; //此时 const pint表示指向int的常量指针,而不是指向常量int的指针
*p = 12;
p = &v2;//错误

auto类型说明符
auto让编译器通过初始值来推算变量的类型。所以auto 定义的变量必须有初始值:

decltype

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值