0

I wrote a little piece of code that is supposed to take a char array and make it look like the computer is typing the text out. Simple enough, right? But when I ran it, Terminal told me this:

*** 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)

I am new to C++ (I have a C background), and I have no idea what a stack smash or backtrace is. if you can help me, it will help a lot! Here is the code:

#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];
    }

}
DarkSun
  • 41
  • 2
  • 6
  • You are looking for a \n that is not there; strings are null-terminated. – antlersoft Dec 26 '14 at 20:52
  • SO if I set letters[27] = '\n', will that fix it? – DarkSun Dec 26 '14 at 20:52
  • Smashing the stack is when you read or write beyond the stack, and as you (should) know all local variables on modern C and C++ compilers are stored on the stack. If you ever used a debugger then you should know what a backtrace is, it's the function call stack. – Some programmer dude Dec 26 '14 at 20:54
  • @DarkSun If you set letters[27] = '\n', you will be writing past the end of the array – antlersoft Dec 26 '14 at 20:54
  • @DarkSun No, doing `letters[27] = '\n';` will write *beyond* the array, thereby "smashing" the stack. – Some programmer dude Dec 26 '14 at 20:54
  • could someone give me an example of working code for this? – DarkSun Dec 26 '14 at 20:59
  • `for(; *letters; ++letters) { usleep(wait); cout << *letters; }`. there ya go. And I would advise declaring the function `void type(const char letters[])`. You make no modifications to `letters[]` and have no reason to pass it non-const. – WhozCraig Dec 26 '14 at 21:29

5 Answers5

2

Strings in C++ are expected to be null terminated, i.e. their last character is a \0. In your code, the loop doesn't terminate at the end of the string letters because you're looking for the \n char which doesn't actually exist in that string.

First Fix

Terminate the string with the character you're looking for in your loop:

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

Second Fix

Terminate the loop by looking for the end-of-string character \0 that actually does exist:

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

Third Fix

Use a proper string length check as the loop termination criterion:

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

Or any combination of those three.

In general, it's never a good idea to declare a string as a fixed-size array, so use const char *letters = "..."; instead.

Jens
  • 8,423
  • 9
  • 58
  • 78
1

You are in an infinite loop

You are looking for '\n' which doesn't exist. You should look for the null character \0

for(int i = 0; letters[i] != '\0'; ++i){
    usleep(wait)
    cout << letters[i];
}
Jérôme
  • 8,016
  • 4
  • 29
  • 35
  • Except now the length of the array should be 28 – antlersoft Dec 26 '14 at 20:55
  • ... and the added hard-terminator is useless. there is already one present at the end of that string. The advice to look for the null-char rather than the `'\n'` is correct given the original input string. – WhozCraig Dec 26 '14 at 21:26
0

One of two solutions you can use here.

1) You can include \n in the loop, but that would have to be in the array itself and the array size would have to be increased by 1 to letters[28].

2) You keep the array as you declared it, but the for loop would be

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

The second solution, you wouldn't have to change the array size and the loop would continue until the end of the array

user2649644
  • 124
  • 1
  • 2
  • 12
0

In addition to the end-of-string problems noted by other commenters, your code probably won't give you the effect you want because you're using cout. That output stream buffers things until you send a newline anyway, so your "typing" will appear all at once when the final newline is printed.

You can get the one-character-at-a-time effect by printing to cerr or by flushing cout after every character is supposed to be printed.

Dave M.
  • 1,496
  • 1
  • 12
  • 30
0

You should use std::string if you are using C++. This will keep track of the length for you, but you can also use iterators.

#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;
    }
}

Although, if you wish, you can still access the characters of the string by index, e.g.:

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];
    }
}
dreamlax
  • 93,976
  • 29
  • 161
  • 209