学习笔记 学习笔记 下面是我从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’的报错.
下面一个例子让我不太懂,不过现在只能不求甚解,先暂时囫囵吞枣,以后有机会再看了.
现在懂了,原理见本文后面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 ; }
运行截图:
具体解释如下:
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 ; cout << "C++ knows the loop" << endl; cout << i << endl; } cout << i << endl; return 0 ; }
运行结果:
5.1.4 使用for循环访问字符串 这一小节讲的内容其实不重要,重要的是这里的程序里面的一个细节引起弹幕的争吵和我的思考,原来自己也不是很清楚.本来打算上网搜索的,但是这个问题难以找到对口的思考和网络博客,干脆直接自己实战,做一个实践者.
下面是视频教程内引起弹幕争议的程序.
下面是我的思考.
可以明确的是
C 风格的字符串起源于 C 语言,并在 C++ 中继续得到支持。字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。 下面的声明和初始化创建了一个 “Hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello” 的字符数多一个 。
对于C-风格字符串而言,strlen()会返回什么?
如果是这样的呢,加上ArSize = 20;
抱歉这第二张图片没有运行就贴上来了,下面是他运行后的结果
这个时候他们的greeting[5]的ascii码都是0.也就是null 字符 ‘\0’ 终止的一维字符数组.
因此可以做一个总结:
对于C-风格字符串而言,字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
无论你给字符数组的ArSize设定为多大,这两种初始化字符数组的方式都会在字符串加一个null 字符 ‘\0’(第一种是显示的,第二种是隐式的).
而且这两种初始化字符数组的方式使用strlen()都是返回除了null 字符 ‘\0’的可见字符的个数.
对于string类对象定义的字符串而言,可以动态的分配字符串的长度,因此不必讨论Arsize的的情况.
但是String类对象的底层原理是什么,恐怕现在还没学到因此不清楚,但是能明确的一点,现在就已经足够用的一点就是s.length()或者s.size()返回的也是除了null 字符 ‘\0’(当然我这里假定了有null字符结尾,你只要知道我说的是什么意思就行了)的可见字符的个数.
这就引出我的问题,string类对象真的最后有一个null字符’\0’吗?
google了一下,果然很多人和我一样的疑问,他们讲的非常详细,这里给出链接
https://segmentfault.com/q/1010000005141633
https://blog.51cto.com/u_14011026/6192540
总结:
精简总结:
在C++11及以后,string是以’\0’结尾的.
对于null字符’\0’的读取,两者的区别
事实上第二点不用纠结,很难用得上,知道就行.
5.1.8 递增/递减运算符和指针 规则:看书上
每一行的解释也可以看书上.
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> using namespace std;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 ; }
运行结果:
5.1.9 组合赋值运算符 5.1.10 复合语句(语句块 )
5.1.11 逗号运算符 说实话,不太重要,略过就行.
这中间遗失的内容在hsuwindow笔记的原书pdf里面有
参考博文在这里
C风格字符串 C++string对象 字符串常量 字符串直接量 https://blog.csdn.net/sole_cc/article/details/46480711
原书pdf里面一个小小的时代局限性
更加详细的内容可以见我这篇博客前面的 这一小节 下面是视频教程内引起弹幕争议的程序.来看.
5.2 while 循环
5.3 do while 循环 do while循环和while循环有些经典写法和自己的理解,看我这篇博客
https://hsuwindow.vip/cshsuwindowDIY/C/grammar/C++PrimerPlusStudyNotesCh7/
5.4 基于范围的for循环(C++11) C++11的新特性
5.5 循环和文本输入 5.5.1 使用原始的cin进行输入 懒得在这里纠结是while还是do while,,反正大家都用while用的多,记住经典写法就好了.
原书还是细节的,注意到了我说的考量,反正就照着书来.
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.get (ch); while (ch != '#' ) { cout << ch; count++; cin.get (ch); } cout << endl << count << " character read\n" ; return 0 ; }
5.5.3 使用哪一个cin.get() 后面出现的和我这里重复的内容是我之前做的笔记,,其实也都能看.那我直接用后面的笔记了.
对应的复习题反而是给你做了一个好的总结
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 跨过了空白字符
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 #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 ; }
运行结果:
5.5.3 使用哪一个cin.get()
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作为文件结尾 (还有别的具体细节,例如必须在行首还是可以在任何位置,是否必须按下回车键等等)各不相同
[!IMPORTANT]
💡ubuntu下是Ctrl + d 将我们的输入发送一个EOF
Win10下的vscode里面Ctrl + z之后按下回车才行.
EOF结束输入
常见的字符输入做法
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 ; }
最简化的情况
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; while (cin.get (ch)) { cout << ch; count++; } cout << endl; cout << count << endl; return 0 ; }
运行结果正确
自己这次复习的时候又敲了一遍,运行结果也是正确的
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" ; while (cin.get (ch)) { cout << ch; count++; } cout << endl << count << " character read\n" ; return 0 ; }
运行结果
经过这次复习,大概上面两种背下来就好了.
5.5.5 另一个cin.get()版本 跟平台有很大关系,略过,因为这一点用处不大.而且这个视频教程都不讲,说是和平台和有大的关系.
5.6 二维数组
这一小节上面的都是之前的截图,下面是我这次复习敲的代码
看一遍就过了…这里比较简单.
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 ; }
结果
有意思的是,利用cin>>的天然特性,将每个单词时间按照空格或者换行符来隔开计数.该视频教程还用了cin.get()来读取留在输入队列里面的空格或者换行符.我测试了一下.不用cin.get(),因为cin>>会忽略开始连续的所有空白字符.
与第八题很像的第九题的个人解答
就是把字符数组换成了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 ; }
运行结果
用很多空格和换行符测试也是对的
也就是说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> 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); 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> 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 ; }
运行结果
第七题目小心之处在于,他讲要交替读取数值和字符串(参见第4章),我这里复习一下对应的内容.
总结一下就是:
cin>>忽略前面所有连续的空白字符(包括空格和回车 ),直到遇到非空白字符才算是读进去,最后遇到空白字符(可能是换行符,也可能是空格 )作为结尾,但会把最后遇到的空白字符留在输入队列里面.
例子1
很明显连续输入两个整数的时候,第二个cin就忽略了第一个cin留下来的换行符.此时第一个cin以换行符作为结尾
很明显连续输入两个整数的时候,第二个cin就忽略了第一个cin留下来的空格.此时第一个cin以空格作为结尾
💡 有关C++PrimerPlus上的问题,欢迎您在底部评论区留言,一起交流~