0

I've been making exercises as functions and some interface for them. Currently I've made just one exercise which is to erase the first occurrence of line 'we' in some bigger line. There's single guy with same problem and similar conditions (strcpy causing Thread 1: signal SIGABRT), but I get the fault not when function strcpy is used, but after, when we return to switch-case construction, though this is must be connected.

#include <iostream>
using namespace std;

void task1_C() {
    const int N = 10;
    char S[N];
    char rem[3] = "we";
    cout << "Input your line (should consist of 10 characters): ";
    cin >> S;
    char *p = strstr(S, rem);
    if (p) {
        strcpy(p, p + strlen(rem));
        cout << S << endl;
    }
}

void task1_Cpp() {

}

void task2_C() {

}

void task2_Cpp() {

}

void task3_C() {

}

void task3_Cpp() {

}

void task4_Cpp() {

}

void task5_Cpp() {

}

int main(){
    int input;
    cout << "Input 1-5 for C++ functions, 11-13 for C functions." << endl;
    cin >> input;
    switch(input){
        case 1: task1_Cpp(); break;
        case 2: task2_Cpp(); break;
        case 3: task3_Cpp(); break;
        case 4: task4_Cpp(); break;
        case 5: task5_Cpp(); break;
        case 11: task1_C(); break;
        case 12: task2_C(); break;
        case 13: task3_C(); break;
    }
    return 0;
}

Output:

Input 1-5 for C++ functions, 11-13 for C functions.
11
Input your line (should consist of 10 characters): sweweratwe
sweratwe
Program ended with exit code: 9
Martian
  • 227
  • 1
  • 15
  • 6
    Buffer of size `10` can hold at most `9` characters. – Yksisarvinen Mar 17 '20 at 13:57
  • Yes, it's connected. A bug on a particular line of code does not mean that it will always crash there. C++ does not work this way. The program might continue to run for a little while, before finally crashing. – Sam Varshavchik Mar 17 '20 at 14:02
  • It could also be a problem of overlapping memory (strcpy should be used with distinct buffers AFAIK... otherwise you should use memmove) – marco6 Mar 17 '20 at 14:03

1 Answers1

3

Your program has undefined behavior with the shown input already at the line

cin >> S;

The array S has length 10 and the input consists of 10 characters, but the char* overload of >> requires an additional character to store the null terminator of the string. That means the array must have at least size 11. That not being the case, your program accesses the array out-of-bounds and causes undefined behavior, which means the program may or may not crash or do whatever.

You should not use char arrays to store strings in C++. You should use std::string instead. In C you should not use cin >> (because it doesn't have it) and you should learn/teach only either C or C++, not both mixed. You wouldn't use strcpy and strstr in C++. The style considered good in the two languages is completely different.

The char* overload of >> will even be removed from the language in C++20. Instead there will be an overload taking a char[N] array by-reference, which then will stop reading after N-1 characters to avoid buffer overflows like this. In your case here using S directly, which is an array, your program would skip reading the last character because it would go out-of-bounds of the array, in C++20, but at least this direct source of undefined behavior will not be present anymore.

Additionally strcpy has undefined behavior if source and destination overlap. Instead use std::copy in C++ or memmove in C.

walnut
  • 21,629
  • 4
  • 23
  • 59
  • Thank you! What can I use instead of cin if I need C style? I was searching it and I don't understand why inputting a line is such a problem. There's a conio library, but it's outdated and doesn't work for mac. There's also ncourses, but I had some problems with it. I really don't understand why there's no simple solution for such things. In the past coding was really this complicated? – Martian Mar 17 '20 at 15:16
  • No, in C land you use `scanf` and other related functions to get input from stdin. – JohnFilleau Mar 17 '20 at 15:22
  • @АлексейСавицкий Taking inputs of arbitrary length is non-trivial in pure C and other low-level languages, yes. There is though e.g. `getline` which is a POSIX function. For input of statically bounded maximum size, you can use `scanf` (with correct specifier) or `fgets`. See e.g. [this question](https://stackoverflow.com/questions/314401/how-to-read-a-line-from-the-console-in-c), [this one](https://stackoverflow.com/questions/3501338/c-read-file-line-by-line), or [this one](https://stackoverflow.com/questions/16870485/how-can-i-read-an-input-string-of-unknown-length) and many more. – walnut Mar 17 '20 at 15:26