-1

On my computer (Win10, WSL 1, Ubuntu 20.04)

This code would compile and run correctly,

#include <iostream>
#include <cstring>
#include <sstream>
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    char *test[30];
    string a;
    cin >> a;

    // stringstream ss;

    strcpy(test[0], a.c_str());
    cout << test[0] << endl;
}

Input: "abc"

Output: "abc"

But this code would encounter a segmentation default:

#include <iostream>
#include <cstring>
#include <sstream>
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    char *test[30];
    string a;
    cin >> a;

    stringstream ss;

    strcpy(test[0], a.c_str());
    cout << test[0] << endl;
}

Input: "abc"

Output: Segmentation fault (core dumped)

Dharman
  • 30,962
  • 25
  • 85
  • 135
Peter Qiu
  • 103
  • 1
  • 6

1 Answers1

2

char *test[30] defines an array of 30 pointers to char. test[0] is not initialized before being used in strcpy. The resulting behavior is not defined by the C++ standard.

You must provide memory for the copy of the string and assign test[0] to point to that memory.

Any effects due to the presence or absence of stringstream ss; are merely incidental; it may have affected how the program behaved when test[0] was used without being initialized, but only by happenstance of how things were laid out in memory.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Thanks! But why if I comment the `stringstream` it would work? – Peter Qiu Sep 23 '20 at 20:13
  • And I should `char** test = new char *[30]`? – Peter Qiu Sep 23 '20 at 20:14
  • 2
    @PeterQiu It doesn't work if you comment the `stringstream` for precisely the reason this answer explains. Neither result should be described as "working" since the behavior is not defined. – David Schwartz Sep 23 '20 at 20:17
  • @PeterQiu: `char** test = new char *[30]` allocates memory for 30 pointers to `char` and assigns its address to `test`. It does not allocate memory for characters and does not assign an address to `test[0]`. – Eric Postpischil Sep 23 '20 at 20:17
  • @peter "And I should char** test = new char *[30]" - ehh, no, that looks like a horrible idea. Why not use a `std::string` ? – Jesper Juhl Sep 23 '20 at 20:17
  • @Jesper Because I have to call a function called `execvp()` that takes `char *const argv[]` as argument. – Peter Qiu Sep 23 '20 at 20:21
  • @Eric So do I need to `char**test = new char*[30]` and then `for (auto i = 0; i < 30; i++) test[i] = new char[MAX_LEN]` ? – Peter Qiu Sep 23 '20 at 20:23
  • @PeterQiu: That should work, within the fixed limits of 30 strings each of the given maximum length. Generally, good programmers would write code that adapts more to the circumstances, using whatever number of strings of whatever lengths are needed. – Eric Postpischil Sep 23 '20 at 20:45
  • @PeterQiu "*I have to call a function called `execvp()`*" - I would suggest storing the input strings in a `std::vector` first, then store their `c_str()` pointers in a `std::vector`, and then pass that 2nd `vector` via its `data()` method to `execvp()`. See [How to pass a vector of strings to execv](https://stackoverflow.com/questions/5797837/) – Remy Lebeau Sep 23 '20 at 21:19