TLDR;这是C++从头开始系列的一部分。这一部分是关于如何编写一个可以读写控制台的程序。
参考资料
这里有一些有用的链接来了解更多。
为什么是控制台程序
控制台程序是在控制台工作的程序,它们没有用户界面,但它们仍然被大量使用,而且很有用。你说没有用户界面,这有什么好的?嗯,控制台程序很快,真的很快。此外,如果你需要自动发送args并监听输入,作为构建步骤的一部分,例如,如果你正在实践CI/CD,那么它们更容易编写脚本,并在构建服务器的背景下使用。
写入控制台
好了,我们知道为什么控制台程序有时是个好主意。我如何向控制台输出呢?有很多库可以为你做到这一点,但有两个常见的选择。
- iostream,基于流的库,被认为更像C++。
- cstdio,更像C语言的格式化。它的功能与iostream相似,但有人说它有一些问题,比如不能正确地检查插值,而且iostream在未来更安全。
你的第一个输出
要创建一个输出到控制台的程序,你需要iostream ,你需要cout ,像这样。
#include <iostream>
using namespace std;
int main()
{
cout << "Print this";
}
注意你是如何使用cout 和流操作符的,该操作符采用了<< 操作符,这意味着它写到了一个流,这个流将被送到控制台。
混合类型
好的,所以你很可能想结合数字和字符串,比如说总和是8。答案是使用流操作符<< ,像这样分开两种不同的数据类型。
#include <iostream>
using namespace std;
int main()
{
int sum = 8;
cout << "The sum is " << sum;
}
这是唯一的方法吗?如果我想写 "这个程序已经运行了8天 "这样的东西,显然是字符串、int和字符串的混合,我必须多次使用<< ?有几种不同的选择,如下面的代码所示。
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
int sum = 8;
cout << "The sum is " << sum << "\n";
cout << "This program has been running for " + to_string(sum) + "days";
printf("The program has been running for %d days", sum);
cout << format("The program has been running for {0} days", to_string(days));
}
<< "string" << number << "string".这是你到目前为止看到的版本,用<<,将不同的数据类型分开。"string" + to_string(number).在这个版本中,你通过使用函数to_string(),首先转换你的数字来连接字符串。printf.在这里,你使用库cstdio一个c风格的库,它可以插值,允许你通过使用占位符{0}来混合字符串和数字。0说的是它作为参数的位置,例如。
printf("Here's a number {0}, and another one", 3, 5);
format().这里我们使用的是C++20中引入的一个函数。请确保你已经升级了C++,以便能够使用这个函数。
格式化的输出
有一个库iomanip ,使你能够格式化输出,用它你可以做一些事情,例如。
- 设置对齐方式,你可以决定你打印的内容是向左还是向右对齐
- 设置宽度,你可以让你打印的内容占用N个字符,这样你就可以像表格一样打印输出。
下面是一个使用许多iomanips 功能的例子程序。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
cout << setw(10) << "row1col1" << setw(20) << "row1col2" << "\n";
cout << setw(10) << "row2col1" << setw(20) << "row2col2" << "\n";
}
我们有setw() ,设置宽度,用来创建两个不同的列。如果你要运行这个,你会得到以下输出。
row1col1 row1col2
row2col1 row2col2
还有更多的功能,请看文章顶部的 "参考文献 "部分。
从控制台读取信息
为了从控制台读取数据,我们可以使用cin ,从iostream 。你可以这样使用它。
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string name;
cout << "what's your name? ";
cin >> name;
cout << "Hi " << name << endl;
return 0;
}
在这里,cin >> name ,等待用户输入一个字符串,然后再输入一个返回键。然后,该值将被存储在name 。
最后我们键入该值。要尝试这个演示,请采取以下步骤。
- 将上述代码保存在一个文件app.cpp中
- 用
g++ app.cpp编译该程序 - 运行该程序。
./a.out # macOS, Linux
a.out.exe # windows
你应该看到程序像这样运行。
what's your name? chris
Hi chris
多重输入
想象一下,你有一个需要收集多个输入的情况。在下面的程序中,我们有一个计算程序。
#include <iostream>
#include <string>
using namespace std;
int main()
{
int no, no2;
cout << "--Add two numbers--\n";
cout << "First number: ";
cin >> no;
cout << "Second number: ";
cin >> no2;
cout << "The sum is: " << no + no2 << "\n";
return 0;
}
在上面的代码中,你要求一个数字,然后是下一个。但如果你想在一行中收集所有的东西呢?我们可以这样做,只要把代码改成下面的样子。
#include <iostream>
#include <string>
using namespace std;
int main()
{
int no, no2;
cout << "--Add two numbers--\n";
cout << "Input numbers (separated by space): ";
cin >> no >> no2;
cout << "The sum is: " << no + no2 << "\n";
return 0;
}
注意这一行cin >> no >> no2; ,你用>> 来分隔用户的输入。我们这样做的原因是,cin 只取第一个值,直到第一个空格。
我们可以使用的另一种方法是getline() ,读取整行,就像下面的代码。
#include <iostream>
#include <string>
using namespace std;
int main()
{
int sum;
string s_numbers;
cout << "--Add numbers--\n";
cout << "Input numbers (separated by space): ";
getline(cin, s_numbers);
// add code to split and convert numbers to int
cout << "The sum is: " << sum << "\n";
return 0;
}
getline() 读取整行,不管你是否使用空格字符。然而,现在你遇到的情况是,你需要解析 ,因为该行是以字符串形式存储的。如何解决?s_numbers
首先我们需要一个分割函数。
vector<int> split(const string line, char delimiter)
{
stringstream ss(line);
string item;
vector<int> numbers;
while(getline(ss, item, delimiter))
{
numbers.push_back(stoi(item));
}
return numbers;
}
我们要做的第一件事是把来自用户输入的line ,读到一个stringstream 对象中。想象一下,用户的输入是这样的:"1 2 3 4"。
现在我们使用while结构在字符串流对象上进行迭代。这使我们能够读取用户字符串中的每一个子串,所以每次迭代都会得到 "1""2""3""4"。然而,我们需要将其转换为一个int,我们用stoi() ,它将一个字符串转换成一个int。此外,我们需要将每个值添加到vector 类型的numbers (向量是一个动态列表,可以接受任何数量的项目)。
好了,我们解决了一半的问题。我们现在需要对向量中的值进行总结,像这样。
int sumNumbers(vector<int> v)
{
int sum = 0;
for(int i=0; i< v.size(); i++)
{
sum += v[i];
}
return sum;
}
很好,所以我们有东西在向量中循环,最后得到一个整数。现在来看看完整的程序。
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
vector<int> split(const string line, char delimiter)
{
stringstream ss(line);
string item;
vector<int> numbers;
while(getline(ss, item, delimiter))
{
numbers.push_back(stoi(item));
}
return numbers;
}
int sumNumbers(vector<int> v)
{
int sum = 0;
for(int i=0; i< v.size(); i++)
{
sum += v[i];
}
return sum;
}
int main()
{
string s_numbers;
cout << "--Add numbers--\n";
cout << "Input numbers (separated by space): ";
getline(cin, s_numbers);
vector<int> numbers = split( s_numbers, ' ' );
cout << "Sum is: " << sumNumbers( numbers ) << "\n";
}
你通过cin 和getline ,正如你所看到的,如果知道输入的数量,有时只用cin 和一些运算符>> ,会更容易。然而,如果我们需要用户写一个未知数量的输入,我们需要写更多的代码,并使用像stringstream和vector这样的结构来处理它。
小结
这篇文章就写到这里。使用iostream和iomanip的输入和输出可以让你走得更远,而使用stringstream和vector,你可以走得更远,也可以创建灵活的程序。