许多C++程序在有标准类之前就已经存在了,因此既没有使用标准库类型string也没有使用vector.而且,许多C++程序为了兼容现存的C程序,也不能使用C++标准库.因此,现代的C++程序经常必须兼容使用数组和/或C风格字符串的代码,标准库提供了使兼容界面更容易管理的手段.
1.混合使用标准库类string和C风格字符串
正如前面所显示的,可用字符串字面值初始化string类对象:
string st3("Hello World"); //st3 holds Hello World
通常,由于C风格字符串与字符串字面值具有相同的数据类型,而且都是以空字符null结束,因此可以把C风格字符串用在任何可以使用字符串字面值的地方:
a.可以使用C风格字符串对string对象进行初始化或赋值.
b.string类型的加法操作需要两个操作数,可以使用C风格字符串作为其中的一个操作数,也允许将C风格字符串用作复合赋值操作的右操作数.
反之则不成立:在要求C风格字符串的地方不可直接使用标准库string类型对象.例如,无法使用string对象初始化字符指针:
char *str=st2; //compile-time type error
但是,string类提供了一个名为c_str的成员函数,以实现我们的要求:
char *str=st2.c_str(); //almost ok,but not quite
c_str函数返回C风格字符串,其字面意思是:"返回C风格字符串的表示方法",即返回指向字符数组首地址的指针,该数组存放了与string对象相同的内容,并且以结束符null结束.
因此c_str返回的指针指向const char类型的数组,所以上述初始化失败,这样做是为了避免修改该数组.正确的初始化应为:
const char *str=st2.c_str(); //ok
-----------------------------------------------------我是无辜的分割线-----------------------------------------------
注解:c_str返回的数组并不保证一定是有效的,接下来对st2的操作有可能会改变st2的值,使刚才返回的数组失效.如果程序需要持续访问该数据,则应该复制c_str函数返回的数组.
----------------------------------------------------我还是无辜的分割线----------------------------------------------
2.使用数组初始化vector对象
前面提到过不能用一个数组直接初始化另一数组,程序员只能创建新数组,然后显式地把源数组的元素逐个复制给新数组.这反映C++允许使用数组初始化vector对象,尽管这种初始化形式起初看起来有点陌生.使用数组初始化vector对象,必须指出用于初始化式的第一个元素以及数组最后一个元素的下一位置的地址:
const size_t arr_size=6;
int int_arr[arr_size]={0,1,2,3,4,5};
//ivec has elements:each a copy of the corresponding element in int_arr
vector<int> ivec(int_arr,int_arr+arr_size);
传递给ivec的两个指针标出了vector初值的范围.第二个指针指向被复制的最后一个元素之后的地址空间.被标出的元素范围可以是数组的子集:
//copies 3 elements:int_arr[1],int_arr[2],int_arr[3]
vector<int> ivec(int_arr+1,int_arr+4);
这个初始化创建了含有三个元素的ivec,三个元素的值分别是int_arr[1]到int_arr[3]的副本.
习题4,31 编写程序从标准输入设备读入字符串,并把该串放在字符数组中.描述你的程序如何处理可变长的输入.提供比你分配的数组长度唱的字符串数据测试你的程序.
//从标准输入设备读入字符串,并把该串存放在字符数组中
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int main()
{
string in_str; //用于读入字符串的string对象
const size_t str_size=10;
char result_str[str_size+1];
//读入字符串
cout<<"Enter a string(<="<<str_size
<<" characters):"<<endl;
cin>>in_str;
//计算需要复制的字符的数目
size_t len=strlen(int_str.c_str());
if (len>str_size)
{
len=str_size;
cout<<"String is longer than "<<str_size
<<" characters and is stored only "
<<str_size<<" characters!"<<endl;
}
//复制len个字符至字符数组result_str
strncpy(result_str,in_str.c_str(),len);
//在末尾加上一个空字符(null字符)
result_str[len+1]='/0';
return 0;
}
c_str是转换C风格跟string的标准库函数
为了接受可变长的输入,程序中用一个string对象存放读入的字符串,然后使用strncpy函数将该对象的适当内容复制到字符数组中.因为字符数组的长度是固定的,因此首先计算字符串的长度.若该长度小于或等于字符数组可容纳字符串的长度,则复制整个字符串至字符数组,否则,根据数组的长度,复制字符串中前面部分的字符,以防止溢出.
注意,上述给出的是满足题目要求的一个解答.事实上,如果希望接受可变长的输入并完整地存放到字符数组中,可以采用动态创建数组来实现
习题4.32 编写程序用int型数组初始化vector对象.
//用int型数组初始化vector对象
#include<iostream>
#include<vector>
using namespace std;
int main()
{
const size_t arr_size=8;
int int_arr[arr_size];
//输入数组元素
cout<<"Enter "<<arr_size<<" numbers:"<<endl;
for (size_t ix=0;ix!=arr_size;++ix)
cin>>int_arr[ix];
//用int型数组初始化vector对象
vector<int> ivec(int_arr,int_arr+arr_size);
return 0;
}
习题4.33 编写程序把int型vector复制给int型数组.
//把int型vector复制给int型数组
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> ivec;
int ival;
//输入vector元素
cout<<"Enter numbers:(Ctrl+Z to end)"<<endl;
while(cin>>ival)
ivec.push_back(ival);
//创建数组
int *parr=new int[ivec.size()];
//复制元素
size_t ix=0;
for(vector<int>::iterator iter=ivec.begin();iter!=ivec.end();++iter,++ix)
parr[ix]=*iter;
//释放数组
delete [] parr;
return 0;
}
4.34 编写程序读入一组string类型的数据,并将它们存储在vector中.接着,把该vector对象复制给一个字符指针数组.为vector中的每个元素创建一个新的字符数组,并把该vector元素的数据复制到相应的字符数组中,最后把指向昂该数组的指针插入字符指针数组.
//读入一组string类型的数据,并将它们存储在vector中.
//接着,把该vector对象复制给一个字符指针数组
//为vector中的每个元素创建一个新的字符数组
//并把该vector元素的数据复制到相应的字符数组中
//最后把指向该数组的指针插入字符指针数组
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main()
{
vector<string> svec;
string str;
//输入vector元素
cout<<"Enter strings:(Ctrl+Z to end)"<<endl;
while(cin>>str)
svec.push_back(str);
//创建字符指针数组
char **parr=new char*[svec.size()];
//处理vector元素
size_t ix=0;
for(vector<string>::iterator iter=svec.begin();iter!=svec.end();++iter,++ix){
//创建字符数组
char *p=new char[(*iter).size()+1];
//复制vector元素的数据到字符数组
strcpy(p,(*iter).c_str());
//将指向该字符数组的指针插入到字符指针数组
parr[ix]=p;
}
//释放各个字符数组
for(ix=0;ix!=svec.size();++ix)
delete[] parr[ix];
//释放字符指针数组
delete[] parr;
return 0;
}
看不懂 - - c_str是干嘛的
4.35 输出习题4.34中建立的vector对象和数组的内容.输出数组后,记得释放字符数组.
//读入一组string类型的数据,并将它们存储在vector中.
//接着,把该vector对象复制给一个字符指针数组
//为vector中的每个元素创建一个新的字符数组
//并把该vector元素的数据复制到相应的字符数组中
//然后把指向该数组的指针插入字符指针数组
//输出建立的vector对象和数组的内容
#include<iostream>
#include<vector>
#include<string>
using namespace std;
int main()
{
vector<string> svec;
string str;
//输入vector元素
cout<<"Enter strings:(Ctrl+Z to end)"<<endl;
while(cin>>str)
svec.push_back(str);
//创建字符指针数组
char **parr=new char*[svec.size()];
//处理vector元素
size_t ix=0;
for(vector<string>::iterator iter=svec.begin();iter!=svec.end();++iter,++ix){
//创建字符数组
char *p=new char[(*iter).size()+1];
//复制vector元素的数据到字符数组
strcpy(p,(*iter).c_str());
//将指向该字符数组的指针插入到字符指针数组
parr[ix]=p;
}
//输出vector对象的内容
cout<<"Content of vector:"<<endl;
for(vector<string>::iterator iter2=svec.begin();iter2!=svec.end();++iter2)
cout<<*iter2<<endl;
//输出字符数组的内容
cout<<"Content of character arrays:"<<endl;
for(ix=0;ix!=svec.size();++ix)
cout<<parr[ix]<<endl;
//释放各个字符数组
for(ix=0;ix!=svec.size();++ix)
delete[] parr[ix];
//释放字符指针数组
delete[] parr;
return 0;
}