从这里开始,就是郭炜老师的《程序设计与算法(三)C++面向对象程序设计》的内容了,笔记会更加具体,会有很多类与对象的内容,同时和之前的笔记一样更加偏向实际运用方面而不是纯理论。
在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来。
另外,由于笔者主要是在word上编辑的这篇文章,除了代码部分的部分””双引号不是编辑器可以理解的双引号,所以如果要复制的话记得修改双引号,造成不便深表歉意。
在这一篇文章中,我们主要介绍string的用法和应用
1.1 string的建立
string类是模板类:
typedef basic_string<char>string;
使用string类要包含头文件<string>
string对象的初始化:
string s1(“hello”);
string month = “March”;
string s2(8,’x’);(这里面s2就有8个x)
错误的初始化方法:
string error1 = ‘c’; //错
string error2(‘u’); //错
string error3 = 22; //错
string error4(8); //错
(归纳起来就是不能直接赋字符和其他类型的变量)
但是我们可以将字符赋给string对象
string s;
s = ‘n’;
这样是对的
一个包含以上的内容的简单样例:
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 5 int main(int argc, char const *argv[]) 6 { 7 string s1("hello"); 8 cout<<s1<<endl;//输出:hello 9 string s2(8,'x'); 10 cout<<s2<<endl;//输出:xxxxxxxx 11 string month = "March"; 12 cout<<month<<endl;//输出:March 13 string s; 14 s = 'n'; 15 cout<<s<<endl;//输出:n 16 return 0; 17 }样例
string对象的长度用成员函数length()读取
string s(“hello”);
cout<<s.length()<<endl;
string支持流读取运算符(如果没学过类中的输入输出流的话,只用了解它支持cin就行了)
string stringObject;
cin>>stringObject;
string支持getline函数
string s;
getline(cin,s);(getline相当于读取一整行的cin,不会因为空格而停顿,在输入人名时会有用,比如用cin输入Awake Fantasy就会在接收完Awake时就结束了,而getline就能接收整个名字)
1.2 string的赋值和连接
用 = 赋值
string s1(“cat”),s2;
s2 = s1;
用assign成员函数复制
string s1(“cat”),s3;
s3.assign(s1);
用assign成员函数部分复制
string s1(“catpig”),s3;
s3.assign(s1,1,3);//从s1中下标为1的字符开始复制三个字符
(测试一下发现这里s3是atp,看来string是从下标为1开始存的,我还以为老师会复制cat呢)
单个字符复制
s2[5] = s1[3] =’a’;
逐个访问string对象中的字符
string s1(“hello”);
for(int i = 0;i<s1.length();i++)
cout<<s1.at(i)<<endl;
成员函数at会做范围检查,如果超出范围,会抛出out_of_range异常,而下标运算符[]不做范围检查。(不做范围检查的效率比做的快,所以要是打比赛要用什么懂得都懂)
用 + 运算符连接字符串
string s1(“good ”),s2(“morning!”);
s1 += s2;
cout<< s1;
用成员函数append连接字符串
string s1(“good ”),s2(“morning!”);
s1.append(s2);
cout<<s1;
s2.append(s1,3,s1.size());//s1.size()为s1的字符数
cout<<s2;
下标为3开始,s1.size()个字符,如果字符串内没有足够字符,则复制到字符串最后一个字符
1.3 比较string
用关系运算符比较string的大小
==, >, >=, <, <=, !=
返回值都是bool类型,成立返回true,否则返回false
例如:
1 string s1("hello"),s2("hello"),s3("hell"); 2 bool b = (s1 == s2); 3 cout<<b<<endl; 4 b = (s1 == s3); 5 cout<<b<<endl; 6 b = (s1 > s3); 7 cout<<b<<endl;
输出:1 0 1
用成员函数compare比较string的大小
1 string s1("hello"),s2("hello"),s3("hell"); 2 int f1 = s1.compare(s2); 3 int f2 = s1.compare(s3); 4 int f3 = s3.compare(s1); 5 int f4 = s1.compare(1,2,s3,0,3);//s1 1-2; s3 0-3 6 int f5 = s1.compare(0,s1.size(),s3);//s1 0-end 7 cout<<f1<<endl;//0 hello == hello 8 cout<<f2<<endl;//1 hello > hell 9 cout<<f3<<endl;//-1 hell < hello 10 cout<<f4<<endl;//-1 el < hell 11 cout<<f5<<endl;//1 hello > hell
(int f4 = s1.compare(1,2,s3,0,3);//s1 1-2; s3 0-3
这里的1,2是表示从1开始的2个字符,不是下标1到下标2,有兴趣可以去尝试一下)
1.4 子串
成员函数 substr
1 string s1("hello world"),s2; 2 s2 = s1.substr(4,5); 3 cout<<s2<<endl;//结果:o wor
这里substr(4,5)是指下标4开始5个字符
成员函数 swap
1 string s1("hello world"),s2("really"); 2 s1.swap(s2); 3 cout<<s1<<endl;//结果:really 4 cout<<s2<<endl;//结果:hello world
寻找string中的字符
成员函数 find()
string s1(“hello world”);
s1.find(“lo”);
在s1中从前向后查找”lo”第一次出现的地方,如果找到,返回”lo”开始的位置,即l所在位置的下标。如果找不到,返回string::npos(string中定义的静态常量)(npos应该就是 no position吧)
成员函数rfind()
string s1(“hello world”);
s1.rfind(“lo”);
在s1中从后向前查找”lo”第一次出现的地方,如果找到,返回”lo”开始的位置,即l所在位置的下标。如果找不到,返回string::npos(string中定义的静态常量)(这个rfind的“r”应该就是reverse)
find还可以指定开始查找的位置:
1 string s1("hello worlld"); 2 cout<<s1.find("ll",1)<<endl;//结果:2 3 cout<<s1.find("ll",2)<<endl;//结果:2 4 cout<<s1.find("ll",3)<<endl;//结果:9 5 //分别从下标1,2,3开始查找“ll”
(注意一下哈,从第三个开始找时,这里s1是“worlld”,有两个‘l’,所以找到了,如果是“world”,输出的是垃圾数字(18446744073709551615),如果自己测试一下的话,会发现find函数找不到的返回值是前面的提到的string::npos)
成员函数find_first_of()
string s1("hello world");
s1.find_first_of("abcd");
在s1中从前向后查找"abcd"中任何一个字符第一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。
成员函数find_last_of()
string s1("hello world");
s1.find_last_of("abcd");
在s1中查找"abcd"中任何一个字符最后一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。
成员函数find_first_not_of()
string s1("hello world");
s1.find_first_not_of("abcd");
在s1中从前向后查找不在"abcd"中的字母第一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。
成员函数find_last_not_of()
string s1("hello world");
s1.find_last_not_of("abcd");
在s1中从后向前查找不在"abcd"中的字母第一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。
上述4个函数的例子:
1 string s1("hello world"); 2 cout<<s1.find("ll")<<endl;//结果:2 3 cout<<s1.find("abc")<<endl;//结果:18446744073709551615 4 cout<<s1.rfind("ll")<<endl;//结果:2 5 cout<<s1.rfind("abc")<<endl;//结果:18446744073709551615 6 cout<<s1.find("ll")<<endl;//结果:2 7 cout<<s1.find_first_of("abcde")<<endl;//结果:1 8 cout<<s1.find_first_of("abc")<<endl;//结果:18446744073709551615 9 cout<<s1.find_last_of("abcde")<<endl;//结果:10 10 cout<<s1.find_last_of("abc")<<endl;//结果:18446744073709551615 11 cout<<s1.find_first_not_of("abcde")<<endl;//结果:0 12 cout<<s1.find_first_not_of("abc")<<endl;//结果:0 13 cout<<s1.find_last_not_of("abcde")<<endl;//结果:9 14 cout<<s1.find_last_not_of("abc")<<endl;//结果:10
(那串乱七八糟的数字就是npos对应的)
1.5 删除string中的字符
成员函数erase()
string s1("hello world");
s1.erase(5);
cout<<s1;
cout<<s1.length();
cout<<s1.size();
去掉下标5及以后的字符
输出:hello55
(刚查了一下,size()和length()完全等同,只是length的可读性比较好而已)
1.6 替换string中的字符
成员函数replace()
用法1:
string s1("hello world");
s1.replace(2,3,"haha");
cout<<s1;
将s1中下标2开始的3个字符换成"haha"
(这里就是把"llo"换成了"haha")
输出:hehaha world
用法2:
string s1("hello world");
s1.replace(2,3,"haha",1,2);
cout<<s1;
将s1中下标2开始的3个字符换成"haha"中下标1开始的2个字符
(这里就是把"llo"换成了"ha")
输出:heah world
(老师这例子真别扭,heha world也行啊,heah是啥玩意啊)
(我还以为是我英语不好,上网一查:)
(好吧其实好像有这个单词,但是好像不太正式)
(啊啊啊不扯了,继续学习)
1.7 在string中插入字符
成员函数insert()
1 string s1("hello world"); 2 string s2("show insert"); 3 s1.insert(5,s2);//将s2插入s1下标5的位置 4 cout<<s1<<endl;//输出:helloshow insert world 5 s1.insert(2,s2,5,3); 6 //将s2中下标5开始的3个字符插入s1下标2的位置 7 cout<<s1<<endl;//输出:heinslloshow insert world
(从这个例子中能发现插入的位置是选定下标的后面)
1.8 转换成C语言式char*字符串
成员函数c_str()
string s1("hello world");
printf("%s\n",s1.c_str());
s1.c_str()返回传统的const char* 类型字符串,且该字符串以'\0'结尾,
输出:hello world
成员函数data()
string s1("hello world");
const char * p1 = s1.data();
for(int i=0;i < s1.length();i++)
printf("%c",&(p1+i))
s1.data()返回一个char* (区别)类型的字符串,对s1的修改可能会使p1出错。
输出:hello world
1.9 字符串流处理
除了标准流和文件流输入输出外,还可以从string进行输入输出;
类似istream和ostream进行标准流输入输出,我们用istringstream和ostringstream进行字符串上的输入输出,也称为内存输入输出。
#include<string>
#include<iostream>
#include<sstream>
样例:
1 #include<iostream> 2 #include<sstream> 3 #include<string> 4 using namespace std; 5 6 int main(int argc, char const *argv[]) 7 { 8 string input("Input test 123 4.7 A"); 9 istringstream inputString(input); 10 string string1, string2; 11 int i; 12 double d; 13 char c; 14 inputString >> string1 >> string2 >> i >> d >>c; 15 cout<<string1<<endl<<string2<<endl; 16 cout<<i<<endl<<d<<endl<<c<<endl; 17 long L; 18 if (inputString >> L) 19 { 20 cout<<"long\n"; 21 } 22 else 23 { 24 cout<<"empty\n"; 25 } 26 ostringstream outputString; 27 int a = 10; 28 outputString <<"This "<< a << "ok" << endl; 29 cout<<outputString.str(); 30 /* 31 输出: 32 Input 33 test 34 123 35 4.7 36 A 37 empty 38 This 10ok 39 */ 40 return 0; 41 }样例
最后inputString >> L 时,因为整个流已经读完了,所以返回false
后记:
开始做这篇笔记是一天前,本来一看视频只有20分钟,想着做完就跑路,然后那天跑路了还没做四分之一,无奈,第二天下午继续,下午2点开始,一动不动做了3个小时才把剩下的做完。
如果你问我累不累,我可以直接告诉你累,但是我是快乐的,我想说的是如果学习编程没有一个一颗爱好的心,是很难坚持下去的。
不知为什么,在我思考如何敲程序的时候,我的内心充满的是一种追求答案的渴望,在我敲出程序的时候,我的内心充满的是成就感,在我学习这些知识的时候,我感叹设计STL标准库的那帮人的精巧。
标准库中太多东西是相似的,不会在这里的函数在另一个地方不兼容,不会存在两个差不多的容器操作方式却截然不同的现象,还有类和对象的设计,提高了巨大的兼容性,或许这就是艺术吧。
找到自己的爱好和擅长的事物太重要了,如果一个人热爱着一个事物,其他人若在对那件事无感的情况下,热爱者做好那件事的概率相对来说要大得多。而且热爱者还能获得极大的正向反馈。
所以如果还没有找到自己的方向的话,努力去寻找吧!找到了方向的话,努力去前进吧!
突发奇想写了这么多,逻辑也是乱七八糟,大家看看就好,如果对大家有所帮助那自然最好,没所帮助的话大家就当我啥也没说吧哈哈哈~~~