学习笔记

学习笔记

下面是我从notion上面迁移过来的笔记,也算是重点,是可以看的,是有用的. .

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main(void)
{
int i = 100;
for (int i = 0; i < 5; i++)
{
cout << "C++ knows the loop" << endl;
}
cout << i << endl;
return 0;
}

有意思的是:这并不会报错,反而会运行成功.运行结果如下图.

可见再循环体外面定义的i和循环体第一个表达式里面定义的i是不一样的,且就算是两个int,也不会出现error: redeclaration of ‘int i’的报错.

image

下面一个例子让我不太懂,不过现在只能不求甚解,先暂时囫囵吞枣,以后有机会再看了.

现在懂了,原理见本文后面5.1.10部分.

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;
int main(void)
{
int i = 3;
for (; i < 5; i++)
{
int i = 0;
cout << "C++ knows the loop" << endl;
}
cout << i << endl;
return 0;
}

运行截图:

image1

具体解释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
int main(void)
{
int i = 3;
for (; i < 5; i++)
{
int i = 0;//花括号里面的i都是新的i
cout << "C++ knows the loop" << endl;
cout << i << endl;
}//遇到这个花括号新的i就消亡了,此时i变成旧的i,然后才执行i++,然后判断i<5是否为真,接着进入下一次循环
cout << i << endl;
return 0;
}

运行结果:

image2

5.1.4 使用for循环访问字符串

这一小节讲的内容其实不重要,重要的是这里的程序里面的一个细节引起弹幕的争吵和我的思考,原来自己也不是很清楚.本来打算上网搜索的,但是这个问题难以找到对口的思考和网络博客,干脆直接自己实战,做一个实践者.

下面是视频教程内引起弹幕争议的程序.

image-20241028205639102

下面是我的思考.

可以明确的是

C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 “Hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello” 的字符数多一个

对于C-风格字符串而言,strlen()会返回什么?

image-20241028205837160

如果是这样的呢,加上ArSize = 20;

image-20241028210305090

image-20241028210330841

抱歉这第二张图片没有运行就贴上来了,下面是他运行后的结果

image-20241028210423992

这个时候他们的greeting[5]的ascii码都是0.也就是null 字符 ‘\0’ 终止的一维字符数组.

image-20241028210616533

image-20241028210638873

因此可以做一个总结:

对于C-风格字符串而言,字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。

无论你给字符数组的ArSize设定为多大,这两种初始化字符数组的方式都会在字符串加一个null 字符 ‘\0’(第一种是显示的,第二种是隐式的).

而且这两种初始化字符数组的方式使用strlen()都是返回除了null 字符 ‘\0’的可见字符的个数.

对于string类对象定义的字符串而言,可以动态的分配字符串的长度,因此不必讨论Arsize的的情况.

但是String类对象的底层原理是什么,恐怕现在还没学到因此不清楚,但是能明确的一点,现在就已经足够用的一点就是s.length()或者s.size()返回的也是除了null 字符 ‘\0’(当然我这里假定了有null字符结尾,你只要知道我说的是什么意思就行了)的可见字符的个数.

image-20241028211509506

image-20241028211853117

这就引出我的问题,string类对象真的最后有一个null字符’\0’吗?

google了一下,果然很多人和我一样的疑问,他们讲的非常详细,这里给出链接

https://segmentfault.com/q/1010000005141633

https://blog.51cto.com/u_14011026/6192540

总结:

image-20241028212155246

image-20241028212526576

精简总结:

  1. 在C++11及以后,string是以’\0’结尾的.

  2. 对于null字符’\0’的读取,两者的区别image-20241028213828067

  3. 事实上第二点不用纠结,很难用得上,知道就行.

5.1.8 递增/递减运算符和指针

规则:看书上

image-20241028220312462

每一行的解释也可以看书上.

image-20241028220619870

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
// const int ArSize = 16;
int main(void)
{
double arr[5] = {11.1, 21.1, 31.1, 41.1, 51.1};
double *pt = arr;
cout << pt << endl;
cout << "*++pt = " << *++pt << endl;
cout << "++*pt = " << ++*pt << endl;
cout << "(*pt)++ =" << (*pt)++ << endl;
cout << "*pt =" << *pt << endl;
cout << "*pt++ =" << *pt++ << endl;
cout << "*pt =" << *pt << endl;

return 0;
}

运行结果:

image3

5.1.9 组合赋值运算符

5.1.10 复合语句(语句块 )

image4

5.1.11 逗号运算符

说实话,不太重要,略过就行.

image5

这中间遗失的内容在hsuwindow笔记的原书pdf里面有

参考博文在这里

C风格字符串 C++string对象 字符串常量 字符串直接量

https://blog.csdn.net/sole_cc/article/details/46480711

image-20241029090443483

原书pdf里面一个小小的时代局限性

image-20241029105403602

image-20241029105348774

更加详细的内容可以见我这篇博客前面的 这一小节 下面是视频教程内引起弹幕争议的程序.来看.

5.2 while 循环

image-20241031092811111

5.3 do while 循环

do while循环和while循环有些经典写法和自己的理解,看我这篇博客

https://hsuwindow.vip/cshsuwindowDIY/C/grammar/C++PrimerPlusStudyNotesCh7/

image-20241031092831628

5.4 基于范围的for循环(C++11)

C++11的新特性

5.5 循环和文本输入

5.5.1 使用原始的cin进行输入

懒得在这里纠结是while还是do while,,反正大家都用while用的多,记住经典写法就好了.

原书还是细节的,注意到了我说的考量,反正就照着书来.

image-20241031101720735

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
cin >> ch;
while (ch != '#')
{
cout << ch << endl;
count++;
cin >> ch;
}
cout << endl
<< count << " character read\n";

return 0;
}

5.5.2 使用cin.get(char)进行补救

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
// cin >> ch;
cin.get(ch);
while (ch != '#')
{
cout << ch;
count++;
// cin >> ch;
cin.get(ch);
}
cout << endl
<< count << " character read\n";

return 0;
}

5.5.3 使用哪一个cin.get()

后面出现的和我这里重复的内容是我之前做的笔记,,其实也都能看.那我直接用后面的笔记了.

对应的复习题反而是给你做了一个好的总结

  1. cin >> ch → 忽略过遇到的所有 空白字符 cin.get(ch), ch = cin.get() → 会读取一切输入的字符,包括空白字符,也就是空格,换行符,制表符等等.他都会读取,并且存放在我们的ch里面

5.5.1 使用原始的cin进行输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
const int Cities = 5;
const int Years = 4;
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: " << endl;
cin >> ch;
while (ch != '#')
{
cout << ch;
count++;
cin >> ch;
}
cout << endl;
cout << count << endl;
return 0;
}

运行结果:

cin 跨过了空白字符

c501

5.5.2 使用cin.get(char)进行补救

c502

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
const int Cities = 5;
const int Years = 4;
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: " << endl;
cin.get(ch);
while (ch != '#')
{
cout << ch;
count++;
cin.get(ch);
}
cout << endl;
cout << count << endl;
return 0;
}

运行结果:

c503

c504

5.5.3 使用哪一个cin.get()

c505

image-20241031104512774

5.5.4 文件尾条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
const int Cities = 5;
const int Years = 4;
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: " << endl;
cin.get(ch);
while (cin.fail() == false)
{
cout << ch;
count++;
cin.get(ch);
}
cout << endl;
cout << count << endl;
return 0;
}

书上说了一大堆话,各种各样的系统,最后就一句话..大部分系统用Ctrl + Z作为文件结尾(还有别的具体细节,例如必须在行首还是可以在任何位置,是否必须按下回车键等等)各不相同

image-20241031105602361

c506

c507

[!IMPORTANT]

💡ubuntu下是Ctrl + d 将我们的输入发送一个EOF

Win10下的vscode里面Ctrl + z之后按下回车才行.

image-20241031105842302

  1. EOF结束输入

c508

  1. 常见的字符输入做法

c509

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: " << endl;
cin.get(ch);
while (cin)//改了依旧正常运行
{
cout << ch;
count++;
cin.get(ch);
}
cout << endl;
cout << count << endl;
return 0;
}

c510

最简化的情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters, enter # to quit: " << endl;
// cin.get(ch);
while (cin.get(ch))
{
cout << ch;
count++;
// cin.get(ch);
}
cout << endl;
cout << count << endl;
return 0;
}

c511

运行结果正确

c512

自己这次复习的时候又敲了一遍,运行结果也是正确的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
int main(void)
{
char ch;
int count = 0;
cout << "Enter characters; enter # to quit:\n";
// cin >> ch;
// cin.get(ch);
while (cin.get(ch))
{
cout << ch;
count++;
// cin >> ch;
// cin.get(ch);
}
cout << endl
<< count << " character read\n";

return 0;
}

运行结果

image-20241031120348282

经过这次复习,大概上面两种背下来就好了.

5.5.5 另一个cin.get()版本

跟平台有很大关系,略过,因为这一点用处不大.而且这个视频教程都不讲,说是和平台和有大的关系.

5.6 二维数组

c513

c514

c515

这一小节上面的都是之前的截图,下面是我这次复习敲的代码

看一遍就过了…这里比较简单.

5.7 总结

自己看完了,这个教程视频没讲这一小节

5.8复习题

入口循环:for循环,while循环
出口循环: do while循环

01234

0369

12

6

8

k = 8

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
int main(void)
{
int i;
for (i = 1; i < 64; i *= 2)
{
cout << i << ",";
}
cout << i;
return 0;
}

用花括号括起来

use { , , , , }

valid , x = 20 2) valid , (y = 1), 024 → 024

cin >> ch → 忽略过遇到的所有 空白字符 .

cin.get(ch), ch = cin.get() → 会读取一切输入的字符,包括空白字符,也就是空格,换行符,制表符等等.他都会读取,并且存放在我们的ch里面

后面的标题就不显示了,因为笔记都在原书的pdf里面

经过我笔记的原书的pdf的链接在这片博客下

https://hsuwindow.vip/cshsuwindowDIY/C/grammar/C++PrimerPlusNotesHsuwindowPdf/

5.9 编程练习

编程练习如下

5.9 编程练习

第八题的个人解答

用的是while的经典结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <cstring>
using namespace std;
const int ArSize = 20;
int main(void)
{
char arr[ArSize];
int i;
cout << "Enter words (to stop, type the word done):" << endl;
cin >> arr;
while (strcmp(arr, "done") != 0)
{
cout << i << ": " << arr << endl;
i++;
cin >> arr;
}
cout << "You entered a total of " << i << " words";
return 0;
}

结果

image-20241031162015682

有意思的是,利用cin>>的天然特性,将每个单词时间按照空格或者换行符来隔开计数.该视频教程还用了cin.get()来读取留在输入队列里面的空格或者换行符.我测试了一下.不用cin.get(),因为cin>>会忽略开始连续的所有空白字符.

image-20241031162442775

与第八题很像的第九题的个人解答

就是把字符数组换成了string对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <string>
using namespace std;
int main(void)
{
string s;
int i;
cout << "Enter words (to stop, type the word done):" << endl;
cin >> s;
while (s != "done")
{
cout << i << ": " << s << endl;
i++;
cin >> s;
}
cout << "You entered a total of " << i << " words";
return 0;
}

运行结果

image-20241031162859408

用很多空格和换行符测试也是对的

image-20241031162948059

也就是说cin>>后面接字符数组和string对象都是一眼情况,看上面我的总结.

第七题的个人解答.

出现的最严重的错误就是没有在cin>>n之后 cin.get(); // 清除输入整数之后留在输入队列里面的 换行符..

事实上,要看到cin>>整数就想到可能需要 cin.get(); // 清除输入整数之后留在输入队列里面的 换行符 的好习惯

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
// #include <array>
using namespace std;
struct car
{
string producer;
int produceAge;
};
int main(void)
{
int n;
cout << "How many cars do you wish to catalog? ";
cin >> n;
cin.get(); // 清除输入整数之后留在输入队列里面的 换行符
car *p = new car[n];
for (int i = 0; i < n; i++)
{
cout << "Car #" << i + 1 << ":" << endl;
cout << "Please enter the make: ";
getline(cin, (p + i)->producer); // 这里应该采用读入一行string对象,getline()自动抛弃一行结尾的换行符
cout << "Please enter the year made: ";
cin >> (p + i)->produceAge;
cin.get(); // 清除输入整数之后留在输入队列里面的 换行符
}

cout << "Here is your collection:" << endl;
for (int i = 0; i < n; i++)
{
cout << (p + i)->produceAge << " " << (p + i)->producer << endl;
}
}

这个教程讲的第三题弄错了.应该是我这样d

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
// #include <array>
using namespace std;
int main(void)
{
double number;
double sum = 0;
cin >> number;
while (number != 0)
{
sum += number;
cout << "current sum = :" << sum << endl;
cin >> number;
}
return 0;
}

运行结果

image-20241031123333619

第七题目小心之处在于,他讲要交替读取数值和字符串(参见第4章),我这里复习一下对应的内容.

image-20241031124051427

image-20241031124230710

总结一下就是:

cin>>忽略前面所有连续的空白字符(包括空格和回车),直到遇到非空白字符才算是读进去,最后遇到空白字符(可能是换行符,也可能是空格)作为结尾,但会把最后遇到的空白字符留在输入队列里面.

例子1

image-20241031124659854

很明显连续输入两个整数的时候,第二个cin就忽略了第一个cin留下来的换行符.此时第一个cin以换行符作为结尾

image-20241031124736001

很明显连续输入两个整数的时候,第二个cin就忽略了第一个cin留下来的空格.此时第一个cin以空格作为结尾

💡 有关C++PrimerPlus上的问题,欢迎您在底部评论区留言,一起交流~