C++Primer(1-3章)

第一章:开始

控制流

读取数量不定的输入数据

此程序实现对用户输入的一组数进行求和,我们预先不知道用户要输入多少个数。

书中代码如下:

int main()
{
	int sum = 0;
	int val = 0;
	while (cin >> val)
	{
		sum += val;
	}
	cout << sum<<endl;

	system("pause");
}

然而,这种方法需要我们手动指出输入结束,也就是按ctrl-z,或者输入别的数据类型。

改进程序:cin在遇到enter后,才去读取数据。
注意:键盘输入的数据都是先存放在输入缓冲区中的,当键入enter,cin才去缓冲区读取数据。

int main()
{
	int sum = 0;
	int val = 0;
	while (cin >> val)
	{
		sum += val;
		if (getchar() == '\n')
		{
			break;
		}
	}
	cout << sum<<endl;

	system("pause");
}

我们需要用getchar()截取当前的输入,并判断是否是换行,至此完成该程序。

第二章:变量和基本类型

对象:指一块能存储数据并具有某种类型的内存空间。

类型转换:

  • 当我们把一个非布尔类型的算术值赋给布尔类型时,初始值为0则结果为false,否则结果为true。
  • 当我们把一个布尔值赋给非布尔类型时,初始值为false则结果为0,否则结果为1。
  • 当我们把一个浮点数赋值给整数类型时,结果值仅保留浮点数中小数点之前的部分。
  • 当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如:8bit的unsigned char表示0-255区间的值,把-1赋给它后所得到的结果是-1对256取模的值255。
  • 当我们赋给有符号类型一个超出它表示范围的值时,结果是未定义的。

含无符号类型的表达式:
当一个算术表达式中既有无符号数又有int值时,那个int值会转换成无符号数。

转义序列:
在这里插入图片描述
在程序中,转义序列被当作一个字符。

注:nullptr是指针字面值。

变量

列表初始化:
用列表初始化的方法可以检查类型是否不匹配。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
默认初始化:
定义在任何函数体之外的变量被初始化为0,函数体内部的内置类型变量不被初始化。
在这里插入图片描述
在这里插入图片描述
声明和定义:
变量声明规定了变量的类型和名字,在这一点与定义相同。但是,定义还申请了存储空间,并且可能为变量赋一个初始值。
如果想声明一个变量但非定义它,需要加关键字extern,而且不要初始化变量。

extern int i;//声明i
int j;//声明并定义j
extern int k = 1;//定义k

如果在函数体内部初始化一个extern关键字标记的变量会出错。

作用域:
C++中大部分作用域都以花括号分隔。
同一个名字在不同的作用域中可能指向不同的实体。名字的有效区域始于名字的声明语句,以声明语句所在的作用域末端为结束。

二级指针:
通过*的个数可以区分指针的级别。
在这里插入图片描述
指向指针的引用:
在这里插入图片描述

const限定符:
为了防止程序修改变量的值,我们可以用关键字const对变量的类型加以限定。此外,因为const对象一旦创建后其值就不能再改变,所以const对象必须初始化。

指针常量,本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量,常量指针,本质上是一个指针,常量表示指针指向的内容,说明该指针指向一个“常量”。
常量指针(指针地址可以变,值不能变)。

int a = 0,b = 0;
const int *p = &a;
*p = 1; //错误,不可修改常量值
*p = &b; //正确,可以指向另一个常量

指针常量(指针地址不可变,值可变。注:指针常量在定义时要赋初值。)

int a = 0,b = 0;
int* const p = &a;
*p = 1; //正确,可以修改值
*p = &b; //错误,不可改变地址

指向常量的指针常量(指针地址不可变,值不可变)

int a = 0,b = 0;
const int * const p = &a;
*p = 1; //错误,不可以修改值
*p = &b; //错误,不可改变地址

auto类型说明符:
使用auto能让编译器替我们去分析表达式所属的类型。

decltype类型指示符:
它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。

// sum的类型就是函数f返回的类型
decltype(f()) sum = x;

decltype并不会实际计算表达式的值,编译器分析表达式并得到它的类型。
函数调用也算一种表达式,因此不必担心在使用decltype时真正的执行了函数,正如前例中的f()。

预处理器:
确保头文件多次包含仍能安全工作的常用技术是预处理器。当预处理器看到#include标记时就会用指定的头文件的内容代替#include。
C++还会用的一项预处理功能是头文件保护符。预处理变量有两种状态:已定义和未定义。#define指令把一个名字设定为预处理变量,另外两个指令则分别检查某个指定的预处理变量是否已经定义。
#ifdef 当且仅当变量已定义时为真,#ifndef当且仅当变量未定义时为真。一旦检查结果为真,则执行后续操作直到遇到#endif指令为止。

例如:

#ifndef SALES_DATA_H
#define SALES_DATA_H
#include <string.h>
struct Sales_data
{
	std::string bookNo;
	unsigned units_ssold = 0;
	double revenue = 0.0;
};
#endif

第一次包含Sales_data.h时,#ifndef为真,预处理器将顺序执行直到遇到#endif为止。此时,预处理变量SALES_DATA_H也变成已定义,后续如果再包含一次,则#ifndef检查结果为假,不再执行。

第三章:字符串、向量和数组

字符串string

初始化string对象的方式

在这里插入图片描述

string对象上的操作

1.读写:cin cout
注意:cin遇到空格就结束读入。
在这里插入图片描述
2.读取未知数量的string对象
在这里插入图片描述
注意:string遇见空格就停止读入,因此需要先输出再检测换行符,否则最后一个字符串无法输出。
3.使用getline读取一整行
我们希望在最终得到的字符串中保留输入时候的空白符,因此需要getline函数。该函数从给定的输入流中读取内容,直到遇到换行符为止。
在这里插入图片描述
4.处理string对象中的字符
我们需要单独处理string对象中的字符,例如检查一个string对象是否包含空白,或者把string对象的字母全部改为小写等。在这些问题中,我们需要知道字符的特性,在cctype中定义了一组标准库函数处理这些问题。
在这里插入图片描述

5.处理每个字符,使用基于范围的for语句。

for(declaration:expression)
		statement

declaration负责定义一个变量,该变量用于访问序列中的基础元素。expression是一个对象,表示一个序列。每次迭代,declaration的变量会被初始化为expression的下一个元素值。
举个例子:
在这里插入图片描述
此外,如果想要改变string对象中字符的值,必须把循环变量定义为引用类型。假设我们想要把字符串改为大写字母的形式,代码如下:
在这里插入图片描述
其中使用了标准库函数toupper,该函数接收一个字符,然后输出其对应的大写形式。

vector

定义和初始化vector对象

在这里插入图片描述
C++11中的列表初始化vector对象
例如:vector<string> articles = { "a","aaa","the" };

创建指定数量的元素
在这里插入图片描述

向vector对象中添加元素

注:vector容器中的下标运算符只可用于访问已存在的元素,不能用于添加元素。添加元素使用push_back

迭代器

所有迭代器都拥有begin和end两个成员。
begin指向第一个元素。
end指向尾元素的下一个元素。

迭代器的使用

例如:我们需要把string对象的第一个字符改成大写。
在这里插入图片描述
如果只需要读操作而无需写操作的话,C++11提供了两个新函数,cbegin和cend。

数组

理解复杂的数组声明

数组本身就是对象,因此允许定义数组的指针以及数组的引用。
在这里插入图片描述
例如:int *(&arr)[10] = arrs
按照由内向外的顺序,我们可以首先看出(&arr)说明arr是一个引用,再看右边知道,arr引用对象是一个大小为10的数组,观察左边发现,数组存放的类型是int *。因此,arr引用的是一个存放10个整型指针的数组。

指针和数组

在大多数表达式中,使用数组类型的对象其实是使用一个指向该数组首元素的指针。
例如:string *p = &s[0];string *p = s; 两条语句等价。
C++11引入了begin和end函数用来得到数组的首和尾后指针。
用法如下:
在这里插入图片描述
接下来就可以用和容器一样的遍历方法遍历数组了。
此外,我们可以用auto n = end(arr) = begin(arr)得到arr的长度。

使用数组初始化vector

只需要指明要拷贝区域的首元素地址和尾元素地址就行。
在这里插入图片描述

多维数组

例如:int arr[10][20][30] = {0};该数组大小为10,它的每个元素都是大小为20的数组,这些数组的元素是含有30个整数的数组。

使用范围for语句处理多维数组。
注意:用for来处理多维数组,除了最内层的循环,其他所有的循环控制变量都应该是引用类型。
在这里插入图片描述
第一个循环遍历arr的所有元素,这些元素是大小为3的数组,因此p就是含有3个整数的数组的引用。第二个循环遍历那些4元素数组中的某一个。
在这里插入图片描述
如果最外层循环不是引用类型,数组会被自动转成指针,内层循环就不合法了。
在这里插入图片描述
我们可以推断出p是指向含有4个整数的数组的指针,q的类型是指向整数的指针。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值