使用字符串而不是 char 数组时程序崩溃

Posted

技术标签:

【中文标题】使用字符串而不是 char 数组时程序崩溃【英文标题】:Program crashes when using string instead of char array 【发布时间】:2017-03-19 19:00:29 【问题描述】:

我正在尝试编写一个程序来输入密码等文本(显示“*”而不是用户输入的字符)。

问题是,当我使用 char 数组存储密码时,程序运行良好,但是当我使用字符串类变量实现相同目的时,我的程序在显示字符串时崩溃。

代码如下:

 // *********THIS CODE WORKS FINE***********

#include <iostream>
#include<string>
#include<conio.h>

int main()
 
    using namespace std;

    int i=0;
    cout<<"Enter a password,press ENTER to finish writing"<<endl;
    char passw[20];

    passw[i]=getch();

    while(passw[i]!=13)
    
        i++;
        cout<<"*";
        passw[i]=getch();
    
    passw[i+1]='\0';
    cout<<"\nPassword is "<<passw;

    return 0;

现在当我将char passw[20] 替换为string passw 时:

//**********THIS CODE CRASHES!!*********

#include <iostream>
#include<string>
#include<conio.h>

int main()
 
    using namespace std;
    int i=0;
    cout<<"Enter a password,press ENTER to finish writing"<<endl;
    string passw;

    passw=getch();

    while(passw[i]!=13)
    
        i++;
        cout<<"*";
        passw[i]=getch();
    

    cout<<"\nPassword is "<<passw;

    return 0;

谁能解释为什么会这样?

刚从字符串开始,我对字符串了解的太多了 :)

【问题讨论】:

std::string 不是无限的字符数组。在您可以访问 i th 元素之前,您必须将它放在那里(passw[i]=getch() 不会放在那里)。 我该怎么做? 试试std::string::append passw += getch() 使用追加来填充字符串。您仍然可以使用 getch() 来获取字符。然后将其附加到字符串的末尾并继续。 【参考方案1】:

在字符串中你可以使用字符串连接。 您可以保存您的 char 并将其添加到您的字符串变量中。

char ch;
string pass;
ch=getch();
pass=pass+ch;

【讨论】:

【参考方案2】:

您正在访问的位置 (passw[i]) 尚不存在于您的 std::string 中,并且您没有将其正确存储到字符串中。你应该使用passwd.push_back(char)的方法来存储它。

查看参考:http://en.cppreference.com/w/cpp/string/basic_string/push_back

【讨论】:

我只是想指出string::append 没有简单字符的重载。 @ErvinSzilagyi 有,您应该指定要附加的字符数 - 例如 1 (en.cppreference.com/w/cpp/string/basic_string/append) @madduci 是的,但sting::append(char)string::append(size_type count, char c) 是完全不同的东西。【参考方案3】:

string 与 char 数组的工作方式不同。您可能知道char passw[20] 在您的第一个示例中创建了一个最多可容纳20 个chars 的数组。然后可以使用operator[] 毫无问题地访问这些内容。 string 与基本数组不同,它是一个动态 数据结构,这意味着它会随着您的程序运行而随时间增长和缩小。它的内容也可以使用operator[] 访问,但是,这不会附加到字符串中,它只能用于更改已经存在的内容。

请务必注意,在 c++ 中,并非所有操作都会执行所谓的边界检查。在您的第二个示例中,您访问字符串的第 i 个字符并将一个字符写入该位置。但是,例如,如果您尝试写入一个只有 5 个空格的字符串的第 10 个字符,会发生什么?当通过operator[] 执行此操作时,程序将写入第 10 个字符所在的任何位置,即使该部分内存 实际上不是字符串的一部分。任何东西都可能存在并且会被该操作覆盖。正如您可能想象的那样,这根本是不可取的,并且可能会导致以后出现各种问题。如果幸运的话,您的程序会在写入时立即崩溃。但是,您的情况并非如此,这不是一件好事。越界写入可能会导致堆损坏(堆是内存的某个部分),这通常会在某个时间点导致崩溃。

当且仅当您知道要访问的任何索引都在字符串大小范围内时,才可以使用 operator[] 更改 strings 字符。否则,您需要使用appropriate member function 附加到字符串。如有必要,这些将扩大字符串。

在使用动态内存时,您始终需要注意您正在访问其中的哪些部分(例如,在您的第一个示例中,如果您的密码太长,您也会写出越界)。

【讨论】:

有没有办法通过string 提前知道passw的位置? 你不需要知道任何位置,你需要知道它的大小(或者更具体地说,它的capacity)

以上是关于使用字符串而不是 char 数组时程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章

可以/为啥在返回类型中使用 char * 而不是 const char * 会导致崩溃?

删除动态数组时崩溃

NSString 到 C 风格的 char 数组在第二次调用 drawRect 时崩溃

Rshiny CRUD 应用程序:使用选择输入而不是文本输入时用户输入崩溃

iOS:当应用程序因任何崩溃而退出时,是不是有任何委托方法

fgets() 多次使用时 C 程序崩溃