C++Primer-第二章 变量和基本类型

第二章 变量和基本类型

数据类型是程序的基础:它告诉我们数据的意义及我们能在数据上执行的操作

2.1 基本数据类型

C++定义了一套包括算术类型空类型在内的基本数据类型

2.1.1 算术类型

算术类型:

  • 整型
  • 浮点型
    在这里插入图片描述
    布尔类型的取值是或者
    带符号类型和无符号类型
    除去布尔型和扩展的字符之外,其他整型可以划分为 带符号的无符号的。带符号的可以表示正数、负数、0,无符号类型仅可以表示大于等于0的值。
    • 类型 int、short、long、和 long long都是带符号的
    • 类型 unsigned int、unsigned short、unsigned long和 unsigned long long都是无符号的

如何选择类型

  • 当明确知晓数值不可能为负时,选用无符号类型
  • 使用int执行整数运算。如果数值超过int的数值范围,则选用long long
  • 在算术表达式中不要使用char或bool,只有在存放字符或者布尔值时才使用他们
  • 执行浮点数运算选用double
2.1.2 类型转换

对象的类型定义了对象能包含的数据和能参与的运算,其中一种运算被大多数类型支持,就是将对象从一种类型转换为另一种类型。
类型所能表示的值的范围决定了转换的过程:

  • 当我们把一个非布尔类型的算术值付给布尔类型时,初始值是0 则结果为false,否则结果为true
#include <iostream>
using namespace std;
int main()
{
	int intVal=12;
	bool boolVal=intVal;
	cout<<"boolVal:"<<boolVal<<endl;
	return 0;
}
结果: 
boolVal:1
  • 当我们把一个布尔值赋给非布尔类型时,初始值为false 则结果为0,初始值为true 则结果为1
#include <iostream>
using namespace std;
int main()
{
	bool boolTrueVal=true;
	bool boolFalseVal=false;
	int intTrueVal=boolTrueVal;
	int intFalseVal=boolFalseVal;
	cout<<"intTrueVal:"<<intTrueVal<<endl;
	cout<<"intFalseVal:"<<intFalseVal<<endl;
	return 0;
}
结果:
intTrueVal:1
	 intFalseVal:0
  • 当我们把一个浮点数赋给整数类型时,进行了近似处理。结果值将仅保留浮点数中小数点之前的部分。
#include <iostream>
using namespace std;
int main()
{
	double doubleVal=3.1415926;
	int intVal=doubleVal;
	cout<<"intVal:"<<intVal<<endl;
	return 0;
}
结果:
intVal:3
  • 当我们把一个整数值赋值给浮点类型时,小数部分记为0。如果该整数所占的空间超过了浮点类型的容量,经度可能有损失。
#include <iostream>
using namespace std;
int main()
{
	int intVal=120;
	float doubleVal=intVal;
	cout<<"doubleVal:"<<doubleVal<<endl;
	return 0;
}
结果:
doubleVal:120
这地方在输出结果的时候给格式化了
  • 当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。
#include <iostream>
using namespacestd;
int main()
{
	//unsigned int的最大值为 4294967296
	unsigned int intVal;
	intVal = 9999999999999999999;
	cout << "intVal:" << intVal << endl;
	//取模
	unsigned intMod = 9999999999999999999 % 4294967296;
	cout << "intMod:" << intMod << endl;
	return 0;
}
结果:
intVal:2313682943
intMod:2313682943
  • 当我们赋给带符号类型一个超出它表示范围的值时,结果是错误值。(此处应注意)
#include <iostream>
using namespace std;
int main()
{
	int intVal=9999999999999999999;
	cout<<"intVal:"<<intVal<<endl;
	return 0;
}
结果:
intVal:-1981284353
2.1.3 字面值常量

一个形如42的值被称作字面值常量。

  • 整型和浮点型字面值
20 //十进制
024 //八进制
0x14 //十六进制
  • 字符和字符串字面值
'a' //字符字面值
"Hello world!" //字符串字面值
  • 转义序列
名称字符名称字符名称字符
换行符\n横向制表符\t报警(响铃)符\a
纵向制表符\v退格符\b双引号\"
反斜杠\问号\?单引号\’
回车符\r进纸符\f
  • 指定字面值类型
L'a' //字符串类型字面值,类型是wchar_t
u8"hi" // utf-8字符串字面值
42ULL //无符号整型字面值,类型是unsigned long long

在这里插入图片描述

  • 布尔字面值和指针字面值
//布尔字面值是 true 和 false
bool trueVal=true;
bool falseVal=false;
//nullptr是指针字面值(指针模块)
int* pIntVal=nullptr;

2.2 变量

变量提供一个具名的,可供程序操作的存储空间。
个人理解就是:有很多存放不同物品的仓库,我把每个仓库都取上名字。

2.2.1 变量的定义

变量定义的基本形式:类型说明符 由一个或多个变量名

int sum=0,value=0,units_sold=1; //sum value和units_sold都是int
Sales_item item; //item类型是Sales_item
  • 初始值
//price先被定义并赋值,随后被用于初始化discount
double price=109.99,discount=price*0.16;
//age 先定义  然后赋值
int age;
age=10;
  • 列表初始化
int units_sold=0;
int units_sold={0};
  • 默认初始值
    如果定义变量时没有指定初值,则变量被默认初始化,此时变量被赋予了默认值
    全局变量在声明时会把初始化;局部变量在声明时不会被初始化
2.2.2 变量声明和定义的关系
  • 声明:使得名字为程序所知。(例如:做饭的时候需要有汤勺,锅,刀等等。只是有这些东西,用不用另说)
  • 定义:负责创建于名字关联的实体。(例如:做饭的时候使用到的汤勺,锅等等)
2.2.3 标识符

C++的标志符由 字母、数字、下划线组成,其中必须以字母或下划线开头。

  • 变量命名规范
    • 标志符要能体现实际含义。
    • 变量名一般用小写字母,如index,不要用Index或者INDEX。
    • 用户自定义类型一般以大写字母开头,如Sales_item。
    • 如果标识符由多个单词组成,则单词间应有明显区分,如student_loan或studentLoan。

对于命名规范来说,若能坚持,必将有效

命名规范不是c++语言硬性规定的,只是在写代码的时候便于识别和理解的约定,团队可以根据情况自行规定风格。可以参考 Google、微软等大公司的风格。

  • c++关键字
    在这里插入图片描述
  • C++操作符替换名
    在这里插入图片描述
2.2.4 名字的作用域

作用域是程序的一部分,在其中名字有其他特定的含义。C++语言中大多数作用域以花括号分隔。(说的不明不白的)
个人理解:作用域就是名字的使用范围。例如:学校里的班级,在这个学校里可以直接说哪个班,但是在学校以外就要指定学校名称+班级名称。

  • 嵌套作用域
    作用域能彼此包含,被包含的作用域成为内层作用域,包含着别的作用域的作用域称外层作用域

2.3 符合类型

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

2.3.1 引用

引用 为对象起了另一个名字,引用类型引用另外一种类型。通过将声明符写成&d的形式定义引用类型,其中d是声明的变量名。

int iVal=1024;
int &refVal=iVal; //refVal指向iVal
int &refVal2; //报错:引用必须被初始化
  • 引用即别名

引用并非对象,相反的,它只是为一个已经存在的对象所取的另外一个名字。
对引用类型的所有操作都是在与之绑定的对象上进行的。

2.3.2 指针
  • 指针是执行另外一种类型的符合类型。与引用类似,指针也实现了对其他对象的间接访问。
    • 指针本身就是一个对象,允许对指针赋值和拷贝。与引用不同。
    • 指针无需在定义时赋值。
  • 获取指针的地址
    &:取地址符
int iVal=20;
int *p=&iVal; //p 存放变量iVal的地址,或者说p指向变量iVal的指针
指向
*p指针
iVal
  • 指针值
    指针值应属于下列4中状态之一:
  1. 指向一个对象。
  2. 指向紧邻对象所占空间的下一个位置。
  3. 空指针,意味着指针没有指向任何对象。
  4. 无效指针,依旧是上述情况之外的其他值。
  • 利用指针访问对象
    *:解引用符(操作符*)
int iVal=40;
int *p=&iVal;//p存放着变量iVal的地址
cout<<"*p:"<<*p<<endl;//由符号*得到指针p所指向的对象
  • 空指针
    空指针:不指向任何对象的指针。
int *p1=nullptr;//等价与 int *p1=0;
int *p2=0;
//需要引入 cstdlib头文件
int *p3=NULL;
//上方三者等价
  • 赋值和指针
int i=42;
int *pi=0;	//pi被初始化,但没有指向任何对象
int *pi2=&i;//pi2被初始化,存有i的地址
int *pi3;	// pi3被定义,值无法确定

pi3=pi2;	//pi3和pi2指向同一个对象i
pi2=0;		//pi2不指向任何对象
  • void* 指针
    void*是一种特殊的指针,可用于存放任意对象的地址。
double obj=3.14,*pd=&obj;
void *pv=&obj;//正确:void* 能存放任意类型对象的地址
pv=pd; //pv可以存放任意类型的指针
2.3.3 理解符合类型的声明
  • 定义多个变量
int* p1,p2;		//p1是指向int的指针,p2是int  容易产生误导
int *p1,p2;		//推荐写法
  • 指向指针的指针
int iVal=1024;
int *pi=&iVal;		//pi指向一个int类型的数
int **ppi=&pi;		//pi指向一个int型的指针

在这里插入图片描述

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

2.4 const限定符

const: 用const修饰的变量的值不能被改变。

  • 初始化和const
int i=1024;
const int ci=i;		//正确:i的值被拷贝给了ci
int j=ci;			//正确:ci的值被拷贝给了j
2.4.1 const的引用
  • 初始化和对const的引用
int i=1024;			//定义i
const int &r1=i;	//正确:允许将const int&绑定到一个普通int对象上
const int &r2=2048;	//正确:r1是一个常量引用
const int &r3=r1*2;	//正确:r3是一个常量引用
int &r4=r1*2;		//错误:r4是一个普通的非常量引用
2.4.2 指针和const
  • 指向常量的指针指针常量
const double pi=3.14;//pi是一个常量,它的值不能改变
double *ptr=&pi;	 //错误:ptr是一个普通指针
const *cptr=&pi;	 //正确:cptr可以指向一个双精度常量
*cptr=1024;			 //错误:不能给*cptr赋值

也就是说 指针保存的地址是能改变的,保存的地址指向的对象是不可以变的

  • const指针常量指针
    指针是对象而引用不是,因此就像其他对象类型一样,运行把指针本身定位常量。
    常量指针必须初始化,而且一旦初始化完成,则它的值就不能再改变了。
int errNumb=0;
int *const curErr=&errNumb; //curErr将一直指向errNumb
const double pi=3.14159;
const double *const pip=&pi; //pip是一个指向常量对象的常量指针

指针所保存的地址是不可以改变的,保存地址所指向的对象是可以改变的

2.4.3 顶层底层const
  • 顶层const:指针本身是个常量
  • 底层const:指针所指的对象是一个常量
2.4.4 constexpr和常量表达式
  • 常量表达式:值不会改变并且编译过程就能得到计算结果的表达式。
const int max_files=20;		//max_files是常量表达式
const int limit=max_files+1;	//limit是常量表达式
int staff_size=27;				//staff_size不是常量表达式
const int sz=get_size();		//sz不是常量表达式
  • constexpr变量
    C++11新标准规定,运行将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。
constexpr int mf=20;		//20是常量表达式
constexpr int limit=mf+1;	//mf+1是常量表达式
constexpr int sz=size();	//只有当size是 一个constexpr函数时,才是一个正确的声明语句
  • 指针和constexpr
    在constexpr生命中如果定义了一个指针,限定符constexpr仅对指针有效,与指针所指的对象无关。
const int *p = nullptr;	//p是一个指向整型变量的指针
constexpr int *q = nullptr;	//q是一个指向整数的常量指针
// p和q相差甚远,p是一个指向常量的指针,而q是一个指针常量,
// 其中关键字constexpr把它所定义的对象置为顶层const

2.5 处理类型

2.5.1 类型别名

类型别名 是一个名字,它是某种类型的同义词。

  • 定义类型别名
    • typedef:
    typedef double wages;	//wages是double的同义词
    typedef wages base, *p; //base是double的同义词,p是double*的同义词
    
    • using:
    using SI=Sales_item;	//SI是Sales_item的同义词
    
  • 指针、常量和类型别名
	typedef char *pstring;
	const pstring cstr=0;	//cstr是指向char的常量指针
	const pstring *ps;		//ps是一个指针,它的对象是指向char的常量指针
2.5.2 auto类型说明符

C++11新标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式所属的类型。

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

auto一般会忽略掉顶层const,同是底层const会保留下来

int i=0,&r=i;
const int ci=i,&cr=ci;
auto b=ci;	//b是一个整数(ci的顶层const特性被忽略掉了)
auto c=cr;	//c是一个整数(cr是ci的别名,ci本身是一个顶层const)
2.5.3 decltype 类型指示符

C++11新标准引入了第二种类型说明符declytype,它的作用是选择并返回操作数的数据类型

decltype(f()) sum=x; //sum类型就是函数f的返回类型
const int ci=0,&cj=ci;
decltype(ci) x=0;	//x 类型为  const int
decltype(cj) y=x;	//y的类型是 const int&, y绑定到变量x
decltype(cj) z;		//错误:z的类型是一个引用,必须初始化
  • decltype和引用
int i=1024,*p=&i,&r=i;
decltype(r+0) b;	//正确:加法的结果是int,因此b是一个(未初始化的)int
decltype(*p) c;		//错误:c是int&,必须初始化

2.6 自定义数据结构

2.6.1 定义Sales_item
struct Sales_item
{
	string bookNo;
	unsigned int units_sold=0;
	double revenue=0.0;
}salesItem,*salesItem;
2.6.2 使用Sales_item类
#include <iostream>
#include <string>
using namespace std;

struct Sales_item
{
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
}saleItem,*p_SalesItem; //此处声明一个实例,和一个指针引用

int main()
{
	saleItem.bookNo = "C++从入门到精通";
	saleItem.units_sold = 100;
	saleItem.revenue = 89;
	cout << "bookNo:" << saleItem.bookNo<<"\t unit_sold:"<<saleItem.units_sold<<"\t revenue:"<<saleItem.revenue << endl;
	p_SalesItem = new Sales_item();
	p_SalesItem->bookNo = "Effective C++";
	p_SalesItem->units_sold = 200;
	p_SalesItem->revenue = 99;
	cout << "bookNo:" << p_SalesItem->bookNo << "\t unit_sold:" << p_SalesItem->units_sold << "\t revenue:" << p_SalesItem->revenue << endl;
	delete(p_SalesItem);
	return 0;
}
2.6.3 编写自己的头文件

#define: 把一个名字设定为预处理变量
#ifdef : 当且仅当变量定义时为真(以 #endif为止)
#ifndef: 当且仅当变量未定义时为真(以 #endif为止)

#ifndef SALES_ITEM_H
#define SALES_ITEM_H
#include <string>
using namespace std;
struct Sales_item
{
	string bookNo;
	unsigned units_sold=0;
	double revenue=0.0;
}saleItem,*p_saleItem;
#endif // SALES_ITEM_H

下面的头文件和上面的等价

#pragma once   //此文件只引用一次
#include <string>
using namespace std;
struct Sales_item
{
	string bookNo;
	unsigned units_sold=0;
	double revenue=0.0;
}saleItem,*p_saleItem;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值