C++抽象编程——字符串与整数之间的相互转换详解

鉴于文件和字符串都是字符序列,似乎有理由认为编程语言可能允许我们同样的地对待它们.C ++通过< sstream >库提供了这种功能,该库导出了几个类,允许将流与一个字符串值与< fstream >库允许将流与文件关联的方式大致相同。 istringstream类是ifstream的对应物,可以使用流操作符从字符串读取数据。对于输出,ostringstream类非常像流,除了输出被定向到一个字符串而不是一个文件。

字符串转整数

我们先来看一段代码:

#include 
#include 
#include  //string stream 
#include  //EXIT_FAILURE
#include 
using namespace std;
int stringToInteger(string str);
void error(string msg); //输出错误信息并且退出执行 
int main(){
    int n = 3,sum;
    cout << "输入要相加的字符串" << endl; 
    string line;
    getline(cin,line);//我们这个时候定义的line是string类 
    sum = n + stringToInteger(line);
    cout << "结果为  " << sum;
}
int stringToInteger(string str) {
    istringstream stream(str);
    int value;
    stream >> value >> ws;
    if (stream.fail() || !stream.eof()) {
    error("非法的整型转换");
        return 0;
    }
    return value;
}
void error(string msg){
    cerr << msg << endl;
    exit(EXIT_FAILURE);
}

结果如下:

代码分析

这里我们定义了一个函数 stringToInteger,顾名思义就是把string转换成int型以便用于运算,这在我们以后很常常用到(这个时候我们就可以用这个函数代替C++抽象编程——STL(2)——括号匹配与口袋计算器中口袋计算器中的atof函数)。
现在我们仔细分析一下 stringToInteger这个函数。

int stringToInteger(string str) {
    istringstream stream(str);
    int value;
    stream >> value >> ws;
    if (stream.fail() || !stream.eof()) {
    error("非法的整型转换");
        return 0;
    }
    return value;
}

函数的第一行,引入了我们尚未提到的变量声明的一个重要特征(在面向对象),如果我们声明一个对象,C++允许在控制该对象初始化的变量名之后提供参数。

istringstream stream(str);

声明一个名为stream的变量,并将其初始化为已设置为,从字符串变量str读取数据的istringstream对象。下两行代码:

int value;
stream >> value >> ws;

从该流读取整数值并将其存储在变量值value中。在此实现过程中,允许空白字符在该值之前或之后。第一个>>运算符自动跳过出现在该值之前的任何空白字符; 在行末尾的ws操纵器读取跟随该值的任何空白字符,从而确保如果输入格式正确,流将被正确定位在行尾。(也就是我们常常的 << 会忽略空白字符,但是ws会读取空白字符,将其结合在一起使用) 下面的if语句

if (stream.fail() || !stream.eof()) {
error("stringToInteger: Illegal integer format");
}

检查以确保输入有效。如果字符串不能被解析为整数,则stream.fail()将返回true,输出错误。但是,如果字符串以数字开头但是包含一些附加字符,则stream.eof()将为false,这也会输出错误。
比如下面的图片:

整数转字符串

如果需要在另一个方向进行转换,则可以使用ostringstream类。 例如,以下函数将整数转换为字符串:

string integerToString(int n) {
ostringstream stream;
stream << n;
return stream.str();
}

下面我们一样写个代码试试(为了方便,我就直接在上面的代码里添加了):

#include 
#include 
#include  //string stream 
#include  //EXIT_FAILURE
#include 
using namespace std;
int stringToInteger(string str);
string integerToString(int n);//返回类型为string 
void error(string msg); //输出错误信息并且退出执行 
int main(){
    int n = 3,sum;
    cout << "输入要相加的字符串" << endl; 
    string line;
    getline(cin,line);//我们这个时候定义的line是string类 
    sum = n + stringToInteger(line);
    cout << "结果为  " << sum;
    cout << endl;
    cout << "将结果变为字符串,然后前面加上abc" << endl;
    string str = "abc";
    str +=  integerToString(sum);
    cout << str << endl;
}
int stringToInteger(string str) {
    istringstream stream(str);
    int value;
    stream >> value >> ws;
    if (stream.fail() || !stream.eof()) {
    error("非法的整型转换");
        return 0;
    }
    return value;
}
string integerToString(int n) {
    ostringstream stream;
    stream << n;
    return stream.str();
}
void error(string msg){
    cerr << msg << endl;
    exit(EXIT_FAILURE);
}

执行的效果如下:

integerToString函数第二行中的<<运算符将其值转换为十进制表示形式,就像文件一样。 然而,在这里,输出被定向到作为ostringstream对象的一部分内部存储的字符串值。 return语句中的str函数复制该内部字符串的值,以便可以将其返回给调用者。 有趣的是,由于不再需要考虑到格式化错误,因此在这个方向上进行转换比较容易。

控制台输入的更好的策略

srtin流还提供了检查用户输入是否正确形成的问题的解决方案。 我们都知道,>>操作符不会检查用户的输入是否有错误。试想一下,比如我们有下面的代码:

int limit;
cout << "Enter exponent limit: ";
cin >> limit;

如果用户输入有效的整数,一切都很好。但是,如果用户尝试输入值16但是如果用户不小心滑倒键盘上的一行并输入字母t而不是数字6,则会发生什么。在理想的世界中,程序会查看输入1t并怀疑其有效性。 不幸的是,如果在C++中使用提取操作符,并不会检测该错误。当要求将值读入整数变量limit时,>>操作符读取字符,直到找到在整数字段中为非法的字符。 因此输入在t上停止,但是值1仍然是合法的整数,所以程序将保持正确的等于1的limit(即此时limit = 1)。就拿上面的第一个程序来说,如果我们把出错的信息都注释掉,当我们输入100a的时候,输出的sum就是103a,a不进行运算。

确保用户输入有效的最有效方法是将整行作为字符串读取,然后将该字符串转换为整数。 我们先写个getInteger函数来实现它,如下面的代码一样。该函数像>>操作符一样从用户读取一个整数,但也确保整数有效。

/*从用户请求一个整数值。 该功能通过在控制台上打印提示字符串开始,然后等待用户输入一行输入数据。 
*如果该行包含单个整数,该函数将返回相应的整数值。如果输入不是合法整数,或者输入行上出现了无关的字符
*(除空格之外),则该函数会给用户重新输入值
*/
int getInteger(string prompt) {
int value;
string line;
while (true) {
cout << prompt;
getline(cin, line);
istringstream stream(line);//按行输入
stream >> value >> ws;
if (!stream.fail() && stream.eof()) break;
cout << "Illegal integer format. Try again." << endl;
}
return value;
}

getInteger的逻辑类似于上一节中的stringToInteger函数中使用的逻辑。唯一的主要区别是getInteger给用户重新输入一个值,而不是使用错误消息终止程序,我们来运行一下第一个例子的精简加改进版本:

#include 
#include 
#include  //string stream 
#include 
using namespace std;
int getInteger(string prompt);
int main(){
    int n, sum = 0; string line;
    cout << "输入要相加的字符串" << endl;  
    n = getInteger(line);
    sum += n; 
    cout << "结果为  " << sum;
}
int getInteger(string prompt) {
    int value;
    string line;
    while (true) {
        cout << prompt;
        getline(cin, line);
        istringstream stream(line);
        stream >> value >> ws;
    if (!stream.fail() && stream.eof()) break;//当输入失败,跳出循环 
        cout << "不合法的输入,再试一次" << endl;
    }
    return value;
}

结果为:

你可能感兴趣的:(抽象编程(C++),C++学习与基础算法)