C++ primer 5th 第2章 变量和基本类型
=====================================================================
第2章 变量和基本类型 030页
=====================================================================
算术类型(arithmetic type)
表2.1:C++:算术类型 |
||
bool |
布尔类型 |
未定义 |
char |
字符 |
8位 |
wchar_t |
宽字符 |
16位 |
char16_t |
Unicode字符 |
16位 |
char32_t |
Unicode字符 |
32位 |
short |
短整型 |
16位 |
int |
整形 |
16位 |
long |
长整型 |
32位 |
long long |
长整型 |
64位 |
float |
单精度浮点型 |
6位有效数字 |
double |
双精度浮点型 |
10位有效数字 |
long double |
长双精度浮点型 |
10位有效数字 |
=====================================================================
第2章 变量和基本类型 034-35页 类型
=====================================================================
//QQ108201645编写
#include
int main()
{
//大括号采用局部定义,防止变量名冲突
{
std::cout << "第1部分" << std::endl;
unsigned u = 10;
int i = -42;
std::cout << i + i << std::endl;//输出-84
std::cout << u + i << std::endl;//输出4294967264
}
{
std::cout << "第2部分" << std::endl;
unsigned u1 = 42, u2 = 10;
std::cout << u1 - u2 << std::endl;//输出32
std::cout << u2 - u1 << std::endl;//输出4294967264
}
{
std::cout << "第3部分" << std::endl;
for (int i = 10; i >= 0; --i)
{
std::cout << i << std::endl;
}
}
{/*
std::cout << "第4部分" << std::endl;
for (unsigned u = 10; u >= 0; --u)//意味着死循环,变量u永远不会小于0
{
std::cout << u << std::endl;
}
*/
}
{
std::cout << "第5部分" << std::endl;
//用while来代替for循环
unsigned u = 11;
while (u > 0)
{
--u;
std::cout << u << std::endl;
}
}
{
std::cout << "第6部分" << std::endl;
unsigned u = 10, u2 = 42;
std::cout << u2 - u << std::endl;
std::cout << u - u2 << std::endl;
int i = 10, i2 = 42;
std::cout << i2 - i << std::endl;
std::cout << i - i2 << std::endl;
std::cout << i - u << std::endl;
std::cout << u - i << std::endl;
}
getchar();//接收回车关闭
return 0;
}
=====================================================================
第2章 变量和基本类型 037页
换行\n 横向制表符\t 报警\a
纵向制表符\v 退格\b 双引号\"
反斜线\\ 问号\? 单引号\'
回车符\r 进纸符\f
换行\12 空格\40 空字符\0
表2.2:字符和字符串字面值 |
|||
前缀 |
含义 |
|
类型 |
u |
Unicode16字符 |
|
char16_t |
U |
Unicode32字符 |
|
char32_t |
L |
宽字符 |
|
wchar_t |
u8 |
UTF-8(仅用字符串面字符) |
|
char |
整形字面值 |
浮点形字面值 |
||
后缀 |
最小匹配类型 |
后缀 |
类型 |
u or U |
unsigned |
f或F |
float |
l or L |
long |
l或L |
long double |
ll or LL |
long long |
|
|
=====================================================================
第2章 变量和基本类型 040页
表2.3:C++关键字 |
||||
alignas |
continue |
friend |
register |
true |
alignof |
decltype |
goto |
reinterpret_cast |
try |
asm |
default |
if |
return |
typedef |
auto |
delete |
inline |
short |
typeid |
bool |
do |
int |
signed |
typename |
break |
double |
long |
sizeof |
union |
case |
dynamic_cast |
mutable |
static |
unsigned |
catch |
else |
namespace |
static_assert |
using |
char |
enum |
new |
static_cast |
virtual |
char16_t |
explicit |
noexcept |
struct |
void |
char32_t |
export |
nullptr |
switch |
volatile |
class |
extern |
operator |
template |
wchar_t |
const |
false |
private |
this |
while |
constexpr |
float |
protected |
thread_local |
|
const_cast |
for |
public |
throw |
|
=====================================================================
第2章 变量和基本类型 044页 全局对象与局部对象
=====================================================================
//QQ108201645编写
#include
int reused = 42;
int main()
{
int unique = 0;//unique拥有块作用域
//输出#1:使用全局变量reused;输出42 0
std::cout << reused << " " << unique << std::endl;
int reused = 0;//新建局部变量reused,覆盖了全局变量reused
//输出#2:使用全局变量reused,输出0 0
std::cout << reused << " " << unique << std::endl;
//输出#3:显示的访问全局变量reused;输出42 0
std::cout << ::reused << " " << unique << std::endl;
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 045页 引用
=====================================================================
//QQ108201645编写
#include
int main()
{
int ival = 1024;
int &referenceVal = ival;
std::cout << "referenceVal = "<
=====================================================================
第2章 变量和基本类型 048页 指针
=====================================================================
//QQ108201645编写
#include
int main()
{
int *p1 = nullptr;//等价于*p1=0
int *p2 = 0;//直接初始化为0
int *p3 = NULL;//等价于*p3=0
if (p1==p2&&p2==p3&&p3==0)
{
std::cout << "p1 and p2 and p3 of Null" << std::endl;
}
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 049页-52 指针
=====================================================================
//QQ108201645编写
#include
int main()
{
{
int i = 42;
int *pi = 0;//pi被初始化,但没有指向任何对象
int *pi2 = &i;//pi2被初始化,存有i的地址
int *pi3;//如果pi3定义于块内,则pi3的值是无法确定的
pi3 = pi2;//pi3和pi2指向同一个对象i
pi2 = 0;//现在pi2不指向任何对象了
}
{
int ival = 1024;
int *pi = &ival;//pi的值被改变了指向了ival
*pi = 0;//ival的值被改变,指针pi并没有改变
int *pi2 = &ival;//pi2是一个合法的指针,存放着ival的地址
if (pi)//pi的值是0,因为条件值是false
{
;
}
if (pi2)//pi2指向ival,因些它的值不是0,条件值为true
{
;
}
{
double obj = 3.14, *pd = &obj;
//void *能存放任意类型对象的地址
void *pv = &obj;//obj可以是任意类型的对象
pv = pd;//pv可以存放任意类型的对象
}
}
//练习题2.20
{
int i = 42;//
int * p1 = &i;//p1指针存放i变量的地址
*p1 = *p1 *= *p1;//*p1存放i的地址里的值相乘
std::cout << "*p1 = " << *p1 << std::endl;
}
//练习题2.21
{
int i = 0;
//double *bp = &i;//int 不能转换为double
//int *ip = i;//不能将int 初始化给int *
int *p = &i;//把i的地址存放在p正确,指针p指向i的地址
}
//练习题2.22
//if(p)//p是一个int 型指针,如果!=0表示有存放int类型地址,条件为true
//否则为false
//if(*p)//判断p指针所指向地址的值是否为0,不是0,条件为true,否则为false
{
int i = 1024;
int *p = &i;//p指向i的地址
int &r = i;//r是i地址的引用
std::cout << "i = " << i << std::endl;
std::cout << "p = " << p << "\t *p = " << *p << "\t &p = " << &p << std::endl;
std::cout << " &r = " << &r << " r = " << r << std::endl;
r = 6;
std::cout << "r = " << r << "\t i = " << i << "\t *p = " << *p << std::endl;
}
{
//int *p1, p2;//p1是指向int 类型的指针,p2是int
//int *p1,*p2//p1和p2都是指向int 类型的指针
//int *p1;
//int *p2;//同上
}
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 052页 指针的指针,指针引用
=====================================================================
//QQ108201645编写
#include
int main()
{
int ival = 1024;
int *pi = &ival;//pi指向一个int 型的地址
int **ppi = π//ppi是指针的指针。指向一个int 型指针的地址
std::cout << "The value of ival\n"
<< "direct value: " << ival << "\n"
<< "indirect value: " << *pi << "\n"
<< "doubly indirect value: " << **ppi
<< std::endl;
int i = 42;
int *p;//p是一个int类型指针
int *&r = p;//r是一个对指针p的引用//*r表示r引用的是一个指针
r = &i;//r引用了一个指针,因此给r赋值&i就是令p指向i
*r = 0;//解引用r得到i,也就是p指向的对象,将i的值改为0
int** &a = ppi;
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 053页 const限定符
=====================================================================
//QQ108201645编写
//定义一个get_size.h头文件
//extern int j;//其它文件可以声明一下就可以使用j
//输入如下内容
#ifndef _GET_SIZE_
#define _GET_SIZE_
extern const int x;//可以在文件间共享,不用单独定义
int get_size()
{
return x;//返回extren const int x的值
}
#endif
―――――――――――――――――――――――――――――――――――――――
#include
extern const int x = 10;//确保在#include "get_size.h"前,调用文件头能调用到extren const int x
//extern 可以让一个定义在多文件下共享
#include "get_size.h"
int main()
{
const int bufSize = 512;
//bufSize = 512;//非法,常量一经初始化就不能改变里面的值
const int i = get_size();//正确编译时初始化
//const int k;//错误;k是一个未经初始化的常量
{
int i = 42;
const int ci = i;//正确: i的值赋值给了ci;
int j = ci;//正确: ci的值赋值给了j
}
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 055页 常量的引用
=====================================================================
//QQ108201645编写
#include
int main()
{
int i = 42;
const int &r1 = i;//允许将const int&绑定到一个普通int 对象上
//正确:r1是一个常量引用
const int& r2 = 42;
const int &r3 = r1 * 2;//r3是一个常量引用
//int &r4 = r1 * 2;//错误:r4是一个普通的非常量引用
double dval = 3.14;
const int &ri = dval;//初始化”: 从“double”转换到“const int”,可能丢失数据
const int temp = dval;//由双精度浮点数生成的一个临时的整型常量
//“初始化”: 从“double”转换到“int”,可能丢失数据
const int &ri1= temp;//让ri1绑定这个临时常量
//“初始化”: 从“double”转换到“const int”,可能丢失数据
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 056页 常量的引用与常量指针
=====================================================================
//QQ108201645编写
#include
int main()
{
int i = 42;
int &r1 = i;//引用ri绑定对象i
const int &r2 = i;//r2绑定对象i,但不允许通过r2修改i的值
r1 = 0;//“r1”并非常量: 能给r1赋值
//r2 = 0;//“r2”: 不能给常量赋值
const double pi = 3.14;//pi是个常量,它的值不能改变
//double *ptr = π//错误:ptr是一个普通指针
const double *cptr = π//正确:cptr可以指向一个double常量
//*ctr = 42;//错误:不能给常量指针赋值
double dval = 3.14;//dval是一个双精度浮点数,它的值可以改变
cptr = &dval;//正确:但不能通过cptr改变dval的值
int errNumb = 0;
//原理const在“*”号左边,不能通过常量改变指向对向的值
//const在“*”号右边,常量指针所指向的值不能再次指向其它地址
int *const curErr = &errNumb;//curErr将一直指向errNumb
std::cout << " errNumb = " << errNumb << " curErr = " << *curErr << std::endl;
*curErr = 6;
std::cout << " errNumb = " << errNumb << " curErr = " << *curErr << std::endl;
const double PI = 3.14159;
const double *const pip = &PI;//pip是一个指向常量对象的常量指针
//*pip = 2.72;//“pip”: 不能给常量赋值
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 057页 常量相关练习
=====================================================================
//QQ108201645编写
#include
int main()
{
int i2=0;
//练习a
{
int i = -1;
//int &r = 0;//无法从“int”转换为“int &”
}
//b
{
int *const p2 = &i2;
}
//c
{
const int i = -1;
//int &r = 0; //“初始化”: 无法从“int”转换为“int &”
}
//d
{
const int *const p3 = &i2;
}
//e
{
const int *p1 = &i2;
}
//f
{
//const int &const r2;//“r2”: 必须初始化引用
}
//g
{
int i=0;
const int i2 = i, &r = i;
}
{
//练习2.28
//a
int i=0;
//int *const cp;//“cp”: 如果不是外部的,则必须初始化常量对象
//b
int *p1=0;
//int *const p2;//p2”: 如果不是外部的,则必须初始化常量对象
//c
//const int ic,&r = ic;//“ic”: 如果不是外部的,则必须初始化常量对象
//d
//const int *const p3;//p3”: 如果不是外部的,则必须初始化常量对象
//e
const int *p=0;
{
//练习2.29
const int ic = 5;
int i = ic;
//p1 = p3;//无法从“const int *const ”转换为“int *”
//p1 = ⁣//无法从“const int *”转换为“int *”
const int *const p3 = ⁣
int *const p2 = p1;
//ic = *p3;//“ic”: 不能给常量ic赋值
}
}
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 057页 const 底层与顶层
=====================================================================
//QQ108201645编写
#include
int main()
{
//在"*"左边的是底层const,右边的是顶层const
int i = 0;
int* const p1 = &i;//不能改p1的指向,这是一个顶层const
const int ci = 42;不能改ci的指向,这是一个顶层const
const int *p2 = &ci;//不能改变p2的值。这是一个底层const
const int *const p3 = p2;//靠右的const是顶层const,靠左是底层const
const int &r = ci;//用于声明引用的都是底层const
/*const */ //int * p = p3;//错误p3包含底层const的定义,而p没有
p2 = p3;//正确p2和p3都是底层的const
p2 = &i;//正确int* 能转换成const int*
//int &r=ci;//错误const的int& 不能绑定到一个普通int
const int &r2 = i;//正确cont int&可以绑定在一个普通int上
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 058页 const 底层与顶层
=====================================================================
//QQ108201645编写
#include
int main()
{
//练习2.30
//在"*"右边的是顶层const,左边的是底层
const int v2 = 0;//v2 是顶层const
int v1 = v2;//v1是普通int 把v2赋值给v1
int *p1 = &v1, &r1 = v1;//把*p1指向v1,把引用&r1绑定v1
const int *p2 = &v2, *const p3 = &r1, &r2 = v2;//p2是底层const,p3 是顶层const+底层const
r1 = v2;//v2是顶层const
//p1 = p2;//p1没有底层const
p2 = p1;
//p1 = p3;//p1没有p3这个底层const
p2 = p3;
int x;
const int* const y = &x;
const int *const &xx = y; //xx是一个对指针y的引用//*xx表示xx引用的是一个指针
system("pause");
return 0;
}
=====================================================================
第2章 变量和基本类型 058页 constexpr与常量
=====================================================================
//QQ108201645编写
//保存为文件头get_size.h
#ifndef _GET_SIZE_
#define _GET_SIZE_
//const int num = 10;失败
constexpr int get_size()
{
return 10;//返回10
}
#endif
―――――――――――――――――――――――――――――――――――――――
#include
#include "get_size.h"
int main()
{
{
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();
}
{
//声明为constexpr类型可以由编译器来验证变量是不是常量表达式
constexpr int mf = 20;//20是常量表达式
constexpr int limit = mf + 1;//mf+1是常量表达式
constexpr int sz = get_size();//只有当size是一个constexpr函数时
//才是一条正确的声明
}
}
=====================================================================
第2章 变量和基本类型 059页 constexpr常量、指针
=====================================================================
//QQ108201645编写
#include
int main()
{
{
const int *p = nullptr;//p指向整型常量(底层const)
/*例子
const int ci = 42;不能改ci的指向,这是一个顶层const
const int *p2 = &ci;//不能改变p2的值。这是一个底层const
*/
constexpr int* q = nullptr;//q是一个指向整数的常量指针(顶层const)
std::cout << q << std::endl;
}
{
constexpr int* np = nullptr;//np是一个指向整数的常量指针,值为空
int j = 0;
constexpr int i = 42;//i的类型是整型常量(顶层const)
//i和j都必须定义在函数体外
constexpr const int *p = &i;//p是常量指针指向整型常量这里面的const是底层const
//constexpr是顶层const
constexpr int *p1 = &j;//p1是常量指针,指向整数j
}
}
=====================================================================
第2章 变量和基本类型 060页 typedef类型别名
=====================================================================
//QQ108201645编写
#include
#include "Sales_item.h"
int main()
{
typedef double wages;//wages是double的同义词
typedef wages base, *p;//base是double的同义词,p是double*的同义词
/*constexpr int i = 42;
constexpr const int* pp = &i;*/
using Si = Sales_item;//Si是Sales_item的同义词
using int_ = unsigned char;//int_ 是char的同义词
char nstr=0;
typedef char *pstring;
const pstring cstr = &nstr;//cstr是指向char的常量指针
const pstring *ps=&cstr;//ps是一个指针,它的对象是指向char的常量指针
const char tostr=0;
const char * ntstr = &tostr;
}
=====================================================================
第2章 变量和基本类型 061页 auto 类型说明符《未用system(“pause”) 请用f11调试
=====================================================================
//QQ108201645编写
#include
int main()
{
int val1 = 9;
int val2 = 2;
//auto从右到左。处理第一个开始推断类型
auto item = val1 + val2;//由val1与val2相加推断出itemr相加的结果
std::cout << item << std::endl;
auto i = 0, *p = &i;//正确:i是整数,p是整数指针
//auto sz = 0, pi = 3.14;//错误:sz与pi的类型不一样
}
=====================================================================
#include
int main()
{
int i = 0, &r = i, number = 3, &variable = number, price = 4;
auto a = r;//a是一个整数(r是i的别名,而i是一个整数)
//auto会忽略顶层const
const int ci = i, &cr = ci;
auto b = ci;//b 是一个整数(ci的顶层const 被忽略掉了)等同于int类型的 b = ci
//ci = 8;不能给常量赋值
b = 8;//顶层const被忽略后可以给b赋值
std::cout << "ci = " << ci << "\t cr = " << cr << "\t b = " << b << std::endl;
//---------------------------------
auto c = cr;//c是一个整数(cr是ci的别名,ci本身是一个顶层const)等同于int类型的 c = cr
c = variable;
std::cout << "c = " << c << std::endl;
c = price;
std::cout << "c = " << c << std::endl;
//---------------------------------
auto d = &i;//d是一个整形指针(整数的地址就是指向整数的指针)等同于int*类型的 d = &i
std::cout << "d = " << d << std::endl;
*d = 6;
std::cout << "d = " << d <<"\t i = "<=====================================================================
//2.33-2.34练习
auto a = 42;//a是整数
auto b = 42;//b是整数
auto c = 42;//c是整数
auto d = 42;//错误:d是int*
auto e = 42;//错误:e是const int *
auto g = 42;//错误:g是一个常量引用,绑定到ci
//练习2.35
#include
int main()
{
const int i = 42;//顶层const
auto j = i;//j是一个int 整型
std::cout << " i = " << i << "\t j = " << std::endl;
const auto &k = i;//k是一个常量引用,绑定到i
std::cout << " k = " << k << std::endl;
auto *p = &i;//p等同于cosnt int * (底层const)
int number = 9;
p = &number;//可以改变指针的指向,但不能通过指针改变内容
}
=====================================================================
第2章 变量和基本类型 063页 decltype类型指示符
=====================================================================
//QQ108201645编写
#include
int f()
{
return 0;
}
int main()
{
int num = 3;
decltype(f()) sum= num;//f()返回类型定义为int,所以sum类型是int
//编译器并不实际调用函数f,
//而是使用当调用发生时f的返回值类型作为sum的类型。
//换句话说,编译器为sum指定的类型是什么呢?就是假如f被调用的话将会返回的那个类型。
std::cout << sum << std::endl;
//decltype使用表达式是一个变量,则包含这个变量的类型(顶层const和引用在内)
const int ci = 0, &cj = ci;
decltype(ci) x = 0;//x的类型是const int,初始化为0
decltype(cj) y = x;//y的类型是const int &,y绑定到x
//decltype(cj) z;//错误:z是一个引用,必须初始化
int i = 42, *p = &i, &r = i;
decltype(r + 0) b;//正确:加法结果是int,因此b是一个未经初始化的int
//decltype(*p) c;//错误,c是int&,必须初始化
decltype(p) c=&i;//c是int*,必须初始化
//-----------------------
//如果decltype的表达式加上括号的变量,结果将是引用
//decltype((i)) d;//错误:d是int& ,必须初始化
decltype((i)) d = num;
//加上双层括号就永远是引用,如果只有一个括号就只当variable是引用是才是引用
std::cout << "d = " << d << std::endl;
decltype(i) e;//正确:e是一个未初始化的int
}
=====================================================================
//练习2.36
#include
int main()
{
int a = 3, b = 4;
decltype(a) c = a;
decltype((b))d = a;
std::cout << "a = " << a << "\t b = " << b << "\t c = "
<< c << "\t d = " << d << std::endl;
++c;//c的值++
++d;//引用++就是++a
std::cout << "a = " << a << "\t b = " << b << "\t c = "
<< c << "\t d = " << d << std::endl;
}
/*
输出
a = 3 b = 4 c = 3 d = 3
a = 4 b = 4 c = 4 d = 4
*/
=====================================================================
//练习2.37
#include
int main()
{
int a = 3, b = 4;
decltype(a) c = a;
decltype(a = b)d = a;//这个是int&引用,其它是int
std::cout << " a = " << a << "\t b = " << b<< "\t c = "
<< c << "\t d = " << d << std::endl;
system("pause");
}
=====================================================================
第2章 变量和基本类型 064页 定义Sales_item类型
=====================================================================
//QQ108201645编写
//保存为Sales_data.h头文件
#ifndef _SALES_DATA_H_
#define _SALES_DATA_H_
struct Sales_data
{
std::string bookNo;
unsigned units_sold = 0;//c++11开始支持类体内初始化(变量名译:单独售出)
double revenue = 0.0;//初始化revenue(译:财政收入)
};//这里要加分号
#endif
―――――――――――――――――――――――――――――――――――――――
#include
#include //包含string头文件
#include "Sales_data.h"
int main()
{
Sales_data data1, data2;
//读入data1与data2的代码
//检查data1与data2的isbn是否相同
//如果相同,求两个总和
double price = 0;//书的单价
std::cout << "输入第1笔交易:书的编号、销售数量、单价" << std::endl;
std::cin >> data1.bookNo >> data1.units_sold >> price;
//调用方法对象名.成员/或者对象名.成员函数
//计算销售收入
data1.revenue = data1.units_sold*price;
std::cout << "输入第2笔交易:书的编号、销售数量、单价" << std::endl;
std::cin >> data2.bookNo >> data2.units_sold >> price;
data2.revenue = data2.units_sold*price;//财政收入等于数量乘单价
if (data1.bookNo == data2.bookNo)
{
unsigned totalCnt = data1.units_sold + data2.units_sold;
double totalRevenue = data1.revenue + data2.revenue;
std::cout << data1.bookNo << " " << totalCnt
<< " " << totalRevenue << std::endl;
if (totalCnt != 0)
{
std::cout << totalRevenue / totalCnt << std::endl;
}
else
{
std::cout << "(no sales)" << std::endl;
}
//标示成功
}
else
{
//两笔交易的ISBN不一样
std::cerr << " Data must refer to the same ISBN"
<< std::endl;
//标示失败
}
system("pause");
return 0;
}
=====================================================================