C++学习1 变量和基本类型
由于这部分的知识之前学习过,所以这份笔记主要起到一个查缺补漏的作用
无符号类型的表达式注意
无符号类型和有符号类型在进行运算时,系统会自动把有符号类型转化为无符号类型,因而如若此时的有符号类型为负数则会出现错误。
字面值常量
就是指的一望便知的常量,包含数字、字符、字符串、甚至转义字符等等。
变量
初始化
初始化不是赋值,初始化是指在创建变量之初对变量进行赋值(擦去指定地址的值之后填充新的值)
绝大多数类都支持无需显式初始化而定义对象,这样的类提供了一个合适的默认值。
变量声明和定义的关系
- 任何包含了显式初始化的声明均为定义
- 关键字 extern 可以作为前缀用于声明一个变量却不去定义它的场合
- 变量只能被定义一次,但是可以进行多次声明
标识符
字母数字下划线且开头不能为数字
作用域(scope)
作用域用于表征一个变量名字的适用范围。
作用域可以进行嵌套(包含),因而有内层作用域、外层作用域等等之说。
复合类型
指基于其他类型定义的类型,主要包括引用和指针。
引用(reference)
- 引用相当于为对象起了另外一个名字,引用类型引用(refers to)另外一种类型。
- 不同于对新变量初始化的复制操作,引用会使得引用的变量和引用变量捆绑在一起。
- 引用本身不是一个对象,因而无法定义引用的引用。
int ival=1024; //正常对数值进行初始化
int &refVal=ival; //引用ival,refVal相当于是其别名
int &refVal; //报错,因为引动在声明时必须定义其引用的对象
指针(pointer)
- 指针本身即是对象,因而可以对其进行各种操作
- 指针无需在定义时进行初始化
- 定义指针的方式是在变量名前面加*.
int *p;
利用指针获取对象的地址
int liangzi=20;
int *p=&liangzi;
除了少许特例,指针的类型和指向的地址中存放的变量的类型必须严格一致。
指针的值
包括四种状态:
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置
- 空指针——没有指向任何对象
- 无效指针,即1,2,3之外的其他值
利用指针访问对象
使用解引用符(*)来实现访问对象。
int liangzi=20;
int *p=&liangzi;
std::cout<<*p<<endl;
//这样便可以得到输出结果20.
空指针(null pointer)
不指向任何对象。
C++11之后可以直接使用nullptr来定义空指针。
int *p=nullptr;
曾经还使用过名为NULL的预处理变量来给指针初始化,此变量在头文件cstdlib中定义。
关于void* 指针
void* 是一种特殊的指针类型,他可以存放任意类型对象的地址。我们无法确定void* 类型到底指向了什么对象。
指向指针的指针与指向指针的引用
指向指针的指针就不赘述,给出几句代码。
int val;
int *ptr=&val; //指向一个int类型的val
int **pptr=&ptr; //指向一个指向val的指针
引用本身不是对象,因而不能定义指向引用的指针。但是指针是对象,所以可以对指针进行引用。例如:
int i=42;
int *p=nullptr;
int *&r=p; // r是一个对指针p的引用 //离r最近的&决定了r实质是一个引用
r=&i; //首先根据上一行可知r是p的引用,这一行代码使得r被赋值为i的地址,因而p指向了i(p储存着i的地址)
*r=0; //i被赋值为0
const限定符
常变量。
一般const限定只在该文件内有效,若使其完全不能被修改,可以添加extern以使得其只被定义一次。
对const的引用
一个引用对于常量引用的变量进行运算的结果进行赋值的引用必须是常量引用。但是一个常量引用却可以针对一个非常变量对象。
指针和const
也可以用指针指向常变量。
指向常量的指针(pointer to const)不能用于改变其所指对象的值。只能使用常量类型的指针指向常量对象。
而常量指针(const pointer)则是在说明指针中存储的地址即为常量。
const int *p; //pointer to const
int * const p;//const pointer
顶层const
这个还是为了区分常量指针和指向常量的指针两个东西的区别。
所谓顶层const表示指针本身就是一个常量,而底层const指指针所指的对象是一个常量。
constexpr与常量表达式
常量表达式指值不会改变且在编译过程中就可以得到运算结果的表达式。
C++11规定在变量声明时使用constexpr来规定等号右侧的赋值表达式必须为常量表达式。
处理类型
类型别名(type alias)
类型别名是指定义一个类型名字的同义词。
目前较为传统的方法是使用typedef,C++11中定义了一种新的方法。使用别名声明using。
typedef double liangzi;
typedef liangzi base, *p; //定义了base为liangzi的类型别名,*p为liangzi的类型别名(或者说p为liangzi*)
using LZ=liangzi;
auto类型说明符
C++11引入了auto类型说明符来让编译器代替我们去分析变量类型——等号右侧表达式所属类型。
因而auto定义的变量必须有初始值。
decltype
类似于auto,存在这样一种情形:我们需要利用表达式的类型来推断出要定义的变量的类型,但是我们又不希望使用该表达式的值来初始化变量。针对这种问题,C++11引入了选择并返回操作数的类型的类型说明符decltype。
const int ci=0, &cj=ci;
decltype(ci) liangzi=0; //不妨认为decltype为一个函数,因而需要使用()
decltype(cj) y=liangzi; //引用在定义时必须被初始化
int i=42, *p=&i;
decltype(*p) liangzi; //错误,liangzi是int&,是引用,因而必须得初始化 //即如果表达式是解引用操作,那么将会得到引用类型
且对于decltype,多加一层括号就会得到该变量的引用类型。
自定义数据结构
可以使用结构体strcut:
struct liangzi {
string name='liangzi';
int age=20;
string xingbie='man';
};
类内相当于产生了一个新的作用域,类内外的名字可以重复。
之后就是类。有关于类以后介绍。因为类不仅定义了数据,还定义了行为。这样才像是一个完整的数据结构。
番外:预处理器(preprocessor)概述
头文件保护符(header guard)使用的是 #define和 #ifdef #ifndef #endif 的组合。