c++ primer 第五版----学习笔记(二)

1.算术类型:字符、整型数、布尔值和浮点数;c++标准规定的尺寸的最小值:

  • c++语言规定一个int至少和一个short一样大,一个long long至少和一个long一样大。其中数据类型long long实在c++11中新定义的。
  • 带符号类型(signed),无符号类型(unsigned);在带符号类型名前添加unsigned就能得到无符号类型。
  • 如何选择类型:(1)当明确知晓数值不可能为负时,选用无符号类型。
  •                          (2)使用int执行整数运算。
  •                          (3)在算术表达式中不要使用char或bool,只有在存放字符或布尔值时才使用它们。
  •                          (4)执行浮点数运算选用double。

2.类型转换(部分重点):

  • 赋给无符号类型一个超出其表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如:8比特大小的unsigned char 可以表示0至255区间内的值,如果我们赋了一个区间以外的值,则实际的结果是该值对256取模后所得的余数。因此,把-1赋給8比特大小的unsigned char 所得的结果是255.
  • 当我们赋給带符号类型一个超出它表示范围的值时,结果时未定义的(undefined)。此时,程序可能继续工作、可能崩溃,也可能生成垃圾数据。

3.含有无符号类型的表达式:

//1.当表达式中既出现无符号数又有int值时,int值会转换成无符号数
unsigned u = 10;
int i = -42;
cout << i + i << endl;//输出-84
cout << i + u << endl;//如果int占32位,输出4294967264

//2.从无符号数减去一个值,无论该值是不是无符号数,都要确保不能为负值
unsigned u1 = 42, u2 = 10;
cout << u1 - u2 << endl;//输出32
cout << u2 - u1 << endl;//结果是取模后的值

//3.当使用无符号数作为循环变量时,注意循环控制条件

4.字面值常量(对应一种数据类型,字面值常量的形式和值决定了它的数据类型):

  • 整型和浮点型字面值:形如42、20(整型字面值),3.141519(字符型字面值)
  • 字符和字符串字面值:形如'a'(字符字面值),"hello world"(字符串字面值)
  • 转义序列(均以反斜线作为开始):
//转义序列
//  换行符\n       横向制表符\t     报警(响铃)符\a
//  纵向制表符\v    退格符\b        双引号\"
//  反斜线\\       问号\?           单引号\'
//  回车符\r       进纸符\f

cout << '\n';//转到新一行
cout << "\tHi!\n";输出一个制表符,输出"Hi!",转到新一行

//泛化转义序列示例
//  \7(响铃)   \12(换行符)  \40(空格符)
//  \0(空字符)  \115(字符M)  \x4d(字符M)

cout << '\115' << '\n';//输出M,转到新一行
  
  • 指定字面值类型(通过添加下表的前缀和后缀,可以改变字面值的类型): 

 

 

 

 

 

 

 

 

  •  布尔字面值和指针字面值:true和false(布尔字面值),nullptr(指针字面值)

5.变量初始化(对象获得一个特定的值):

  • 初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值查擦除,以一个新值替代
  • 列表初始化:用花括号来初始化变量,形如 int  units_sold{0};
  • 默认初始化:如果定义变量时没有指定初值,则变量被默认初始化

6.extern关键字:

//如果想声明一个变量而非定义它,就在变量前添加关键字extern

extern int i;  //声明i而非定义i
int j;         //声明并定义j

//extern语句如果包含初始值就不再是声明而是定义

extern double pi = 3.1416;  //定义

7.如果函数有可能用到某全局变量,则不宜再定义一个同名的局部变量

int i = 42;
int main()
{
    int i = 100;
    int j = i;
}
//程序中j的值为100,定义在外部的全局变量被同名局部变量覆盖

8.复合类型:引用和指针

(1)引用

  • 定义引用时,程序将引用和它的初始值绑定在一起
  • 引用并非对象(所以不能定义引用的引用),它只是为一个已经存在的对象所起的另外一个名字
  • 引用只能绑定对象,而不能与字面值或某个表达式的计算结果绑定在一起
int ival = 1024;
int &refval = ival;        //refval指向ival(是ival的另一个名字)
int &refval2;              //报错:引用必须被初始化

int refval4 = 10;          //错误:引用类型的初始值必须是一个对象 
double dval = 3.14;
int &refval5 = dval;       //错误:引用的类型要与绑定的对象一致

(2)指针

  • 指针本身是一个对象,允许对指针拷贝和赋值
  • 指针无须在定义时赋初值
  • 指针的类型与所指对象的类型要匹配
  • 使用nullptr初始化指针,得到空指针(0或null也可以初始化指针,但常用nullptr)
  • void *指针:一种特殊的指针类型,可以存放任意对象的地址
  • 指向指针的指针、指向指针的引用
int ival = 42;
int *p = &ival;          //p存放变量ival的地址,或者说p是指向变量ival的指针


int *p1 = nullptr;       //使用nullptr初始化指针

double obj = 3.14, *pd = &obj;
void *pv = &obj;         //obj可以是任意类型的对象
pv = pd;                 //pv可以存放任意类型的指针

int ival = 1024;
int *pi = &ival;         //pi指向一个int型的数
int **ppi = &pi;         //ppi指向一个int型的指针

int i = 42;
int *p;
int *&r = p;             //r是一个对指针p的引用
r = &i;                  //r引用了一个指针,因此给r赋值&i就是令p指向i

9.const限定符

  • const对象创建后其值不能改变,所以const对象必须初始化,初始值可以是任意复杂的表达式
  • 默认状态下,const对象只在文件内有效,不能多个文件共享;如果想在多个文件之间共享const对象,须在变量定义之前添加extern关键字
  • const的引用,若引用绑定在const对象上,则称之为对常量的引用,对常量的引用不能被用作修改它所绑定的值
  • 允许为一个常量引用绑定非常量的对象、字面值或一般表达式
  • 指向常量的指针不能用于改变其所指对象的值;只能使用指向常量的指针存放常量的地址;常量指针必须初始化
  • 顶层const表示指针本身是一个常量(任意的对象是常量),底层const表示指针所指的对象是一个常量
const int i = 42;
const int j;                //错误:const常量必须初始化

//file_1.cc定义并初始化了一个常量,该常量能被其它文件访问
extern const int bufsize = fun();
//file_1.h头文件
extern const int bufsize;   //与file_1.cc中定义的bufsize是同一个

const int ci = 1024;
const int &r1 = ci;         
r1 = 42;                    //错误:r1是对常量的引用
int &r2 = ci;               //错误:试图让一个非常量引用指向一个常量对象

const double pi = 3.14;
double *ptr = &pi;          //错误:ptr是一个普通指针
const double *cptr = &pi;   //正确:cptr可以指向一个双精度常量
*cptr = 42;                 //错误:不能给*cptr赋值

const double pi = 3.14159;
const double *const pip = &pi;//pip是一个指向常量对象的常量指针

10.constexpr和常量表达式

  • 常量表达式:指值不会改变并且在编译过程就能得到计算结果的表达式
  • c++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式
  • 一个constexpr指针的初始值必须是nullptr或者0,或者是存储于某个固定地址中的对象
const int max_files = 20;         //max_files是一个常量表达式
cosnt int limit = max_files + 1;  //limit是一个常量表达式

constexpr int mf = 20;            //20是常量表达式
constexpr int limit = mf + 1;     //mf + 1是常量表达式

constexpr int *q = nullptr;       //q是一个指向整数的常量指针

11.处理类型:类型别名、auto类型说明符,decltype类型指示符

  • 类型别名:使用关键字typedef、using来定义类型的别名
  • auto类型说明符:让编译器通过初始值来推算变量的类型
  • decltype类型指示符:选择并返回操作数的数据类型
typedef double wages;      //wages是double的同义词
using SI = Sales_item;     //SI是Sales_item的同义词

//auto声明语句只能有一种基本数据类型
auto i = 0, *p = &i;       //i是整数、p是整型指针
auto sz = 0, pi = 3.14;    //错误:sz和pi的类型不一致

auto &h = 42;              //错误:不能为非常量引用绑定字面值
const auto &j = 42;        //正确:可以为常量引用绑定字面值

decltype(f()) sum = x;     //sum的类型就是函数f的返回类型
int  i = 42;
decltype((i)) d;           //错误:d是int&,必须初始化
decltype(i) e;            //正确:e是一个未初始化的int
//切记:decltype((variable))的结果永远是引用,而decltype(variable)的结果只有当variable本身是一个引用时才是引用。

12.部分习题解答:

2.1:

short和int至少16位,long至少32位,long long至少64位;无符号类型只能表示大于0的数,有符号则能表示正数、负数和0;float精度低,double精度高

2.5、2.7、2.8:

熟悉转义序列以及指定字面值类型

2.10:

string global_str;   //初值为空字符串
int global_int;     //初值为0
int main()
{
    int local_int; //初值不确定
    string local_str;  //初值为空字符串
}

2.17:

int i, &ri = i;
i = 5; ri = 10;     //首先将i赋值为5,通过指针将i的值改为10
cout << i << " " << ri << endl;  //输出结果10 10

2.18:

#include <iostream>
using namespace std;
int main()
{
    int a = 0, b = 1;
    int *pi = &a, *pv = pi;
    pi = &b;  //改变了指针的值
    *pv =b;   //改变了指针所指对象的值
    return 0;
}

2.23:

不能,指针是否有效还未知!!

2.27:

(a)引用r的赋值对象必须是一个对象,不合法

(b)合法,将p2设置为常量指针,初始化为i2对象的地址

(c)合法,将i设置为常量,r设置为常量的引用(const int &r = 0正确,而int &r = 0不正确)

(d)合法,p3为指向常量的常量指针,初始值为i2的地址

(e)合法,p1为指向常量的指针,初始值为i2的地址

(f)使用不合法

(g)合法,正常赋值

2.30:

v2是顶层const;p2是底层const;p3最左是底层,右边是顶层const

其他都不是const

2.31:

顶层const拷贝不受限制,但是底层const的拷贝对象必须具有相同的底层const资格。

2.36:

a是int类型 4

b是int类型 4

c是int类型 4

d是int &类型 4

2.39:

[error] expected ';' after struct definition

2.41、2.42:

//Sales_data.h
struct Sales_data {
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};

//Sales_data.cpp
#include<iostream>
#include<string>
#include "Sales_data.h"
using namespace std;

int main()
{
	Sales_data data1, data2;
	double price ;
	cin >> data1.bookNo >> data1.units_sold >> price;
	data1.revenue = data1.units_sold * price;
	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;
		cout << data1.bookNo << " " << totalcnt << " " << totalrevenue << " ";
		if (totalcnt != 0)
		{
			cout << totalrevenue / totalcnt << endl;
		}
		else
		{
			cout << " (no sales) " << endl;
		}
		system("pause");
		return 0;
	}
	else
	{
		cout << "Data must refer to the same ISBN" << endl;
	}
	system("pause");
    return 0;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值