主题:这是我学习C++ Primer的一些心得(未完),有点菜,但还是想和大家分享一下
引言:
我之所以打算利用寒假的这几天好好学习一下C++ Primer 这本书,是因为很多人都说这本书是C++系列的经典之作,所以我想利用这本书巩固一下自己C++的知识!
在学习的过程中,我习惯的对书中设计的源代码进行修改,以此来加深对知识的理解!但在此过程中,难免会遇到一些小问题,其实并不是很大的程序错误,可以说是一些小技巧吧,在此我会一一记录,希望当我学完这本书时,这个Word文档可以成为一篇不错的学习笔记,为其他人初识C++提供些帮助!
*******************************************************************************
运行环境为Microsoft Visual Studio 2008(以下简写为:VC2008)
*******************************************************************************
笔记:
1. (1)日期:2011.1.9
(2)问题:在运行一段只包括“输出”的代码时,窗口停不住,以前未遇到这种情况
(3)原因:通过在网上查询,了解到这个和编译器有关。对于使用Visual C++ 6.0的同学来说不会存在这样的问题,但像我这种使用VC2008 的人来说,就会遇到。
(4)网上查询的解决方法是(我选择较好的一种):
1.在您想要暂停的地方加上 system("pause"); 就可以使 C/C++ 程序暂停。不过,这个办法奏效的前提是系统中必须存在 pause 这个命令。此外,还需要包含标准头文件 stdlib.h(对于 C)或者 cstdlib(对于 C++)。
2.在您想要暂停的地方加上 getchar();(对于 C 和 C++)或者 cin.get();(仅适用于 C++)就可以使程序暂停,然后按回车程序就会继续执行。不过,您会发现,这种办法却不一定奏效。如果您够细心,会发现只有当 getchar();/cin.get(); 前面有接收输入的语句的时候,该办法才会失效。如果之前没有接收任何输入,该办法是 100% 奏效的!这是因为,如果前面接收了输入,输入流中可能会有残留数据,
getchar();/cin.get(); 就会直接读取输入流中的残留数据,而不会等待我们按回车。解决该问题的办法是,先清空输入流,再用 getchar();/cin.get();。清空输入流的办法如下:
1). /* 适用于 C 和 C++。需要包含 stdio.h(对于 C)或者 cstdio(对于 C++)*/
while ( (c = getchar()) != '\n' && c != EOF ) ; /* 对于 C 和 C++ */
2). cin.clear(); // 仅适用于 C++,而且还需要包含标准头文件 limits
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
(5)自己实践:
通过实践,最简单的方法是:首先在头文件部分加入 #include <cstdlib>,然后在你打算停住的地方加上代码:system(“pause”);(注意分号),完成!
(6)实践代码:
#include "stdafx.h"
#include <iostream>
#include <string>
#include<cstdlib> //加入的头文件
using namespace std;
int main()
{
string line("dfdsfsfs");
int n=line.size();
cout<<n<<endl;
system("pause"); //加入的代码
cout<<n+1<<endl; //本行是为了验证上面的点是否停住了!
return 0;
}
2.(1)日期:2011.1.9
(2)问题:对string库中size()和empty()两个函数的理解
(3)实践代码:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
string line;
while(getline(cin,line))
{ //注意用括号将while()循环体括起来,不然while()将进行输出字符串的死循环
cout<<line<<endl;
int m=line.empty();
int n=line.size();
cout<<m<<endl;
cout<<line.size()<<endl;
system("pause");
cout<<line.size()+1<<endl;
}
return 0;
}
3.(1)日期:2011.1.11
(2)问题:当输入数据是空格(’ ’)、制表符(‘\t’)、换行符(’\n’)时,如何处理输入,还用cin>>.....吗?
(3)原因:不能使用提取操作符(>>),因为对>>而言,空格、制表符和换行符均为数据项分隔符,会被忽略掉,而cin对象的get成员函数则不会这样。
(4)实践代码:
将需要输入流的地方写为:cin.get(ch); (ch为已经定义的字符型数据:char ch) 即可!
4.(1)日期:2011.1.13
(2)问题:在C++中,如何理解一个String类型字符串和一个C风格字符串的区别
(3)原理分析:
(以下分析中,“前者”是指String字符串,“后者”是指C风格字符串)
1. 首先是两者头文件上的区别:
前者是:#include <iostream>
#include <string>
后者是:#include <iostream>
#include <cstring>
2. 其次是两者所包含库函数的区别
前者是:s.empty() //如果s为空串,则返回true,否则返回false
s.size() //返回s中字符的个数
s[n] //返回s中位置为n的字符,位置从0开始计数
s1+s2 //把s1和s2连接成一个新字符串,返回新生成的字符串
s1=s2 //把s1内容替换为s2的副本
v1==v2 //比较两者的内容,相等返回true,否则返回false
!=,<,<=,>,>= //保持这些操作惯有的定义(此点很重要)
后者是:Strlen(s)
Strcmp(s1,s2)
Stricmp(s1,s2)
Strcat(s1,s2)
Strcpy(s1,s2)
Strncat(s1,s2,n)
Strncpy(s1,s2,n)
3. 我个人认为两者的区别主要在于:前者直接定义String类的对象,直接对其进行操作,后者定义的是字符数组,实际上是对数组的操作!
(4)实践代码:
5.(1).日期:2011.1.18
(2).问题(技巧性的):当我们在程序开发阶段,我们有时需要对所包含的代码进行调试,当我们交付软件时,这些调试代码就不需要了,要进行屏蔽。
(3).原理分析:
1.我们可以采用“预处理器”进行调试,将用于调试的语句用 #ifndef NDEBUG和 #endif 包含起来,当这些调试代码不再需要时,我们通过定义NDEBUG的方法,即可完成对代码的屏蔽。
2.(书中P61)#define指示接受一个名字并定义该名字为预处理变量。#ifndef
指示检测指定的预处理变量是否未定义。如果预处理变量未定义,那么跟在其后的
所有指示都被处理,直到出现#endif。
(4).实践代码:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cstdlib> //用于暂停
#include <cctype>
#define NDEBUG //如果未对NDEBUG进行定义,则下面的调试代码将执行
using namespace std;
int main()
{
string currword,preword;
cout<<"Enter some words:"<<endl;
while(cin>>currword){
#ifndef NDEBUG
cout<<currword<<' '; //调试:将所输入的字符串输出一遍
#endif
if(!isupper(currword[0]))
continue;
if(currword==preword)
break;
else
preword=currword;
}
if(currword==preword&&!currword.empty())
cout<<"The repeated word:"<<currword<<endl;
else
cout<<"There is no repeated word that has initial capital."<<endl;
system("pause");
return 0;
}
6.(1).日期:2011.1.20
(2).问题:(结合下面的代码进行理解,即习题7.13)在int sum3()函数中,我起初不明白为什么要另外定义一个指针p,对比int sum1(),我不太理解,而且我尝试直接用指针begin,运行结果我发现有错误!
(3).原理分析:通过实践,我发现其实这是个很简单的问题,直接用begin的话,while 循环体中要执行一步:begin++ 的操作,而while 的判定条件是:begin!=begin+size; 会永远为真,程序将陷入死循环。为了验证这一点,我在while循环体中加入了一个输出语句,验证了我的想法。
(4).实践代码:(sum3的正确函数体见书的配套答案)
#include "stdafx.h"
#include <iostream>
//#include <cstdlib> //用于暂停
//#define NDEBUG
using namespace std;
int sum1(const int *begin,const int *end)
{
int sum=0;
while(begin!=end){
sum=sum+*begin;
begin++;
}
return sum;
}
int sum2(const int ia[],size_t size)
{
int sum=0;
for(size_t ix=0;ix!=size;++ix)
{
sum+=ia[ix];
}
return sum;
}
int sum3(int *begin,size_t size)
{
int sum=0;
//int *p=begin;
while(begin!=begin+size)
{
sum=sum+*begin;
#ifndef NDEBUG
cout<<"wsqw"<<endl;
#endif
begin++;
}
return sum;
}
int main()
{
int ia[]={1,2,3,4};
cout<<"Summation from sum1():"<< sum1(ia,ia+4)<<endl;
cout<<"Summation from sum1():"<< sum2(ia,4)<<endl;
cout<<"Summation from sum1():"<< sum3(ia,4)<<endl;
system("pause");
return 0;
}
7.(1).日期:2011.2.21
(2).问题:今天在解决习题11.9时遇到了一些关于文件的问题,由于今天状态不错,于是就尝试解决了一下~~
(3).解决方案:首先我根据书中题干编译了代码,生成了exe文件;然后我在桌面定义了一个文本文件,并在文件中输入了为测试而准备的一段英文;之后利用刚才的exe文件将其打开,得到的运行结果与预想一致,程序成功!!!
(4).实践代码:
// 123.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cstdlib> //用于暂停
#include <vector>
#include<fstream>
#include<algorithm>
using namespace std;
//用于将单词排序的比较函数
bool isShorter(const string &s1,const string &s2)
{
return s1.size()<s2.size();
}
//确定给定单词的长度是否不小于
bool GT6(const string &s)
{
return s.size()>=6;
}
//如果ctr不为,返回word的复数版本
string make_plural(size_t ctr,const string &word,const string &ending)
{
return (ctr==1) ? word:word+ending;
}
int main(int argc,char **argv)
{
//检查命令行参数
if(argc<2)
{
cerr<<"No input file!"<<endl;
return EXIT_FAILURE;
}
//打开文件
ifstream inFile;
inFile.open(argv[1]);
if(!inFile)
{
cerr<<"Can not open input file!"<<endl;
return EXIT_FAILURE;
}
vector<string> words;
string word;
//读入要分析的输入序列,并存放在vector容器中
while(inFile>>word)
words.push_back(word);
//对输入排序以便去除重复的单词
sort(words.begin(),words.end());
//使用算法unique对元素重新排序并返回一个迭代器,
//表示无重复的单词范围的结束,
//erase操作使用该迭代器删除输入序列中重复的单词
words.erase(unique(words.begin(),words.end()),words.end());
//将单词按长度排序,等长的单词按字典顺序排列
stable_sort(words.begin(),words.end(),isShorter);
//计算并输出长度不小于的单词的数目
vector<string>::size_type wc=count_if(words.begin(),words.end(),GT6);
cout<<wc<<" "<<make_plural(wc,"word","s")<<" 6 characters or longer"<<endl;
//输出输入序列中不重复的单词
cout<<"unique words:"<<endl;
for(vector<string>::iterator iter=words.begin();iter!=words.end();++iter)
cout<<*iter<<" ";
cout<<endl;
system("pause"); //程序在此处停住,以便检查运行结果!
return 0;
}
(5).测试文件内容:
the quick red fox jumps over the slow red turtle
我之所以打算利用寒假的这几天好好学习一下C++ Primer 这本书,是因为很多人都说这本书是C++系列的经典之作,所以我想利用这本书巩固一下自己C++的知识!
在学习的过程中,我习惯的对书中设计的源代码进行修改,以此来加深对知识的理解!但在此过程中,难免会遇到一些小问题,其实并不是很大的程序错误,可以说是一些小技巧吧,在此我会一一记录,希望当我学完这本书时,这个Word文档可以成为一篇不错的学习笔记,为其他人初识C++提供些帮助!
*******************************************************************************
运行环境为Microsoft Visual Studio 2008(以下简写为:VC2008)
*******************************************************************************
笔记:
1. (1)日期:2011.1.9
(2)问题:在运行一段只包括“输出”的代码时,窗口停不住,以前未遇到这种情况
(3)原因:通过在网上查询,了解到这个和编译器有关。对于使用Visual C++ 6.0的同学来说不会存在这样的问题,但像我这种使用VC2008 的人来说,就会遇到。
(4)网上查询的解决方法是(我选择较好的一种):
1.在您想要暂停的地方加上 system("pause"); 就可以使 C/C++ 程序暂停。不过,这个办法奏效的前提是系统中必须存在 pause 这个命令。此外,还需要包含标准头文件 stdlib.h(对于 C)或者 cstdlib(对于 C++)。
2.在您想要暂停的地方加上 getchar();(对于 C 和 C++)或者 cin.get();(仅适用于 C++)就可以使程序暂停,然后按回车程序就会继续执行。不过,您会发现,这种办法却不一定奏效。如果您够细心,会发现只有当 getchar();/cin.get(); 前面有接收输入的语句的时候,该办法才会失效。如果之前没有接收任何输入,该办法是 100% 奏效的!这是因为,如果前面接收了输入,输入流中可能会有残留数据,
getchar();/cin.get(); 就会直接读取输入流中的残留数据,而不会等待我们按回车。解决该问题的办法是,先清空输入流,再用 getchar();/cin.get();。清空输入流的办法如下:
1). /* 适用于 C 和 C++。需要包含 stdio.h(对于 C)或者 cstdio(对于 C++)*/
while ( (c = getchar()) != '\n' && c != EOF ) ; /* 对于 C 和 C++ */
2). cin.clear(); // 仅适用于 C++,而且还需要包含标准头文件 limits
cin.ignore( numeric_limits<streamsize>::max(), '\n' );
(5)自己实践:
通过实践,最简单的方法是:首先在头文件部分加入 #include <cstdlib>,然后在你打算停住的地方加上代码:system(“pause”);(注意分号),完成!
(6)实践代码:
#include "stdafx.h"
#include <iostream>
#include <string>
#include<cstdlib> //加入的头文件
using namespace std;
int main()
{
string line("dfdsfsfs");
int n=line.size();
cout<<n<<endl;
system("pause"); //加入的代码
cout<<n+1<<endl; //本行是为了验证上面的点是否停住了!
return 0;
}
2.(1)日期:2011.1.9
(2)问题:对string库中size()和empty()两个函数的理解
(3)实践代码:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
string line;
while(getline(cin,line))
{ //注意用括号将while()循环体括起来,不然while()将进行输出字符串的死循环
cout<<line<<endl;
int m=line.empty();
int n=line.size();
cout<<m<<endl;
cout<<line.size()<<endl;
system("pause");
cout<<line.size()+1<<endl;
}
return 0;
}
3.(1)日期:2011.1.11
(2)问题:当输入数据是空格(’ ’)、制表符(‘\t’)、换行符(’\n’)时,如何处理输入,还用cin>>.....吗?
(3)原因:不能使用提取操作符(>>),因为对>>而言,空格、制表符和换行符均为数据项分隔符,会被忽略掉,而cin对象的get成员函数则不会这样。
(4)实践代码:
将需要输入流的地方写为:cin.get(ch); (ch为已经定义的字符型数据:char ch) 即可!
4.(1)日期:2011.1.13
(2)问题:在C++中,如何理解一个String类型字符串和一个C风格字符串的区别
(3)原理分析:
(以下分析中,“前者”是指String字符串,“后者”是指C风格字符串)
1. 首先是两者头文件上的区别:
前者是:#include <iostream>
#include <string>
后者是:#include <iostream>
#include <cstring>
2. 其次是两者所包含库函数的区别
前者是:s.empty() //如果s为空串,则返回true,否则返回false
s.size() //返回s中字符的个数
s[n] //返回s中位置为n的字符,位置从0开始计数
s1+s2 //把s1和s2连接成一个新字符串,返回新生成的字符串
s1=s2 //把s1内容替换为s2的副本
v1==v2 //比较两者的内容,相等返回true,否则返回false
!=,<,<=,>,>= //保持这些操作惯有的定义(此点很重要)
后者是:Strlen(s)
Strcmp(s1,s2)
Stricmp(s1,s2)
Strcat(s1,s2)
Strcpy(s1,s2)
Strncat(s1,s2,n)
Strncpy(s1,s2,n)
3. 我个人认为两者的区别主要在于:前者直接定义String类的对象,直接对其进行操作,后者定义的是字符数组,实际上是对数组的操作!
(4)实践代码:
5.(1).日期:2011.1.18
(2).问题(技巧性的):当我们在程序开发阶段,我们有时需要对所包含的代码进行调试,当我们交付软件时,这些调试代码就不需要了,要进行屏蔽。
(3).原理分析:
1.我们可以采用“预处理器”进行调试,将用于调试的语句用 #ifndef NDEBUG和 #endif 包含起来,当这些调试代码不再需要时,我们通过定义NDEBUG的方法,即可完成对代码的屏蔽。
2.(书中P61)#define指示接受一个名字并定义该名字为预处理变量。#ifndef
指示检测指定的预处理变量是否未定义。如果预处理变量未定义,那么跟在其后的
所有指示都被处理,直到出现#endif。
(4).实践代码:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cstdlib> //用于暂停
#include <cctype>
#define NDEBUG //如果未对NDEBUG进行定义,则下面的调试代码将执行
using namespace std;
int main()
{
string currword,preword;
cout<<"Enter some words:"<<endl;
while(cin>>currword){
#ifndef NDEBUG
cout<<currword<<' '; //调试:将所输入的字符串输出一遍
#endif
if(!isupper(currword[0]))
continue;
if(currword==preword)
break;
else
preword=currword;
}
if(currword==preword&&!currword.empty())
cout<<"The repeated word:"<<currword<<endl;
else
cout<<"There is no repeated word that has initial capital."<<endl;
system("pause");
return 0;
}
6.(1).日期:2011.1.20
(2).问题:(结合下面的代码进行理解,即习题7.13)在int sum3()函数中,我起初不明白为什么要另外定义一个指针p,对比int sum1(),我不太理解,而且我尝试直接用指针begin,运行结果我发现有错误!
(3).原理分析:通过实践,我发现其实这是个很简单的问题,直接用begin的话,while 循环体中要执行一步:begin++ 的操作,而while 的判定条件是:begin!=begin+size; 会永远为真,程序将陷入死循环。为了验证这一点,我在while循环体中加入了一个输出语句,验证了我的想法。
(4).实践代码:(sum3的正确函数体见书的配套答案)
#include "stdafx.h"
#include <iostream>
//#include <cstdlib> //用于暂停
//#define NDEBUG
using namespace std;
int sum1(const int *begin,const int *end)
{
int sum=0;
while(begin!=end){
sum=sum+*begin;
begin++;
}
return sum;
}
int sum2(const int ia[],size_t size)
{
int sum=0;
for(size_t ix=0;ix!=size;++ix)
{
sum+=ia[ix];
}
return sum;
}
int sum3(int *begin,size_t size)
{
int sum=0;
//int *p=begin;
while(begin!=begin+size)
{
sum=sum+*begin;
#ifndef NDEBUG
cout<<"wsqw"<<endl;
#endif
begin++;
}
return sum;
}
int main()
{
int ia[]={1,2,3,4};
cout<<"Summation from sum1():"<< sum1(ia,ia+4)<<endl;
cout<<"Summation from sum1():"<< sum2(ia,4)<<endl;
cout<<"Summation from sum1():"<< sum3(ia,4)<<endl;
system("pause");
return 0;
}
7.(1).日期:2011.2.21
(2).问题:今天在解决习题11.9时遇到了一些关于文件的问题,由于今天状态不错,于是就尝试解决了一下~~
(3).解决方案:首先我根据书中题干编译了代码,生成了exe文件;然后我在桌面定义了一个文本文件,并在文件中输入了为测试而准备的一段英文;之后利用刚才的exe文件将其打开,得到的运行结果与预想一致,程序成功!!!
(4).实践代码:
// 123.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include <iostream>
#include <string>
#include <cstdlib> //用于暂停
#include <vector>
#include<fstream>
#include<algorithm>
using namespace std;
//用于将单词排序的比较函数
bool isShorter(const string &s1,const string &s2)
{
return s1.size()<s2.size();
}
//确定给定单词的长度是否不小于
bool GT6(const string &s)
{
return s.size()>=6;
}
//如果ctr不为,返回word的复数版本
string make_plural(size_t ctr,const string &word,const string &ending)
{
return (ctr==1) ? word:word+ending;
}
int main(int argc,char **argv)
{
//检查命令行参数
if(argc<2)
{
cerr<<"No input file!"<<endl;
return EXIT_FAILURE;
}
//打开文件
ifstream inFile;
inFile.open(argv[1]);
if(!inFile)
{
cerr<<"Can not open input file!"<<endl;
return EXIT_FAILURE;
}
vector<string> words;
string word;
//读入要分析的输入序列,并存放在vector容器中
while(inFile>>word)
words.push_back(word);
//对输入排序以便去除重复的单词
sort(words.begin(),words.end());
//使用算法unique对元素重新排序并返回一个迭代器,
//表示无重复的单词范围的结束,
//erase操作使用该迭代器删除输入序列中重复的单词
words.erase(unique(words.begin(),words.end()),words.end());
//将单词按长度排序,等长的单词按字典顺序排列
stable_sort(words.begin(),words.end(),isShorter);
//计算并输出长度不小于的单词的数目
vector<string>::size_type wc=count_if(words.begin(),words.end(),GT6);
cout<<wc<<" "<<make_plural(wc,"word","s")<<" 6 characters or longer"<<endl;
//输出输入序列中不重复的单词
cout<<"unique words:"<<endl;
for(vector<string>::iterator iter=words.begin();iter!=words.end();++iter)
cout<<*iter<<" ";
cout<<endl;
system("pause"); //程序在此处停住,以便检查运行结果!
return 0;
}
(5).测试文件内容:
the quick red fox jumps over the slow red turtle