C++Primer笔记-变量与基本类型

前言

该系列是《C++Primer第五版》的笔记,包含本人认为值得记录和整理的主要的知识点,并不是全部内容,也不是具体的内容。
该系列文章的作用应该是作为复习或预习的参考,有哪些知识点忘记或想学,可以大致浏览下该文章,然后再去书中寻找详细解答。(本系列文章基本是按书本顺序罗列的知识点,便于大家去书中寻找)
所以看该文章前,需要有一定的C++基础,否则阅读起来可能有困难。

本文大致整理了第二章的知识点,属于C++比较基础的内容,有零星几个难点。

链接目录

基本内置类型

内置的数据类型具体的长度和机器及编译器相关,以下的是通常情况下的长度,仅供参考。

cprimer_1_1.jpg

在算术运算中尽量不用char,因为在不同机器中,char可能被解释为带符号数或无符号数。

变量初始化

对于内置类型,在函数体外未显式初始化,默认初始化为0,在函数体内则不进行初始化,值是不确定的。

//例如int,a的值为0,b的值不确定
int a;
int main(){
	int b;
	return 0;
}

变量的声明和定义

C++为了支持分离式编译,声明和定义可以分开。

  • 声明定义了变量的类型和名字
  • 定义额外进行申请内存空间,初始化等操作

如果在多个文件中使用同一个变量,定义和声明需要分离开,定义只能出现在一个文件中,其他使用该变量的文件只能声明。

extern int i;//声明了i,但没定义
int j;//声明并定义了j,定义内容由默认初始化决定

引用

引用是对象的另一个名字,使用&进行引用的定义。记住引用不是对象,没有实际地址,只是一个对象的别名。且有几个注意事项。

  • 引用类型必须严格匹配
  • 引用必须被初始化
  • 不能定义引用的引用
int val = 1;
int &refI = i;//refI为i的引用

指针

指针与引用的不同点:

  • 允许赋值和拷贝
  • 可以在不同时刻指向不同的对象
  • 无需在定义时就初始化
  • 可以有指向另一个指针的指针

但也有几个注意事项:

  • 不能定义指向引用的指针
  • 大部分情况下(类的继承关系除外),指针类型和对象必须匹配
int i = 1;
int *p = &i;//p是指向i的指针
int **pp = &p;//pp是指向p的指针

指针的使用是非常容易出错的,访问无效指针会引发程序错误,但编译器并不负责检查。

我们可以通过解引用符*访问指针指向的对象:cout << *p << endl;

空指针有三种形式:

  • 0
  • NULL
  • nullptr,C++11新引入的,推荐使用

const限定符

阻止对对象的修改,可以和其他关键字组合使用。

常量引用:用const修饰的引用

  • 一个常量对象的引用必须是常量引用
  • 一个非常量对象,可以有常量引用,也可以有非常量引用
const int i = 1;
const int &r1 = i;//常量i的常量引用

int j = 1;
const int &r2 = j;//非常量j的常量引用
r2 = 2;//非法,无法修改常量引用
j = 2;//合法,对象本身非常量,可修改

指针和const:和常量引用一样,指向常量对象的指针必须用const修饰,且不能通过该指针修改对象。
常量指针(const指针):该指针本身是个常量,即指针的指向不可变,但仍可以通过该指针修改对象。

指针和const速记:

  • const*左侧,指针指向常量,所指对象不可变
  • const*右侧,常量指针,指针指向不可变

顶层const:表示指针本身是个常量,即指向不可变
底层const:表示指针所指对象是常量,即对象不可变

指针值在条件表达式中的使用:

  • 如果指针值是0,则条件为false
  • 否则,为true

constexpr和常量表达式

常量表达式:在编译过程中就能得到计算结果的表达式。
由于在复杂系统中,很难分辨一个表达式是不是常量表达式,所以C++11引入constexpr变量,将常量表达式的检查交给编译器。

constexpr变量:一定是常量,而且必须用常量表达式进行初始化。

//constexpr的用法
constexpr int bufSize = 32;
constexpr int limit = bufSize * 2;//用常量表达式进行初始化
constexpr int sz = size();//当size是一个constexpr函数时才正确

指针和constexpr:如果指针和constexpr组合,constexpr只会对指针生效,即如果声明一个指针为constexpr,则指针指向不可变。

类型别名

typedef:定义类型别名

//number是int的别名,n是int*的别名
typedef int number, *n;

//C++11中等价的新方法
using number = int;

指针、常量和类型别名:难!!!容易产生令人困惑的结果

typedef int* pint;
int i = 1;
//此时const用于修饰指针,而不是对象,可以理解
//为const修饰pint,而pint是一个指针
const pint pi = &i;//pi是指向int的常量指针,指向无法更改,对象值可以更改

//此处可以理解为pint*是声明一个指向pint的指针
//而由于pi是一个常量,所以必须用常量指针
const pint* ps = &pi;//ps是一个指针,所指对象是一个指向int的常量指针

*pi = 4;//可以通过常量指针修改对象,此时a为4
ps = &ps;//ps是一个指针,可以修改指向,但所指的对象无法修改指向
**ps = 1;//通过所指对象的所指对象修改b的值,此时b为1

auto类型说明符

auto:C++11中引入的类型说明符,将类型判断交给编译器,必须进行初始化。在复杂的复合类型中非常好用。(通常是*const等各种关键字的复杂组合,有时候难以判断是什么类型,只知道怎么使用这个类型,这时候就可以用auto)

另外,auto通常会省略掉顶层const,但会保存底层const,如果希望推断出的auto是顶层const,需要显式指出。例如:const auto &i = 1;,是一个常量整数引用。

int i = 1;
auto j = i;//编译器通过i判断j的类型

//一个只能用auto的例子,可以暂时不用理解什么是lambda表达式
//我们无法准确知道f的类型,但知道如何使用它
auto f = []{return "hello";}
cout << f << endl;

decltype类型指示符

decltype:C++11中引入的一种类型说明符,通过编译器分析表达式的类型,但并不会计算值。用途和auto类似。

decltype和引用:例如decltype(*p)的结果是int&而非int(p是指向int的指针)。

另外,decltype对括号敏感,delctype((...))一定是一个引用。

int i = 1;
decltype(i) j = 2;//通过i的类型来判断j的类型

头文件

本博客有一篇关于头文件的文章,介绍了基本的头文件保护符的使用示例。(文章链接

头文件保护符:

  • #define:把一个名字设定为于处理变量
  • #ifdef:当变量已定义时为真
  • #ifndef:当变量未定义时为真
  • #endif:当条件为真时,执行中间的语句直到#endif

未列入知识点

由于该部分的知识较为深入,当前阶段不易理解或使用,完整写出来篇幅较大。所以单独列出来,学有余力或兴趣的,可以自行去书中阅读。

void*指针:可以用于存放任意类型的地址,但解读内存地址中的内容的方式未知。(726页有详细介绍)

上一篇 下一篇

评论 | 0条评论