2

I need to have a dynamic array of strings, so that I can expand it at any time. So I wanted to do it with malloc/realloc. But every time I try to run it I get segmentation fault with following errors from valgrind:

==13709== Use of uninitialised value of size 8
==13709==    at 0x4EEED9B: std::string::assign(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==13709==    by 0x400953: main (test.cpp:12)
==13709== 
==13709== Invalid read of size 8
==13709==    at 0x4EEED9B: std::string::assign(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17)
==13709==    by 0x400953: main (test.cpp:12)

My code looks like that:

int main()
{
    string* arr;
    arr=(string*) malloc(5*sizeof(string));
    arr[0]="test1";
    arr[1]="test2";
    cout << arr[0] << arr[1] << endl;
}

I know about char**, but it is kind of a pain to use, so I wanted to use strings. Any hint on how to make it work?

14
  • 7
    Why don't you just make a std::vector< std::string >? Commented Jul 19, 2014 at 14:45
  • 5
    Just use vector<string> and save yourself a whole lot of grief. Commented Jul 19, 2014 at 14:46
  • 1
    malloc is almost never used in C++, this reason being one of them. As a direct replacement, new works with non-POD types (like std::string) and a vector works even better. I'm not sure what kind of memory you're saving by not using a vector. Commented Jul 19, 2014 at 14:48
  • 1
    @Testie Using a vector costs you roughly the space needed for three pointers; which is pretty much the minimum you need for a performant dynamic array. You're not paying for anything you're not using. Commented Jul 19, 2014 at 14:51
  • 1
    @Testle No, it doesn't. You would have to allocate a new array, copy everything over, then deallocate the old array. We avoid this kind of manual memory management in C++ by letting classes manage it for us (like std::vector). Commented Jul 19, 2014 at 14:52

2 Answers 2

6

To summarise the comments:

malloc(5*sizeof(string)) will only allocate memory large enough to fit 5 std::strings. Class type objects (like std::string) need to be initialised after the memory has been allocated, which means constructing the object, before the object can be used. Attempting to use the uninitialised memory as though it were a valid initialised std::string object will give you undefined behaviour.

In C++, dynamic memory allocation is performed using the new operator. That is, your line would be written as arr = new string[5]; instead. This allocates space for 5 std::strings and also constructs all of them. They are then ready to use.

However, in C++ we try to avoid performing dynamic memory allocation ourselves because it leads to bugs and unsafe code. Instead, we use classes (often those provided by the standard library) that encapsulate this behaviour. In this case, you are much better off using a std::vector<std::string> which represents a container of std::strings that can easily be added to, removed from, resized, etc. without ever having the dangers of manual dynamic allocation.

To demonstrate how much better this is, here is how I would write your code:

int main() {
  std::vector<std::string> arr = {"test1", "test2"};
  std::cout << arr[0] << arr[1] << std::endl;
}
Sign up to request clarification or add additional context in comments.

Comments

1

I need to have a dynamic array of strings, so that I can expand it at any time. So I wanted to do it with malloc/realloc.
[...]
Any hint on how to make it work?

Just use std::vector<std::string>.

In this way, all the memory management happens "under the hood" automatically.
It will make your code much easier to read and to maintain.

In modern C++ (unless there is a strong reason for not doing that), consider using convenient STL container classes, like std::vector, and string classes, like std::string, instead of raw C-like pointers.

If you want to add more strings to your vector, just call std::vector's push_back() method, and new room will be made for the new string, and the vector updated correctly.

And vector's and string's destructors will automatically release memory for you.

It's a big win over raw malloc/free (or new[]/delete[]).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.