0

在 C++ 中,我通过从另一个已经初始化的字符串(字符串类)复制字符索引来创建一个新的字符串(字符串类)。

但我无法使用cout. 使用c_str()我可以使用cout. 但不是c_str()只在使用时才需要,printf()因为它需要交流类型的字符串?

#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

int main() {
    int i;
    string a,b;
    cin>>a;
    for(i=0;a[i]!='\0';i++){
        b[i]=a[i];
    }
    cout<<b;
    return 0;
}

编辑:感谢您的帮助!但是我的问题可能不太清楚,所以这些是我遇到的主要问题。请阅读以下内容,如果您能进一步帮助我,那就太好了!(另外,我理解b=a;是最简单的分配方法,但我试图理解字符串,因此是问题。)

a)我不知道cpp字符串何时为空终止,何时不是,但在这种情况下,初始化后的a字符串为空终止,因为循环结束并且它在字符串a的最后一个字符之后结束,因为从出来循环并cout<<a[i];打印 a 的最后一个字符。

b) 在循环中,在我包含cout<<b[i];它的赋值之后,打印出我们期望的值刚刚分配给 b[i]。所以 b[i] 确实存在一些奇怪的原因。

c)在for循环之外,在程序结束时,当我cout<<b[2];打印字符串的第三个字符时。如果我这样做cout<<b.c_str();,它会打印出整个字符串。只有当我这样做时cout<< b;,才会打印任何内容。为什么是这样?

4

3 回答 3

3

您可能已经注意到它std::string的行为不像普通的 C 样式字符串。注意到这一点很重要。

首先是这样的直接分配是行不通的。真正的原因是这不会改变字符串的大小。您可以通过输出自己找到它b.size(),或者检查两者b.start()b.end()引用相同的字符,b[0]

如果您首先将大小调整b为与a.

b.resize(a.size());

其次,看看你的循环。不要将其\0与 C 风格的字符串进行比较。相反,请检查 if i < a.size(),因为不能保证 astd::string将以 null ( \0) 终止。

但是,您真正应该做的只是将 a 分配给 b,然后 b 将拥有您想要的 a 的副本。

b = a;
于 2016-09-28T14:04:28.227 回答
2

b在开始使用 覆​​盖其字符之前,您需要分配空间b[n]。所以b.resize(...)需要。否则,您需要使用 . 将每个字符添加到末尾b += a[i];

std::string也不是空终止,所以请不要检查\0,使用他们的size()

考虑一下:

int main()
{
    int i;

    string a, b; // these are both empty

    std::cout << "a.size() = " << a.size() << '\n';
    std::cout << "b.size() = " << b.size() << '\n';

    cin >> a; // now a contains something

    std::cout << "a.size() = " << a.size() << '\n';
    std::cout << "b.size() = " << b.size() << '\n';

    // for(i = 0; a[i] != '\0'; i++) // no don't test for null
    // {
    //  b[i] = a[i]; // no b has no spaces
    // }

    for(std::size_t i = 0; i < a.size(); ++i)
        b += a[i]; // increases b's size by one each time

    std::cout << "b.size() = " << b.size() << '\n';

    cout << b;
}

要回答其他问题:

a)它是一个以std::stringnull 结尾的内部实现细节。事实是空终止字符超出了公共接口的合法范围,从技术上讲,访问它是“未定义的行为”。找到结尾的正确方法std::string是使用它的size()函数或它的end()迭代器。

b)如果在字符串末尾之外分配了内存,那纯属运气。即使那里有内存,它也不是字符串的一部分,并且不会在像.a = b;

c)这是完全未定义的行为。可能std::cout << b;会查看size()is 的字符串zero并决定不打印任何内容,因为size()is zero(参见我的示例)。然而c_str()只是简单地返回字符串开头的内存地址。仅从内存地址std::cout无法判断它来自的字符串应该有多大。因此,它只会继续打印字符,直到找到空值。如果它打印出您希望的内容,那是纯粹的运气。

于 2016-09-28T13:59:28.147 回答
1

b是空的。对于 的任何值,分配 tob[i]具有未定义的行为i

a[i]!='\0'仅当您的编译器支持 C++11 或更高版本时,条件才有效。在 C++11 之前str[str.size()]有未定义的行为。


您可以通过首先调整大小来解决第一个问题b。如果您有 C++11 支持,则基于范围的循环会简单得多。如果您没有 C++11,那么以下是一个有效的选项:

b.resize(a.size());
for(i=0; i < a.size(); i++)

不过,编写一个循环来复制字符串有点傻。您可以简单地使用赋值:

b = a;

a)我不知道cpp字符串何时为空终止,何时不是,但在这种情况下,初始化后的a字符串为空终止,因为循环结束并且它在字符串a的最后一个字符之后结束,因为从出来循环并cout<<a[i];打印 a 的最后一个字符。

(假设您没有在启用 C++11 的情况下进行编译)这恰好是您在操作系统上使用编译器编译并在特定时间在 cpu 上运行程序时观察到的情况。如果任何因素发生变化,则无法保证行为是相同的。

b)在循环中,在我包含cout<<b[i];它的赋值之后,它确实打印出我们期望刚刚分配给的值b[i]。确实b[i]存在一些奇怪的原因

这并不意味着b[1]“存在”。行为未定义。

c)在for循环之外,在程序结束时,当我cout<<b[2];打印字符串的第三个字符时。如果我这样做cout<<b.c_str();,它会打印出整个字符串。只有当我这样做时cout<< b;,才会打印任何内容。为什么是这样?

这是因为行为未定义。

于 2016-09-28T13:51:55.327 回答