740 likes | 938 Views
C++ 程序设计. string 、 vector. 3.1 标准库 string 类型. 3.1.1 对象与变量. 一般情况下,为了与内置类型变量相区别,称复杂数据类型的变量为 对象 ( object ),或称某某数据类型对象。 广义讲, 常量、变量 都称为 对象 ,狭义讲,对象仅指 复杂数据类型的变量 ,在本书中,沿用对象广义概念, 类变量 称为对象, 基本数据类型 的变量称为对象, 常量 也称为对象。. 3.1.2 string 对象的定义和初始化. 为了在程序中使用 string 类型,必须包含 string 头文件 ,并导入名字空间,如下:
E N D
C++程序设计 string、vector
3.1 标准库string类型 3.1.1 对象与变量 一般情况下,为了与内置类型变量相区别,称复杂数据类型的变量为对象(object),或称某某数据类型对象。 广义讲,常量、变量都称为对象,狭义讲,对象仅指复杂数据类型的变量,在本书中,沿用对象广义概念,类变量称为对象,基本数据类型的变量称为对象,常量也称为对象。
3.1.2 string对象的定义和初始化 为了在程序中使用string类型,必须包含string头文件,并导入名字空间,如下: #include <string> using std::string; 标准库string是类类型,类类型对象通过构造函数初始化,构造函数是一个特殊的类成员函数,在类对象初始化的时候执行。
3.1.2 string对象的定义和初始化 表3-1 string的几个常用构造函数
3.1.3 string对象的输入输出 【例 3.1】string对象的输入和输出操作。 #include <iostream> #include <string> using namespace std; // using std::string; int main( ) { string s1, s2;// 定义s1、s2,并初始化s1、s2为空字符串 // 依次读取字符串一赋给s1,字符串二赋给s2 cin >> s1 >> s2; // 注意空白字符s1="hello world" cout << s1 << s2 << endl; // 输出s1和s2 return 0; } 提示:利用 getline(cin,s1)可实现整行字符的读取
3.1.4 string对象的操作 对象成员包括该数据类型定义的成员函数和内部数据成员,要调用一个对象的成员函数,或者引用一个对象的内部数据成员,通过“.”运算符,表示如下: 对象名.数据成员 或者 对象名.成员函数名(参数表) 前者引用的是数据成员,后者调用成员函数,这里,“.”是一个运算符,功能是表示对象的成员。
3.1.4 string对象的操作 1.string的大小和容量函数 • 一个C++字符串存在3种大小,相应的函数分别是: • 函数size( )和length( )等价,都返回string对象中字符个数。函数empty( )判断字符串是否为空,判断字符串是否空也可以利用函数size( )或者length( ),将长度与0比较;
3.1.4 string对象的操作 【例 3.2】string的大小和容量函数的使用。 #include <iostream> #include <string> using namespace std; int main( ) { string s("Hello World!"); // s初始化为"Hello World!" cout << s.length( ) << endl; cout << s.size( ) << endl; if ( s.empty( ) ) cout << "s 是空串" << endl; else cout << "s 长度是" << s.size( ) << endl; return 0; }
3.1.4 string对象的操作 2.string关系运算 string类定义了常见的关系运算符(==、!=、<、<=、>、>=),关系运算符比较两个string对象时采用大小写敏感的字典序策略。 • str1、str2比较,不失一般性,假设str1.length()< str2.length(),str2比str1长,如果str1与str2前面部分相同,则 str1小于str2。 • 如果str1和str2的字符不同,则比较第一个不匹配的字符。
3.1.4 string对象的操作 例如: string subStr = "Hello"; string phrase = "Hello World"; string str = "Hi"; 如果两两比较,则subStr小于phrase,str大于subStr,str大于phrase。
3.1.4 string对象的操作 string类还支持比较成员函数compare( ),compare( )支持用索引值和长度定位子串来进行比较,返回一个整数,如: string s("abcd"); string s2("ab"); s.compare("abcd"); // 将s("abcd")和"abcd"比较,相等,返回0 s.compare("dcba"); // 将s("abcd")和"dcba"比较,返回一个小于0的值 s.compare( s2 );// 将s("abcd")和s2("ab")比较,返回大于0的值 s.compare(s);// 相等,返回0 //将s(“abcd”)中“ab”和s(“abcd”)中“cd”比较,返回值小于0
3.1.4 string对象的操作 3.string对象的赋值 string对象的赋值可使用操作符运算符=,如: string strTo, strFrom=“hello”; strTo = strFrom;
3.1.4 string对象的操作 4.string对象相加 相加指字符串连接,支持string对象和string对象、string对象与const char*对象、string对象与char对象,可以通过使用加运算符(+)或复合赋值运算符(+=)连接,结果生成一个新的string对象,例如 string s1("Hello "); string s2("World\n"); 下面通过加法生成新的string对象: string s3 = s1 + s2; // s3是:Hello World\n string + string // s4是:Hello Kitty string + 字符串字面值 string s4 = s1 + "Kitty";
3.1.4 string对象的操作 如果要把s2直接追加到s1末尾,可以使用+=运算符: s1 += s2; // 相当于s1 = s1 + s2 string加法返回的是string对象,和流输入输出(>>、<<)返回流对象类似,可以串接使用,如下: string s1, s2; cin >> s1 >> s2; s1 = s1 + ", " + s2;// 注意+ 左操作数必须是string对象 // s1="error"+","+s2 cout << s1 << ", " << s2 << endl;
3.1.4 string对象的操作 5.string对象的字符元素存取 string类型支持通过下标运算符[ ]或者通过at( )函数访问其中的字符元素,下标运算符[ ]需要一个size_type类型的值,作为“下标”或“索引”,以标明要访问字符的位置,string对象的下标从0开始,如果s是一个string对象且s不空,则s[0]就是字符串的第一个字符,s[1]就表示第二个字符,而s[s.size( )-1]则表示s的最后一个字符。
3.1.4 string对象的操作 【例 3.12】string对象的字符元素存取操作。 #include <iostream> #include <string> using namespace std; int main( ) { string s("some string"); for (string::size_type ix = 0; ix != s.size( ); ++ix) { cout << s[ix] << endl; } for (string::size_type index = 0; index != s.size( ); ++index) { cout << s.at(index) << endl; } return 0; }
3.2 标准库vector类型 vector称为容器,因为vector能够像容器一样存放各种数据类型的对象,不过,同一个vector中的所有对象都必须是相同数据类型,格式是将数据类型放在vector后面的尖括号中,例如: vector<int> ivec; // ivec可存取int类型的元素 vector<string> svec; // svec可存取string类型元素
3.2.1 vector对象的定义和初始化 为了在程序中使用vector类型,必须包含vector头文件,并导入名字空间,如下: #include <vector> using std::vector; vector<int> ivec; 如果不导入名字空间,则需要通过域限定符::引用vector: std::vector<int> ivec;
3.2.1 vector对象的定义和初始化 表3-3 vector类型的几个常用构造函数
3.2.1 vector对象的定义和初始化 • vector<T> v1 • 创建一个T类型的空的vector对象。 • vector<T> v2(v1) • 用vector对象v1初始化对象v2时,v2中每一个元素都初始化为v1中相应元素的副本,v1和v2必须同元素类型。 • vector<int> ivec1; // ivec1可存放int类型的元素 • vector<int> ivec2(ivec1);// 通过从ivec1复制元素来创建ivec2 • vector<string> svec(ivec1);// 错误:svec的元素类型是string
3.2.1 vector对象的定义和初始化 • vector<T> v3(n, i) • 用元素个数和元素值初始化vector对象。 vector<int> ivec4(10, -1); 创建一个包含10个int类型数据的vector,每个元素都初始化为-1; vector<string> svec(10, "hi!"); 创建一个包含10个string类型数据的vector,每个元素都初始化为"hi!"。
3.2.1 vector对象的定义和初始化 • vector<T> v4(n) 创建一个包含n个T类型数据的vector对象,vector中元素的初始化,取决于vector中存储的元素的数据类型,如果vector保存基本数据类型的元素(如int、float),则用0初始化每个元素。 vector<float> fvec(10); // 10个元素,初始化为0 如果vector保存的是含有构造函数的类类型的元素(string),则用该类型的缺省构造函数初始化每个元素: vector<string> svec(10); // 10 个元素,初始化为空字符串
3.2.2 vector对象的操作 表3-4 常用的vector操作
3.2.2 vector对象的操作 vector的大小和容量函数 vector的empty( )和size( )函数与string类似,size( )返回vector相应的size_type类型,注意,使用size_type类型时,必须同时包含vector的元素类型: vector::size_type // 错误 vector<int>::size_type // 正确
3.2.2 vector对象的操作 2.向vector中添加元素 push_back( )函数将一个新元素添加到vector对象的后面,也就是“尾插”。 // 从标准输入读入单词并存储到vector中 #include <vector> using std::vector; string word; vector<string> svec; // 空vector for (int i = 0; i < 10; i++) { cin >> word; svec.push_back(word); // word尾插到svec中 }
3.2.2 vector对象的操作 3.vector的下标操作 vector支持通过下标运算符[ ]或者通过at( )函数访问元素,索引的数据类型是vector<T>::size_type,下标从0开始,如果ivec是一个vector<int>对象且ivec不空,则ivec[0]就是ivec的第一个字符,ivec[1]表示第二个字符,ivec[ivec.size( )-1]表示ivec的最后一个元素。 vector的at( )函数会检查索引参数的范围,如果索引无效,会抛出out_of_range异常。
3.2.2 vector对象的操作 【例 3.4】vector的操作示例一。 #include <iostream> #include <vector> using namespace std; int main( ) { vector<int> ivec; // 空vector // 索引数据类型是vector<T>::size_type,这里是vector<int>::size_type for (vector<int>::size_type index = 0; index < 7; ++ index) { ivec.push_back(index) ; // 尾插 } cout<<ivec.size()<<endl; for (vector<int>::size_type idx = 0; idx != ivec.size( ); ++idx) { cout << ivec[idx] << ", "; // 下标运算符[ ] } cout << endl; for(unsigned i=0;i<ivec.size();i++){ ivec.pop_back(); // 删除最后一个数据元素 } cout<<ivec.size()<<endl; cout << endl; return 0;} 运行结果: 7 0, 1, 2, 3, 4, 5, 6, 0
3.2.2 vector对象的操作 4.下标操作不添加元素 下标只能索引已存在的元素,必须是已存在的元素才能用下标运算符进行索引,试图索引不存在的元素将产生运行时错误,例如: vector<int> ivec; // 空vector cout << ivec[0]; // 错误:ivec中尚没有元素 vector<int> ivec2(10); // ivec2包含10个元素 // 错误:索引越界,ivec元素的索引范围:0…9 cout << ivec[10];
3.2.2 vector对象的操作 因为不能索引尚不存在的元素,所以,不能通过vector的下标赋值添加元素,如下: vector<int> ivec; // 空vector for (vector<int>::size_type ix = 0; ix != 10; ++ix) ivec[ix] = ix + 3; // 应用程序错误 ivec是空的vector对象,添加元素正确写法应该是: vector<int> ivec; // 空vector for (vector<int>::size_type ix = 0; ix != 10; ++ix) ivec.push_back( ix + 3 ); // 尾插
3.2.2 vector对象的操作 5.删除vector中的元素 vector提供了erase( )、pop_back( )删除vector中的元素,pop_back( )功能是删除vector中最后一个元素,如果vector为空,则相当于什么也没做。
3.2.2 vector对象的操作 【例 3.14】vector的操作示例二。 #include <iostream> #include <vector> using namespace std; int main( ) { vector<int> ivec; vector<int>::size_type ix; for (ix = 0; ix != 10; ++ix) ivec.push_back( ix + 1 ); // 填充ivec for (ix = 0; ix != ivec.size( ); ++ix) cout << ivec.at(ix) << ", "; // 输出ivec cout << endl; ivec.pop_back( ); // ivec.pop_back( )
3.2.2 vector对象的操作 for (ix = 0; ix != ivec.size( ); ++ix) cout << ivec.at(ix) << ", "; cout << endl; vector<int>::iterator beg = ivec.begin( ); ivec.erase(beg + 4); // erase( pos ) for (ix = 0; ix != ivec.size( ); ++ix) cout << ivec.at(ix) << ", "; cout << endl; beg = ivec.begin( ); vector<int>::iterator end = ivec.end( ); ivec.erase(beg + 3, end - 2); // erase(beg, end) for (ix = 0; ix != ivec.size( ); ++ix) cout << ivec.at(ix) << ", "; cout << endl; return 0; } 运行结果: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 6, 7, 8, 9, 1, 2, 3, 8, 9,
3.3 数组 数组的作用 程序设计中,在处理相互间有关联的变量(如数列、矩阵等)时,通过数组把多个相同类型的变量有序地组织起来,可以提高编程效率,改善代码的可读性 。
3.3.1 数组的定义 数组定义的一般形式为: 类型说明符 数组名 [常量表达式], …; 类型说明符可以是除引用类型外的任意数据类型,数组名是标识符,方括号中的常量表达式是数组元素个数,称为数组的长度,例如: int A[5]; // 定义int类型数组A,有5个元素 // 定义float类型数组B和C,长度分别为10和20 float B[10], C[20]; char ch[20]; // 定义char类型数组ch,有20个元素
3.3.1 数组的定义 不能用变量定义元素的个数,数组要求在定义时有确定的数据类型和长度,以便分配存储空间,例如: #define FD 5 int main( ) { int A[3 + 2], B[7 + FD]; …} 是合法的, 下述数组定义是错误的: int main( ) { int n = 5; int A[n]; // 错误:定义时,数组长度不可以是变量 …}
3.3.2 数组的初始化 数组的初始化是在定义数组的同时,为其元素提供一组用逗号分隔的初值,初值用花括号{ }括起来,称为初始化列表。 const unsigned array_size = 5; int ia[array_size] = {0, 1, 2, 3, 4}; 初始化赋值的一般形式为: 类型说明符 数组名[常量表达式] = {值,值,…值} 当{ }中值的个数少于元素个数时,只给前面部分元素赋值,例如: int a[10] = {0, 1, 2, 3, 4};
3.3.2 数组的初始化 另外,只能给元素逐个提供初值,例如:给5个元素全部赋初值1,只能写为: int a[5] = {1, 1, 1, 1, 1 }; 而不能写为: int a[5] = 1; 给全部元素赋值,则在数组定义中,可以不给出数组元素的个数,例如: int a[5] = {1, 2, 3, 4, 5}; 可写为: int a[ ] = {1, 2, 3, 4, 5}; // 编译器自动确定数组长度5 因为显式初始化,编译器会根据列出的元素个数确定数组长度。
3.3.2 数组的初始化 在数组定义时,如果没有指定数组元素的初值,则数组元素的初始化规则如下:基本数据类型数组,如果在函数体外定义,则其元素均初始化为0,如果在函数体内定义,则其元素不初始化。 int A[5]; // 基本数据类型数组 float B[10], C[20]; // 遵循变量初始化规则
3.3.3 字符数组 字符数组是指数组元素是字符的一类数组,可以用来存放多个字符,也可用来存放字符串。可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化。字符串字面值包含一个额外的空字符(‘\0’),标志字符串结束。 当使用字符串字面值来初始化创建的新字符数组时,将在新数组中加入空字符。 char ca1[] = {‘C’, ‘+’, ‘+’}; // 未追加空字符 char ca2[] = {'C', '+', '+', '\0'}; // 显式追加空字符'\0' // 用字符串字面值初始化的数组,其末位包含'\0' char ca3[] = "C++";
3.3.3 字符数组 例如,下面的初始化式将出现编译时的错误: char ca4[5] = "Hello" ; // 错误:数组ca4有6个元素
3.3.4 数组元素的访问 与vector不同,一个数组不能用另外一个数组初始化,也不能将一个数组直接赋值给另一个数组: int ia[] = {0, 1, 2, 3}; int ia2[4]; int ia4[](ia); // 错误:数组不能用另外一个数组初始化 ia2 = ia; // 错误:不能将数组赋值给另外一个数组 数组元素用下标运算符[ ]来访问,数组元素也是从0开始计数。
3.3.4 数组元素的访问 【例 3.6】数组元素的复制与输出。 #include <iostream> using namespace std; int main( ) { int ia[] = {0, 1, 2, 3, 4}; int ia2[5]; for(size_t ix = 0; ix < 5; ix++) { ia2[ix] = ia[ix];// 通过循环,对数组元素逐个复制 } for(size_t index = 0; index < 5; index++) { // 通过循环,对数组元素逐个输出 cout << ia2[index] << “, ”; } cout << endl; return 0; } 运行结果: 0, 1, 2, 3, 4,
3.3.5 二维数组与多维数组 C++语言支持多维数组,多维数组的元素有多个下标。 • 二维数组的定义 二维数组是一个m行n列矩阵,二维数组定义的一般形式是: 类型说明符 数组名[<m>][ <n>], …; 其中:m、n是常量表达式,m为数组行数,n为数组列数,分别是数组第1维和第2维的长度,例如 int a[3][4]; 二维数组元素的访问形式为: 数组名[下标1][下标2], 例如:a[1][2]表示数组a的第2行3列的元素。
3.3.5 二维数组与多维数组 • 二维数组初始化 • 二维数组可以看作元素是一维数组的数组,即其每一个元素是一个一维数组,二维数组初始化的方法有: • 给所有元素赋初值。给数组的所有元素赋初值的方法有两种,方法一: • {{0行初值}, {1行初值}, …, {m行初值}} • 即每行一个花括号,花括号间用逗号分隔,全部初值再用一个花括号,例如: • int a[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
3.3.5 二维数组与多维数组 方法二: {0行初值, 1行初值, …, m行初值} 所有初值放在一个花括号中,按数组排列的顺序给各元素赋初值,例如: int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; 注意:若对所有元素都赋初值,则定义数组时行数可不指定,而列数必须指定,例如: int a[ ][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; 或: int a[ ][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
3.3.5 二维数组与多维数组 • 部分元素赋初值 {{0行部分初值}, {1行部分初值}, …, {m行部分初值} } 例如: int a[3][4] = {{1, 2}, {5}, {9, 10, 11} };
3.3.5 二维数组与多维数组 • 二维数组的应用 【例 3.7】5个学生,3门课程,学号及成绩如表3-5所示,编程求每个学生的平均成绩,并输出每个学生的学号、3门课程成绩和平均成绩。
3.3.5 二维数组与多维数组 #include <iostream> using namespace std; int main( ) { int A[5]; // 存储学号 float S[5][4]; //存储5个学生3门课成绩和平均成绩 int i, j; for (i = 0; i < 5; i++) { cin >> A[i]; // 输入5个学生的学号 for (j = 0; j < 3; j++) cin >> S[i][j]; // 输入3门课成绩 } for (i = 0; i < 5; i++) { // 计算每个学生的平均成绩 S[i][3] = (S[i][0] + S[i][1] + S[i][2]) / 3; }
3.3.5 二维数组与多维数组 for (i = 0; i < 5; i++) { cout<< A[i] << " "; // 输出学号 // 输出每个学生的3门课程成绩和平均成绩 for (j = 0; j < 4; j++) cout << S[i][j] << " "; cout << endl; } return 0; }
3.4 指针 在C++中,将系统为变量、数组、函数等分配的内存首地址称为指针,C++支持通过指针操纵内存单元,在程序中,用一个变量来存放指针,存放指针的变量称为指针变量,在不引起混淆的时候,将指针变量简称指针,将内存首地址简称为内存地址或者地址。