C++ Primer第三章 心得笔记
之前的一章我本末倒置了,我看了一个大佬的此书笔记整理得很详细 很得体。我也想按照他的这种方法 在我学习和敲代码的时候进行记录,但是我发现为了记笔记而记笔记 这种方法使我很累。违背了记录分享交流的初衷。所以也希望才开始的同学,能吸取我的教训 少走一点弯路。(我个人认为 不应该把所有的知识点罗列出来,应该在保持状态的同时 记录重要的点 问题,能解决的直接解决,不能解决的先记录 搁置一边,继续往下学习,不要浪费了进入的状态)
我觉得所谓心得笔记 应该是记录自己所遭遇的问题,和觉得重要的点,然后再把解决问题的思路和过程分享出来。而不是为了表里来记笔记 这样再未来的复习的时候,复习到的就没有那么好的复习效果。
在处理string 类对象时,如使用下标运算符等方法访问string类对象的字符时,应首先确认是否为空,其中一个方法为使用empty()函数确认string类对象是否为空,若为空则返回真,不为空则返回假,这里需要注意表达式取反。
string对象的几种初始化方式
string str = "Hello Word!"; //拷贝初始化string str1 = ("Hello Word!"); //暂且不知道属于哪种初始化string str2 = { "Hello Word!" }; //暂且不知道属于哪种初始化string str3("Hello Word!"); //直接初始化string str4{ "Hello Word!" }; //列表初始化string str5{'H','e','l','l','o',' ','W','o','r','d','!'}; //列表初始化string str6(10,'H') //直接初始化/** 输出结果* Hello Word!* Hello Word!* Hello Word!* Hello Word!* Hello Word!* Hello Word!* HHHHHHHHHH*/
for循环原来还可以分成多行来写(但是每一行的结尾必须以分号结尾),刚才看书的时候楞是没反应过来。
#include <iostream>
#include <cctype>int main() {using std::string;using std::cout;using std::endl;using std::cin;string a("Hello Word!");for (decltype(a.size()) index = 0; //表达式1index != a.size() && !isspace(a[index]); //表达式2++index) //表达式3a[index] = toupper(a[index]);cout << a << endl;//输出结果 HELLO Word!return 0;
}
直接初始化 和 拷贝初始化
“=” 拷贝初始化
“()” 直接初始化
vector是模版(理解为 容器),而非类型。由vector生成的类型必须包含vector类型中元素的类型。如vector。
为什么会将string对象的下标类型设置为 string::size_type,因为我们得确保下表的范围不小于0。所以这里统一设置为这个string::size_type这个无符号类型,就可以确保下标不会小于0。一旦超出这个范围就会发生无法预知的后果。
vector容器的初始化
vector<int> it(10, 5); //容器里有10个整形元素 值都为5vector<int> it1(10); //容器里有10个整形元素 值都为0vector<int> it2{ 10 }; //一个元素 值为10vector<int> int3{ 10,5 }; //两个元素 分别为10和5vector<string> str(10); //十个元素 默认初始化vector<string> str1{ 10 }; //十个元素 默认初始化vector<string> svec(10, "null");vector<string> str2{ 3,"hi"}; //三个元素 值为hivector<string> str3{"Hellow","Word","!"};//三个元素 值分别为Hello Word !
关于迭代器。有两种类型
一种是iterator(可读可写),一种是const_iterator(只读)。
begin和end的返回的具体类型由对象是否是常量而决定。
vector<string> str{"Hello Word!"};
vector<string>::iterator str_iterator = str.begin();
//返回类型为iterator
//等价 auto str_iterator = str.begin(); const vector<string> str1{"Hello Word!"};
vector<string>::const_iterator str1_iterator = str1.begin();
//返回类型为const_iterator
//等价 auto str_iterator = str1.begin();
而另外两种函数cbegin、cend,无论对象是否为常量,它的返回类型都为const_iterator
无法通过类型为const_iterator的迭代器修改容器迭代器指向元素的值
vector<string> str{"Hello Word!"};
vector<string>::const_iterator = str.cbegin();
谨记 但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。
谨记 范围for语句体内不应改变其所遍历序列的大小
从cin读入一组词并把他们存入一个vector对象,然后把所有词都改为大写形式。输出改变后的结果,每个词占一行。
#include <iostream>
#include <cctype>
#include <typeinfo>
#include <vector>int main() {using std::string;using std::cout;using std::endl;using std::cin;using std::vector;vector<string> v1;string temp;//通过循环从标准输入中读取单词while (cin >> temp) v1.push_back(temp);//第一个for循环遍历容器的string元素for (auto v1_iterator = v1.begin();v1_iterator != v1.end(); ++v1_iterator) {//第二个for循环遍历string元素的每个字符 同时把单词变为大写for (decltype((*v1_iterator).size())index = 0;index != (*v1_iterator).size(); ++index) {(*v1_iterator)[index] = toupper((*v1_iterator)[index]);}}for (auto c : v1) {cout << c << endl;}return 0;
}
关键概念:泛型编程
为什么使用 != 而不是使用<或者<=,因为所有标准库容器的迭代器都定义了==和!=,但是大多都没有定义<运算符。所以我们只要养成使用迭代器和 != 的习惯,就不用太在意到底是使用哪种容器类型。
字符串字面值的类型实际上是由常量字符构成的数组,编译器在每个字符串的结尾处添加一个空字符‘\0’。因此,字符串值面值的实际长度比它的内容多1。
字符数组的特性
我们可以用字符串字面值,对此类数组初始化,当使用这种方式时,一定要注意字符串字面值的结尾处还有一个空字符。这个空字符也会像其他字符串的其他字符一样被拷贝到字符数组中去。
char str[]=“Hello Word!”;
char str1[11]=“Hello Word!”;
//初始值的总数量不应该超出指定的大小
不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。
想要理解数组声明的含义,最好的办法是从数组的名字开始按照由内向外的顺序阅读。
在很多用到数组名字的地方,编译器都会自动地将其替换为一个指向数组首元素的指针。
在大多数表达式中,使用数组类型的对象其实上是使用一个指向该数组首元素的指针。
int a[10]={}; //{}是列表初始化 10个0
int *p=&a[0];
//和下面这条代码 等价
int *p1=a;
指针也是迭代器
通过数组名字或者数组中首元素的地址都能获得只想首元素的指针。
而尾后指针(尾元素的下一位置)就要用到数组的另一个特殊性质。尾后指针不指向具体的元素。因此,不能对尾后指针执行解引用或则递增的操作。(递减可以)
比较两个数组
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };int b[10] = { 1,2,3,4,5,6,7,8,9,10 };//int b[10] = { 1,3,5,7,9,11,13,15,17,19};auto a_num = size(a);auto b_sum = size(b);if (a_num == b_sum){//数组的元素数量相等 循环内部对元素进行挨个比较 for (size_t index = 0; index != a_num; ++index) {if (a[index] != b[index]) {cout << "值不相等" << endl;exit(0);}}cout << "相等" << endl;}else{cout << "数量不相等" << endl;}return 0;
比较vector对象是否相等
vector<int> a{10,8,3};vector<int> b{ 10,8,3 };size_t index = 0;if(a.size()==b.size()){while (index != a.size()) {if (a[index] != b[index]) {cout << "值不相等" << endl;exit(0);}++index;}cout << "相等" << endl;}else {cout << "数量不相等" << endl;}return 0;
分析以下代码段
const char ca[] = { 'h','e','l','l','o' };//const char ca[] = { 'h','e','l','l','o','\0' }; 正确格式const char* cp = ca;while (*cp) {cout << *cp << endl;++cp;}return 0;
//输出:hello烫烫烫恬滋掣??4
ca应该是想表达c风格字符串 但是尾元素必须是空字符 ‘\0’。但是由于数组尾元素未设置为空字符,所以循环未按照逻辑(在循环尾元素处结束)。地址一直递增,知道解引用时遇到内存中的空字符。
多维数组
通常所说的多维数组其实是数组的数组,按照由内而外的阅读顺序读此类定义有助于更好地理解真实含义。
例如
int a[3][4]={{1,3,8,1},{2,3,4,6},{1,2,8,4}
};
我们定义的数组名字为a,a是一个包含三个元素的数组,接着往右边发现这三个元素也有自己的维度,a的元素本身就是一个包含四个元素的数组。
对于二维数组,我们通常把第一个维度叫做行,第二个维度叫做列。
constexpr 和 const的区别
在书里经常能看到,一会使用constexpr,一会使用const。具体有什么差异呢?我百度了一下,做了一点肤浅的总结。
constxepr是编译期常量(具体什么是编译期常量 我也没理解明白)。
const就没有区分编译期常量和运行期常量。
在敲代码时,语义在常量就用constexpr。语义在只读就用const。
而检测constexpr函数是否产生编译时期值的方法很简单,就是利用std::array需要编译期常值才能编译通过的小技巧。这样的话,即可检测你所写的函数是否真的产生编译期常值了。
int main()
{using namespace std;constexpr int a_row = 3, a_lie = 4;int a[a_row][a_lie];size_t index = 0;for(auto &row:a)for (auto& lie : row){lie = index;++index;}for (auto& row : a)for (auto& lie : row){cout << lie << endl;}return 0;
}
要使用范围for语句处理多维数组,除了最内层的循环外,其他所有的循环的控制变量都应该是引用类型。
指针和多维数组
当程序使用多维数组的名字时,也会自动将其转换为指向数组首元素的指针。(多维数组是数组的数组),所以这个指针指向的元素也是一个数组。
int main()
{using namespace std;int a[4][3] = {{13,4,2},{1,57,1},{15,48,15},{48,79,16}};//x是一个指针 指向数组的第一行的指针for (auto x = begin(a); x != end(a); x++) {//*x是一个数组,而用这个数组赋值给y 实际上是把这个数组的第一个元素的地址赋给了y//end(*x)实际上返回的是数组a第一个维度的尾后地址(尾后是指末尾元素,尾后地址则是指末尾元素的后面的地址)//尾后地址不能解除引用,也不能用作算数运算 因为没有实际意义,它不指向任何一个元素,只做参考for (auto y = begin(*x); y != end(*x); y++) {cout << *y << " ";}//理解a x *x y *y的含义cout << endl;}
C++ Primer第三章 心得笔记相关推荐
- C++ Primer 第三版 读书笔记
1.如果一个变量是在全局定义的,系统会保证给它提供初始化值0.如果变量是局部定义的,或是通过new表达式动态分配的,则系统不会向它提供初始值0 2.一般定义指针最好写成:" string * ...
- 西瓜书第三章阅读笔记
西瓜书第三章阅读笔记 第三章 线性模型 1.机器学习三要素 2.基本形式 3.线性回归 3.1 模型 3.2 策略 3.3 求解算法 4.对数几率回归 4.1 模型 4.2 策略 4.3 求解算法 5 ...
- 工程伦理第三章学习笔记2020最新
工程伦理第三章学习笔记2020最新 因为之前自己在网上找答案总是觉得费劲,一道一道的找,很慢,突然找到了前两章的答案,感觉有一种前人种树后人乘凉的感觉,于是自己在艰难找完第三章习题并全对的情况下,将题 ...
- 多维随机变量及其分布——《概率论及其数理统计》第三章学习笔记
多维随机变量及其分布--<概率论及其数理统计>第三章学习笔记 文章目录 多维随机变量及其分布--<概率论及其数理统计>第三章学习笔记 前言 MindMap 二维随机变量 定义与 ...
- 周志华西瓜书第三章学习笔记
第三章学习笔记 文章目录 第三章学习笔记 1.知识脉络 2.我的笔记 参考 1.知识脉络 2.我的笔记 这一章公式推导实在太多了,需要补充的推导过程也有很多,就不写电子档了.扩展公式推导和LDA部分补 ...
- 《数学之美》——第三章 个人笔记
第三章 统计语言模型 1 用数学的方法描述语言规律 普遍描述:假定S表示某一个有意义的句子,由一连串特定顺序排列的词w1,w2,...,wn组成,(这里应该是特征列表)这里n是句子的长度.现在, ...
- 孙鑫VC++深入详解第三章学习笔记
第三章 3.1创建MFC AppWizard 如何利用vs2019创建MFC应用见参考文献[1] 需要注意的地方有 [1] 创建MFC单文档应用程序 [2]开启类视图窗口 3.2基于MFC的程序框架剖 ...
- windows 程序设计 第三章读书笔记(上)
娘的,今天晚上在阳台做饭把水管一脚踢爆了,水流到下面的住户的阳台,让个老娘们把我骂了一顿,本着做错事的原则,我装的很绅士还说了个对不起,擦,真是条纯汉子,能屈能伸. 大爷,别看我年轮小,我都给总结了, ...
- 第三章 卡尔曼滤波 笔记
第三章 卡尔曼滤波 文章目录 第三章 卡尔曼滤波 3.1 引言 3.2 卡尔曼滤波器的信号模型 模型分析 3.3 卡尔曼滤波算法 算法总结 3.1 引言 卡尔曼滤(Kalman)滤波和维纳(Wiene ...
最新文章
- PHP使用BC Math 函数处理浮点运算问题
- SAP系统配置常用命令大全
- 【Python】Python一行代码能做什么,30个实用案例代码详解
- ubuntu下载软件安装包
- wpf 可以取消的单选checkbox
- warning C4091: “typedef ”: 没有声明变量时忽略“_matcher”的左侧
- 带电插拔损坏设备原理_Win10拔U盘不用再点“安全弹出”了,XP和Win7老用户都眼馋了...
- 登录用户名和密码相同问题
- Oracle私网mtu滚动修改实施方案
- 实战案例丨使用云连接CC和数据复制服务DRS实现跨区域RDS迁移和数据同步
- typora绑定github博客_零基础搭建个人博客
- Mysql学习总结(7)——MySql索引原理与使用大全
- C/C++学习路线(总体把握C/C++)
- Spring内异常 application exception overridden by commit exception
- linux应用开发 — 控制LED设备
- 001java面试笔记——【java基础篇】从团800失败面试总结的java面试题
- YY创始人携手极客公园调坎QQ企鹅
- 数据包从物理网卡流经 Open vSwitch 进入 OpenStack 云主机的流程
- WAVEFORMATEX 格式说明
- 标题 Python生成二维码和解码