字符串声明/引用参数(c++)的困难

Difficulties with string declaration/reference parameters (c++)

本文关键字:c++ 声明 引用 参数 字符串      更新时间:2023-10-16

上周我做了一个写函数的作业:该函数得到一个string和一个char值,应该将字符串分为两部分,即在现有字符第一次出现之前和之后。

代码有效,但我的老师让我再做一次,因为它写得不好。但我不知道如何让它变得更好。到目前为止,我知道用空格定义两个字符串是不好的,但在其他情况下,我会遇到越界的异常。由于字符串输入发生变化,字符串大小每次都会发生变化。

#include <iostream>
#include <string>
using namespace std;
void divide(char search, string text, string& first_part, string& sec_part) 
{
bool firstc = true;
int counter = 0;
for (int i = 0; i < text.size(); i++) {
if (text.at(i) != search && firstc) {
first_part.at(i) = text.at(i);
}
else if (text.at(i) == search&& firstc == true) {
firstc = false;
sec_part.at(counter) = text.at(i);
}
else {
sec_part.at(counter) = text.at(i);
counter++;
}
}
}
int main() {
string text;
string part1="                            ";
string part2="                            ";
char search_char;   
cout << "Please enter text? ";
getline(cin, text);
cout << "Please enter a char: ? ";
cin >> search_char;
divide(search_char,text,aprt1,part2);
cout << "First string: " << part1 <<endl;
cout << "Second string: " << part2 << endl;
system("PAUSE");
return 0;
}

我建议您学习使用c++标准函数。有很多实用函数可以帮助你进行编程。

void divide(const std::string& text, char search, std::string& first_part, std::string& sec_part)
{
std::string::const_iterator pos = std::find(text.begin(), text.end(), search);
first_part.append(text, 0, pos - text.begin());
sec_part.append(text, pos - text.begin());
}
int main()
{
std::string text = "thisisfirst";
char search = 'f';
std::string first;
std::string second;
divide(text, search, first, second);
}

这里我用了std::find,你可以从这里读到它,还有Iterators

你还有其他一些错误。您通过值传递文本,每次调用函数时都会进行复制。通过引用传递它,但用const限定它,这将表明它是一个输入参数而不是输出。

为什么你的老师是对的

事实上,你需要用空格初始化你的目的字符串是可怕的:

  • 如果输入字符串较长,则会出现越界错误
  • 如果它更短,您就会得到错误的答案,因为在it和编程中,"It works ""It works"不同

此外,您的代码不符合规范。它应该一直工作,与存储在输出字符串中的当前值无关。

备选方案1:您的代码正在运行

只需在开头清除目标字符串。然后像您所做的那样迭代,但使用+=push_back()在字符串末尾添加字符。

void divide(char search, string text, string& first_part, string& sec_part) 
{
bool firstc = true;
first_part.clear();   // make destinations strings empty
sec_part.clear();  
for (int i = 0; i < text.size(); i++) {
char c = text.at(i); 
if (firstc && c != search) {
first_part += c;
}
else if (firstc && c == search) {
firstc = false;
sec_part += c;
}
else {
sec_part += c;
}
}
}

为了避免多重索引,我使用了临时c,而不是text.at(i)text[i]。但这并不是真正需要的:如今,无论您在这里使用什么变体,优化编译器都应该产生等效的代码。

备选方案2:使用字符串成员函数

这个替代方法使用find()函数,然后从开始到那个位置构造一个字符串,从那个位置构造另一个字符串。有一种特殊情况是找不到字符。

void divide(char search, string text, string& first_part, string& sec_part) 
{
auto pos = text.find(search); 
first_part = string(text, 0, pos);
if (pos== string::npos) 
sec_part.clear(); 
else sec_part = string(text, pos,  string::npos); 
}

根据您自己的理解,这些声明

string part1="                            ";
string part2="                            ";

因为在对象CCD_ 14中输入的字符串基本上可以超过两个初始化的字符串。在这种情况下,使用字符串方法at可能导致抛出异常,或者字符串将有尾随空格。

根据分配的描述,不清楚搜索的字符是否应包含在其中一个字符串中。您假设该字符应该包含在第二个字符串中。

考虑到参数text应声明为常量引用。

此外,与其使用循环,不如使用类std::string的方法,例如find

的功能如下

#include <iostream>
#include <string>
void divide(const std::string &text, char search, std::string &first_part, std::string &sec_part)
{
std::string::size_type pos = text.find(search);
first_part = text.substr(0, pos);
if (pos == std::string::npos)
{
sec_part.clear();
}
else
{
sec_part = text.substr(pos);
}
}
int main()
{   
std::string text("Hello World");
std::string first_part;
std::string sec_part;
divide(text, ' ', first_part, sec_part);
std::cout << """ << text << ""n";
std::cout << """ << first_part << ""n";
std::cout << """ << sec_part << ""n";
}

程序输出为

"Hello World"
"Hello"
" World"

正如你所看到的,分隔字符包含在第二个字符串中,尽管我认为最好将其从两个字符串中排除。

另一种选择,在我看来,更明确的方法可以如下

#include <iostream>
#include <string>
#include <utility>
std::pair<std::string, std::string> divide(const std::string &s, char c)
{
std::string::size_type pos = s.find(c);
return { s.substr(0, pos), pos == std::string::npos ? "" : s.substr(pos) };
}
int main()
{   
std::string text("Hello World");
auto p = divide(text, ' ');
std::cout << """ << text << ""n";
std::cout << """ << p.first << ""n";
std::cout << """ << p.second << ""n";
}

只有在part1.length()中找到字符时,您的代码才能工作。您需要类似的东西:

void string_split_once(const char s, const string & text, string & first, string & second) {
first.clear();
second.clear();
std::size_t pos = str.find(s);
if (pos != string::npos) {
first  = text.substr(0, pos);
second = text.substr(pos);
}

}

我看到的最大问题是,在应该使用push_back的地方使用at。请参见std::basic_string::push_back。at被设计为访问一个现有字符来读取或修改它。push_back在字符串中添加一个新字符。

divide可能看起来像这样:

void divide(char search, string text, string& first_part,
string& sec_part)
{
bool firstc = true;
for (int i = 0; i < text.size(); i++) {
if (text.at(i) != search && firstc) {
first_part.push_back(text.at(i));
}
else if (text.at(i) == search&& firstc == true) {
firstc = false;
sec_part.push_back(text.at(i));
}
else {
sec_part.push_back(text.at(i));
}
}
}

由于您不处理异常,请考虑使用text[i]而不是text.at(i)