【问题标题】:Stack Smashing/BackTrace堆栈粉碎/回溯
【发布时间】:2014-12-26 20:47:44
【问题描述】:

我写了一小段代码,它应该接受一个 char 数组,让它看起来像是计算机正在输入文本。很简单,对吧?但是当我运行它时,终端告诉我:

*** stack smashing detected ***: ./TYPE terminated
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(__fortify_fail+0x45)[0xb759aeb5]
/lib/i386-linux-gnu/libc.so.6(+0x104e6a)[0xb759ae6a]
./TYPE[0x80486a9]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb74af4d3]
./TYPE[0x8048591]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:01 1580147    /home/jeremy/Desktop/programming/cpp/Jumping into C++/TYPE
08049000-0804a000 r--p 00000000 08:01 1580147    /home/jeremy/Desktop/programming/cpp/Jumping into C++/TYPE
0804a000-0804b000 rw-p 00001000 08:01 1580147    /home/jeremy/Desktop/programming/cpp/Jumping into C++/TYPE
08a30000-08a51000 rw-p 00000000 00:00 0          [heap]
b7449000-b744b000 rw-p 00000000 00:00 0 
b744b000-b7467000 r-xp 00000000 08:01 4195157    /lib/i386-linux-gnu/libgcc_s.so.1
b7467000-b7468000 r--p 0001b000 08:01 4195157    /lib/i386-linux-gnu/libgcc_s.so.1
b7468000-b7469000 rw-p 0001c000 08:01 4195157    /lib/i386-linux-gnu/libgcc_s.so.1
b7469000-b7493000 r-xp 00000000 08:01 4198259    /lib/i386-linux-gnu/libm-2.15.so
b7493000-b7494000 r--p 00029000 08:01 4198259    /lib/i386-linux-gnu/libm-2.15.so
b7494000-b7495000 rw-p 0002a000 08:01 4198259    /lib/i386-linux-gnu/libm-2.15.so
b7495000-b7496000 rw-p 00000000 00:00 0 
b7496000-b763a000 r-xp 00000000 08:01 4198264    /lib/i386-linux-gnu/libc-2.15.so
b763a000-b763c000 r--p 001a4000 08:01 4198264    /lib/i386-linux-gnu/libc-2.15.so
b763c000-b763d000 rw-p 001a6000 08:01 4198264    /lib/i386-linux-gnu/libc-2.15.so
b763d000-b7640000 rw-p 00000000 00:00 0 
b7640000-b7718000 r-xp 00000000 08:01 8786914    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7718000-b7719000 ---p 000d8000 08:01 8786914    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7719000-b771d000 r--p 000d8000 08:01 8786914    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b771d000-b771e000 rw-p 000dc000 08:01 8786914    /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b771e000-b7725000 rw-p 00000000 00:00 0 
b773e000-b7742000 rw-p 00000000 00:00 0 
b7742000-b7743000 r-xp 00000000 00:00 0          [vdso]
b7743000-b7763000 r-xp 00000000 08:01 4198254    /lib/i386-linux-gnu/ld-2.15.so
b7763000-b7764000 r--p 0001f000 08:01 4198254    /lib/i386-linux-gnu/ld-2.15.so
b7764000-b7765000 rw-p 00020000 08:01 4198254    /lib/i386-linux-gnu/ld-2.15.so
bffc0000-bffe1000 rw-p 00000000 00:00 0          [stack]
abcdefghijklmnopqrstuvwxyzAborted (core dumped)

我是 C++ 新手(我有 C 背景),我不知道堆栈粉碎或回溯是什么。如果你能帮助我,那将有很大帮助!代码如下:

#include <iostream>
#include <ctime>
#include <cstdlib>
#include <unistd.h>

using namespace std;

void type(char letters[]);

int main(){

    char letters[27] = "abcdefghijklmnopqrstuvwxyz";
    system("clear");
    type(letters);

    return 0;
}

void type(char letters[]){

    unsigned int wait = 30000000;

    system("clear");
    for(int i = 0; letters[i] != '\n'; i++){
        usleep(wait)
        cout << letters[i];
    }

}

【问题讨论】:

  • 你正在寻找一个不存在的\n;字符串以 null 结尾。
  • 所以如果我设置 letters[27] = '\n',会解决它吗?
  • 粉碎堆栈是指您在堆栈之外读取或写入,并且您(应该)知道现代 C 和 C++ 编译器上的所有局部变量都存储在堆栈中。如果您曾经使用过调试器,那么您应该知道什么是回溯,它是函数调用堆栈。
  • @DarkSun 如果你设置了 letters[27] = '\n',你会写到数组的末尾
  • @DarkSun 不,letters[27] = '\n'; 将写入 数组,从而“粉碎”堆栈。

标签: c++ c backtrace stack-smash


【解决方案1】:

C++ 中的字符串应该以空值结尾,即它们的最后一个字符是 \0。在您的代码中,循环不会在字符串 letters 的末尾终止,因为您正在寻找该字符串中实际上不存在的 \n 字符。

第一次修复

用您在循环中寻找的字符终止字符串:

char letters[28] = "abcdefghijklmnopqrstuvwxyz\n";

第二次修复

通过查找确实存在的字符串结尾字符\0 来终止循环:

for(int i = 0; letters[i] != '\0'; i++)

第三次修复

使用正确的string length 检查作为循环终止标准:

int len = strlen(letters);
for(int i = 0; i < len; i++)

或者这三者的任意组合。

一般来说,将字符串声明为固定大小的数组绝不是一个好主意,因此请改用const char *letters = "...";

【讨论】:

    【解决方案2】:

    你在一个无限循环中

    您正在寻找不存在的'\n'。你应该寻找空字符\0

    for(int i = 0; letters[i] != '\0'; ++i){
        usleep(wait)
        cout << letters[i];
    }
    

    【讨论】:

    • 除了现在数组的长度应该是28
    • ... 并且添加的硬终止符是无用的。该字符串的末尾已经存在一个。考虑到原始输入字符串,寻找空字符而不是 '\n' 的建议是正确的。
    【解决方案3】:

    您可以在此处使用两种解决方案之一。

    1) 您可以在循环中包含 \n,但这必须在数组本身中,并且数组大小必须增加 1 到字母[28]。

    2) 你保留声明它的数组,但 for 循环将是

    for(int i = 0; letters[i]; i++){
       cout << letters[i];
    }
    

    第二种解决方案,您不必更改数组大小,循环将一直持续到数组末尾

    【讨论】:

      【解决方案4】:

      除了其他评论者指出的字符串结尾问题之外,您的代码可能不会给您想要的效果,因为您正在使用 cout。该输出流会缓冲内容,直到您发送换行符为止,因此在打印最终换行符时,您的“打字”将立即出现。

      您可以通过打印到 cerr 或在应该打印每个字符后刷新 cout 来获得一次一个字符的效果。

      【讨论】:

        【解决方案5】:

        如果你使用 C++,你应该使用std::string。这将为您跟踪长度,但您也可以使用迭代器。

        #include <iostream>
        #include <ctime>
        #include <cstdlib>
        #include <unistd.h>
        
        using namespace std;
        
        void type(const string &);
        
        int main(){
        
            string letters = "abcdefghijklmnopqrstuvwxyz";
            system("clear");
            type(letters);
        
            return 0;
        }
        
        void type(const string &letters)
        {
            unsigned int wait = 30000000;
        
            system("clear");
            for(string::const_iterator it = letters.begin(); it != letters.end(); it++)
            {
                usleep(wait)
                cout << *it;
            }
        }
        

        虽然,如果你愿意,你仍然可以通过索引访问字符串的字符,例如:

        void type(const string &letters)
        {
            unsigned int wait = 30000000;
        
            system("clear");
            for(size_t i = 0; i < letters.length(); i++)
            {
                usleep(wait)
                cout << letters[i];
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-11-18
          • 1970-01-01
          • 1970-01-01
          • 2014-06-26
          • 1970-01-01
          • 1970-01-01
          • 2021-04-29
          相关资源
          最近更新 更多