【问题标题】:Why allocating memory to a char pointer does not truncate the char sequence为什么将内存分配给 char 指针不会截断 char 序列
【发布时间】:2020-03-04 00:35:51
【问题描述】:

我不明白为什么char *ptr = new char[7] 不会截断大于 7 个字符的数据输入。还有为什么八位 char c[7] 会让我输入超过 6 个字符(但在将其归因于超过 6 个字符的文字值时会出错)。

使用malloc function 对我来说似乎有点困难,这就是我不想使用它的原因。我宁愿暂时不要使用它。

char qs[7] = "1234567"; //error too many

char qs2[7];
cin >> qs2;             //input 123456789
cout << qs2;            //out same as input, expecting 123456

char *qs3 = new char[7];
cin >> qs3;             //input 123456789
cout << qs3;            //out same as input, expecting 123456

【问题讨论】:

  • 这是未定义的行为,并不能保证任何特定的结果。它可能会打印123456789,它可能会打印123456,它可能会打印其他东西,它可能会挂起、崩溃或做一些完全不同的事情。它很可能会通过覆盖其他东西(例如堆栈指针)来破坏您的堆栈,这可能会或可能不会使程序崩溃。如果我在 Visual Studio 中以 123456789 为输入运行您的程序,它会崩溃。
  • 我怎么能确定从控制台按下enter 后,我的值将严格为 6 个字符长?
  • 读入变量until 将达到counter 设置为6?
  • @MarcStröbel 但它仍然让我输入多个字符
  • "我怎么能确定从控制台按回车后,我的值将严格为 6 个字符长?"你不能,这就是为什么char qs2[7]; cin &gt;&gt; qs2 是个坏主意

标签: c++ string char undefined-behavior c-strings


【解决方案1】:

目前,输入流只接受一个指针作为参数。因此它无法知道它填充的缓冲区的大小。因此它不知道它是否应该截断。读取比缓冲区长的字符串会导致缓冲区溢出,程序的行为将不确定。不要这样做。

从 C++20 开始,数组操作数通过引用传递,并且该操作确实知道大小并将截断输入。但是,这在 qs3 的情况下无济于事,因为它只是一个指针而不是数组。

相反,您可以使用:

std::cin.get(qs3, 6);
qs3[6] = '\0';

确保读取的字符数不超过缓冲区的容量。

或者如果你不想截断输入,那么你可以读入std::string


用 malloc 函数做这件事对我来说似乎有点困难,这就是为什么我不想使用它。

很好。它不会解决你的问题,也没有必要使用它,使用它也没有任何好处。

【讨论】:

    【解决方案2】:

    两个代码sn-ps

    char qs2[7];
    cin >> qs2;             //input 123456789
    cout << qs2;            //out same as input, expecting 123456
    
    char *qs3 = new char[7];
    cin >> qs3;             //input 123456789
    cout << qs3;            //out same as input, expecting 123456
    

    有未定义的行为。超出分配数组的内存被覆盖。后果可以是任何类型的。

    考虑以下演示程序。

    #include <iostream>
    
    int main() 
    {
        char gs1[7] = "123456";
        char gs2[7];
        char gs3[7] = "ABCDEF";
    
        std::cin >> gs2;
    
        std::cout << '\n';
    
        std::cout << gs1 << '\n';
        std::cout << gs2 << '\n';
        std::cout << gs3 << '\n';
    
        return 0;
    }
    

    如果进入

    1234567
    

    那么程序输出可能看起来像

    123456
    1234567
    

    如您所见,字符串"ABCDEF" 未输出。这是在此语句之后附加到数组gs2 的终止零'\0' 的结果

        std::cin >> gs2;
    

    覆盖数组gs3 的第一个字符。现在它的内容看起来像

    { '\0', 'B', 'C', 'D', 'F', '\0' }
    

    因此,由于数组的第一个元素是终止零,因此在此语句中输出了空字符串

        std::cout << gs3 << '\n';
    

    【讨论】:

      【解决方案3】:

      C 字符串以零结尾,这意味着您应该始终分配大小字符串长度 + 1 的缓冲区。

      char qs[7] = "1234567"; //错误太多

      在静态分配的缓冲区中,编译器很明显你的缓冲区没有空间来终止零。这应该是 char qs[8]。

      在其他两个示例中,运算符将指向缓冲区的指针作为参数,它无法知道它有多大。它只是填充它直到输入结束。你会遇到典型的缓冲区溢出情况,你很幸运,那里没有什么重要的东西(在缓冲区边界之后)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-02-23
        • 2011-10-11
        • 2019-01-10
        • 2020-11-13
        • 1970-01-01
        • 1970-01-01
        • 2018-10-06
        • 2023-03-26
        相关资源
        最近更新 更多