Hello I am attempting to learn C , I am trying to use malloc to create an array of vectors but I cannot seem to get it to work. The vectors contain strings. I have no issue making arrays with integers but using vectors has caused me some issues. I am having the same issues with using realloc.
I am trying this, what am I doing wrong?
int buffer_size = 3;
int buffer_count= 0;
vector * words = (string *) malloc(buffer_size * sizeof(string));
//As array of vectors fills up I will add to the buffer count
if(buffer_count => buffer_size){
words = (string*) realloc(words,buffer_size * sizeof(string));
}
Like I said, I must have something wrong with something in the malloc or realloc function, everything I try gives a variety of errors such as "Use of class template 'vector' requires template arguments.
Thank you for any help.
CodePudding user response:
std::vector
and other STL containers are meant to remove the complexities caused by using pointers and dynamic memory allocation, such as memory leaks, undefined behavior invoked by accessing data out-of-bound, etc.
std::vector
is dynamic in itself. The more you emplace_back
or push_back
, the more it grows. If you want a vector that contains strings of variable length, why not declare it like this:
std::vector<String> words {"Hello", "World"};
Similarly, you can create multidimensional vectors:
std::vector<std::vector<Type>> doubleContainer {};
CodePudding user response:
std::vector
is a template class, but you are trying to use it without specifying any values for its template arguments. That is why you are getting errors.
However, you can't assign a string*
pointer to a vector*
pointer, like you are trying to do. Your words
variable needs to be declared as string*
instead. At least then the code will compile.
However, the code won't behave correctly at runtime, because the malloc()
/realloc()
functions are from the C runtime library, but std::string
is a C non-trivial class that requires construction, and the C functions do not call class constructors. So, you would have to use placement-new
to solve that problem (and forget about using realloc()
, as there is no safe way to realloc memory that is also placement-new'ed), eg:
string *words = (string*) malloc(buffer_size * sizeof(string));
for (int i = 0; i < buffer_size; i) {
new(&words[i]) string;
}
...
if (buffer_count >= buffer_size) {
int new_buffer_size = buffer_size * 2;
string *new_words = (string*) malloc(new_buffer_size * sizeof(string));
for (int i = 0; i < buffer_size; i) {
new(&new_words[i]) string(words[i]);
}
for (int i = buffer_size; i < new_buffer_size; i) {
new(&new_words[i]) string();
}
for (int i = 0; i < buffer_size; i) {
words[i].~string();
}
free(words);
words = new_words;
buffer_size = new_buffer_size;
}
...
for (int i = 0; i < buffer_size; i) {
words[i].~string();
}
free(words);
In which case, it is better/safer to use new[]
/delete[]
instead:
string * words = new string[buffer_size];
...
if (buffer_count >= buffer_size) {
int new_buffer_size = buffer_size * 2;
string *new_words = new string[new_buffer_size];
for (int i = 0; i < buffer_size; i) {
new_words[i] = words[i];
}
delete[] words;
words = new_words;
buffer_size = new_buffer_size;
}
...
delete[] words;
Or, just use std::vector
properly and let it handle all of the dynamic memory management for you:
vector<string> words;
CodePudding user response:
You're using malloc to allocate memory for a vector of strings, but malloc only allocates raw memory, which means you can't directly use it to create an array of vectors. Instead, you need to use the new
keyword.
vector<string> *words = new vector<string>[buffer_size];
You're trying to cast the return value of malloc to a vector*, but this is not allowed. Instead, you can use the vector class's reserve
method to allocate the necessary amount of memory for the vectors in the array, and then use the emplace_back
method to add new elements to the array.
if (buffer_count >= buffer_size) {
words->reserve(buffer_size * 2);
words->emplace_back();
}
Hope this helps!
CodePudding user response:
cout<<sizeof(string)<<endl; have a look