连接字符串的意外问题

Posted

技术标签:

【中文标题】连接字符串的意外问题【英文标题】:Unexpected problems concatenating strings 【发布时间】:2014-01-14 04:00:28 【问题描述】:

我正在尝试使用 + 连接字符串,但是发生了一些奇怪的事情。这是我的班级项目的“等级”课程:

#pragma once
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Grade 
    private:
        string className;
        string student;
        string letter;

    public:
        Grade(string c, string s, string l) : className(c), student(s), letter(l) 

        string getLetterGrade() const  return letter; 
        string getClassName() const  return className; 
        string getStudent() const  return student; 
        void setLetterGrade(string l)  letter = l; return;
        void setClassName(string c)  className = c; return;
        void setStudnet(string s)  student = s; return;

        string toString() const  string output = "hello"+student; return output; 
;

显然,toString() 方法目前不是我想要的。 如果我像上面那样运行 toString(),我会得到“hello529173860”,正如预期的那样。但是,如果我将行更改为:

string toString() const  string output = student+"hello"; return output; 

那么输出是“hello3860”。这不仅仅是将 hello 字符串放在前面,而是在此过程中替换学生字符串中的字符......不知何故?

此外,如果我尝试使用:

string toString() const  string output = "hello"+" world"; return output; 

我收到一个错误:

Grade.h: In member function ‘std::string Grade::toString() const’:
Grade.h:29:53: error: invalid operands of types ‘const char [6]’ and ‘const char [7]’ to binary ‘operator+’
   string toString() const  string output = "hello"+" world"; return output; 
                                                     ^

我真的对这里发生的事情感到不知所措......特别是因为我在程序的早期已经完成了字符串连接而没有问题。 我想要的是输出如下内容:

“学生+[一些空白]+字母+[一些空白]+类名”

【问题讨论】:

欢迎来到使用“using namespace std”的症状之一。不要将C-String(一个简单的字符串文本,一个字符数组,例如“hello”)与 std::string 混淆。当您编写 "hello" + "world" 时,您实际上是在尝试添加两个 char 数组或两个 char* 指针。也就是说,主要问题是 not 字符串运算符 +,它位于代码中的其他位置。见ideone.com/wKrmu6 你能告诉我们你是如何使用Grade对象的吗? 我刚刚进入 Com Sci 的第二个学期,但如果我要连接字符串,我会尝试使用字符串流。我记不太清了,但我认为我的导师说了一些关于 C++ 中的字符串如何不能仅与“+”运算符正确连接的内容。查看cplusplus.com/reference/sstream/stringstream/?kw=stringstream 以获取参考。 @zsherman 为什么需要字符串流?如果您使用 C 风格的字符串,std::string(const_char_one) + std::string(const_char_two)strcat 有什么问题?将std::stringconst char* 连接会做正确的事情,但"hello" + "world" 不会。 @remyabel 就像我说的,我是一个新手程序员,所以这是我第一次听说这些选项。不过,在谷歌搜索strcat 之后,我同意它看起来更有效。 【参考方案1】:

std::string 可以添加到任何内容(另一个 std::string、双引号字符串文字、char)并提供直观的结果,但是如果你尝试将双引号字符串文字添加到另一个字符串文字或 char 然后它不会“工作”:

添加到char 或其他整数值的字符串文字将经过标准转换为const char*,然后添加到指针的任何数字将沿着文字移动该数量的字符:如果偏移量是't 在字符串文字中,如果你取消引用(使用)结果指针,你会得到未定义的行为,

无法添加两个字符串文字,即使在衰减为两个指针之后,也会出现编译时错误。

有时你会想要显式地构造一个std::string,以便与其他值的连接可以按照你的意愿工作:例如my_string = std::string("hello ") + my_const_char_ptr + '\n'.

例子:

std::string s = "Hello";

s + " World"; // ok
"Hello " + s; // ok
"Hello " + "World"; // NOT ok - two string literals
s += " World"; // ok
s += " Goodbye " + "World"; // NOT ok - "+" evaluated before "+="
s += std::string(" Goodbye ") + "World"; // OK - right-hand-side no longer two literals
                                         // BUT may be slower than two "s +="

【讨论】:

你所说的一切都是真的,但这并不能解释student+"hello""hello"+student 如何表现得好像student 被截断了其中一个。就此而言,我不知道问题中的代码是否有任何合理的解释。 @MarkRansom:鉴于当前问题中的代码,“截断”是不可能的,但我确实解释了如何将数字添加到字符串文字可以在文本内的某个位置为您提供一个指针 - 这可能是在一些早期版本的代码中发生了什么...... 我最终发现了问题所在。我从一个文件中获取了一些信息,其中包含一个 '\r' 字符。尽管如此,这个答案对于追查问题最有帮助,所以我将其标记为已接受的答案。【参考方案2】:

常量字符串"hello""world" 只不过是const char* 类型的编译时常量。就像你不能添加两个 int 指针一样:

int *p1, *p2;
p1+p1; // Error

您不能添加两个 (const) char* 对象。这违反了 C/C++ 语言规则。如果你必须连接两个 const-char-pointers,你可以把它们放在一起:

"hello"  "world"

如果您将它们与宏一起使用,此技术主要有用。例如:

// Over simplified
#define ONE(_x) _x
#define TWO(_x) _X

ONE("This is") TWO(" concatenation")

如果要添加两个(或更多)运行时 C 字符串,则必须使用 strXXX 函数(如 strcat),或者最好使用 std::string

【讨论】:

至少对于 C++,“"hello""world" 只不过是 const char* 类型的编译时间常数”——实际上,它们的类型分别是 const char[5]const char[6],而不是 @ 987654337@。如果没有找到匹配项,则会尝试到 const char * 的标准转换。 没错,但是当两个数组相加时,它们被归结为指针相加的概念,差别不大。 "当两个数组被添加时" 从不发生,如果它是合法的并且被标准赋予了一些语义,那么没有特别的理由认为标准转换为指针会参与,但我知道你的意思...... ;-)。 我不在这里辩论。但是 VC 编译器为 int arr[1]; arr+arr; 提供 c2110 ;)【参考方案3】:

字符数组没有运算符 +。所以很明显这段代码

string toString() const  string output = "hello"+" world"; return output; 

无效。

在这个表达式"hello"+" world" 中使用了两个字符串字面量,它们的类型分别对应const char[6]const char[7]。运算符 + 没有为数组定义。

你可以写

string toString() const  return string( "hello" ) + " world"; 

在这种情况下,使用运算符 + 为类 std::string 重载。局部变量input 的声明是多余的。因此,您甚至可以通过以下方式简化功能

string toString() const  return "hello world"; 

【讨论】:

这只是一个半有用的答案。您能否通过解释另一种方法来完成 OP 试图完成的工作来扩展您的答案? @zsherman 这是一个很好的答案。有效结构不需要任何“替代方式”。

以上是关于连接字符串的意外问题的主要内容,如果未能解决你的问题,请参考以下文章

Lint错误 - 意外的字符串连接

WCF 超时太快和“连接意外关闭”异常

监听套接字意外死亡

Perl 字符串连接的奇怪行为

用点表示法连接字符串和变量 = 错误?

sql以只读模式打开连接