I am trying to resize a dynamically allocated string array; here's the code!
void resize_array() {
size_t newSize = hash_array_length + 100;
string* newArr = new string[newSize];
fill_n(hash_array,newSize,"0"); //fills arrays with zeros
memcpy( newArr, hash_array, hash_array_length * sizeof(string) );
hash_array_length = newSize;
delete [] hash_array;
hash_array = newArr;
}
unfortunately it isn't working and gives a segmentation fault. any idea why? this is basically a linear probing hash table where the element gets inserted wherever there is a 0 hence I use fill_n to fill the newly created array with 0's. any help please?
memcpy( newArr, hash_array, hash_array_length * sizeof(string) );
This line is extremely dangerous, std::string is not a plain old data type,
you can't make sure that memcpy could initialize it correctly, it may cause
undefined behavior, one of the most nasty behavior of c++(or programming).
Besides, there are a better and safer(in most of the times) solution to create
a dynamic string array in c++, just use vector
//create a dynamic string array with newSize and initialize them with "0"
//in your case, I don't think you need to initialize it with "0"
std::vector<std::string> newArr(newSize, "0");
if the hash_array has the same type as newArr(std::vector)
The way of copy it is very easy.
c++98
std::copy(hash_array.begin(), hash_array.end(), newArr.begin());
c++11
std::copy(std::begin(hash_array), std::end(hash_array), std::begin(newArr));
Better treat c++ as a new language, it has too many things are different from c.
Besides, there are a lot of decent free IDE, like code::blocks and QtCreator
devc++ is a almost dead project.
If you are new to c++, c++ primer 5 is a good book to start.
If string is actually an std::string (and probably even if it isn't) then this will crash. You are creating a new array of strings, copying the old string classes over the top, and then freeing the old strings. But if the string class contains internal pointers to allocated memory this will result in a double free because all you are doing is copying the internal pointers - not making new memory allocations.
Think about it like this; imagine you had the following class:
class foo
{
char* bar;
foo() { bar = malloc(100); }
~foo() { free(bar);
};
foo* ptr1 = new foo;
foo* ptr2 = new foo;
memcpy(ptr2, ptr1, sizeof(foo*));
delete ptr1;
At this point, ptr2->bar points to the same memory that ptr1->bar did, but ptr1 and the memory it held has been freed
The best solution would be to use a std::vector because this handles the resizing automatically and you don't need to worry about copying arrays at all. But if you want to persist with your current approach, you need to change the memcpy call to the following:
for (int i = 0; i < hash_array_length; ++i)
{
newArr[i] = hash_array[i];
}
Rather than just copying the memory this will call the class's copy constructor and make a proper copy of its contents.
I suspect the culprit is memcpy call. string is complicated type which manages the char array by pointers (just as you are doing right now). Normally copying string is done using assignment operator, which for string also copies its own array. But memcpy simply copies byte-per-byte the pointer, and delete[] also deletes the array managed by string. Now the other string uses deleted string array, which is BAAAD.
You can use std::copy instead of memcpy, or even better yet, use std::vector, which is remedy to most of your dynamic memory handling problems ever.
Related
I would like to perform a deep copy of a char**, but I have no idea how to allocate memory / copy this datatype. This is for a copy constructor in a class that contains a char**. For example, lets say I have this code:
char ** arr1 = new char*[20];
arr1[0] = (char*)"This is index 1";
arr1[1] = (char*)"This is index 2";
char ** arr2;
How do I deep copy the contents of arr1 into arr2? Any help is appreciated!
It’s for a programming assignment, and the teacher wants all strings
to be stored as char*,...
You can tell your teacher that std::string does store strings as char*. If he still doesnt like you to use std::string you should write your own wrapper, because working with bare char* is what you do when you write C, but not in C++. You should write a:
struct my_string {
char* data;
... constructor, operator[], etc...
};
You basically dont need to write more code than you already do, but you should put it in the right place (ie hide it behind a nice interface). You will immediately see the benefit of it when you eg consider ...
...so an array of strings has to be stored as an array of char*.
No. An array of strings is std::array<my_string> (or std::vector<my_string> if it is supposed to be dynamic). And if your teacher insists on not using std::vector, then you should do the same as you just did for strings for vectors (ie encapsulate all the dirty pointer and memory stuff in one place).
This seems more like a C question, but here is an example:
char **AllocateAndDeepCopy(char **arr1, int arr1size)
{
unsigned int i;
char **arr2;
/* Allocate string array */
arr2 = new char*[arr1size];
/* Iterate array elements */
for (i=0; i<arr1size; i++) {
/* Allocate string */
arr2[i] = new char[strlen(arr1[i])+1];
/* Copy contents */
strcpy(arr2[i], arr1[i]);
}
return arr2;
}
Later you have to deallocate arr2 this way:
void DeallocateArr2(char **arr2, int size)
{
for (int i=0; i<size; i++) {
delete arr2[i];
}
delete arr2;
}
I can only shake my head about the sorry state of C++ education. We have a looong way to go there. But since that’s apparently a given, what’s the best you can do?
To copy a C-style data structure like that you have know two things at the point of copy. Both are not inherently provided by a C-style array, so you’ll have to track them explicitely.
The capacity of arr1: 20. If that’s not a compile time constant you have to store it and pass it around. Since you want to implement a copy ctor that means storing the capacity in a non-static member variable of the object.
The number of used indexes in arr1: 2. Same as above. Alternatively make sure that all unused indexes are set to nullptr.
Now you can allocate an arr2 of the correct size and then allocate+memcpy all used indexes.
However, your program will go up in flames regardless, because arr1 and arr2 cannot be treated the same, even though they look identical. The used indexes of arr1 must never ever be deleted because they contain pointers to character literals: They were never newd and live in read-only memory. On the other hand you absolutely must delete the indexes of arr2, because they were newd.
If this brutal disregard of const is really required by the assignment I’d go one step further. I’d introduce another member variable, an array of booleans that tracks which indexes of the char array point to char literals and which were dynamically allocated. During copy you now have all the necessary information to either memcpy or simply set the pointer. Crazy? Definitely, but the whole assignment is, and that way the craziness is visible at least instead of hidden behind an innocent-looking C-style cast. Btw: those should be const_cast<char*> to make it clear what’s going on.
Just take a look at http://en.cppreference.com/w/cpp/algorithm/copy, the deep copy is made by
*d_first++ = *first++;
Consider the following code:
int *expand_array(int *old_arr,int array_length)
{
int *new_arr = new int[array_length +3];
for(int counter=0;counter<array_length;counter++)
new_arr[counter]=old_arr[counter];
delete[] old_arr;
return new_arr;
}
int main()
{
int *my_first_arr = new int[4];
int *my_expanded_arr=expand_array(my_first_arr,4);
delete[] my_expanded_arr;
}
will there be any memory leak here?
And to generalize the question,
if the pointer returned from a new statement is copied ,passed to a function or assigned to a different pointer, will the delete copied_pointer release the memory?
Your code is perfectly valid C++ and has no memory leaks. You can copy a pointer as often as you want to and deleteing any of those copies in any scope has the same effect.
It is still bad practice, however, and you shouldn't write code like this. Use of raw new and delete is too error prone and will make for poorly maintainable code. Instead, use RAII wrapper types like std::unique_ptr, std::shared_ptr or, in this case, std::vector.
The code in your question is basically equivalent to this.
int
main()
{
auto numbers = std::vector<int>(4);
numbers.resize(7);
}
Much simple, no?
Why do you believe that there would be a memory leak? Of course there wouldn't be.
But there is a different bug in this code. If the new array size is larger than the size of the existing old_arr, the code that copies the old array to the newly allocated int array is going to copy too much, run off past the end of the old array, resulting in undefined behavior; possibly a crash (old array size is 2 ints, array_length is 10, the for loop will attempt to copy 10 values from the old array which only has 2).
there is no problem here:
int *x;
x = (int *) malloc(0 * sizeof(int));
int value = 5;
x = (int *) realloc(x,(value)*sizeof(int));
But I cant do that for strings :\
I wanna do that for a y[] array, like this:
y[0]="hello"
y[1]="how are you"
how can I do that?
std::vector<std::string> y;
y.push_back("hello");
y.push_back("how are you");
Don't use malloc, or realloc, or free in C++. Don't use char* for purposes other than interop. Stay away from pointers until you actually need them (same for arrays).
You cannot use realloc on an array of std::string objects because realloc moves things around by bit copying and this is not allowed on general objects.
The standard class std::vector is a generic container for objects that moves and copies things around correctly (using copy constructors, assignments and similar methods) and that can change its size for example with the resize method. All the needed memory is allocated and freed automatically as needed.
With std::vector for example you can write code like...
std::vector<std::string> v; // An empty vector
v.resize(10); // Now size is 10 elements (all empty strings "")
v[0] = "Hello"; // First element is now the string "Hello"
v[1] = "world."; // Second element is now the string "world."
v.resize(2); // Now v.size() is 2
v.push_back("How's going"); // Now the size is 3 and third element is filled.
Do yourself a favor and pick up a good C++ book, reading it cover to cover. C++ is a powerful but complex language and if you try to learn it by experimenting with a compiler you're making a terrible mistake for many reasons.
What you're doing right now is not C++ ... you can do what you want with C-style strings, but you would need an array of pointers to type char that allow you to access the allocated memory for each string in the array. This can be done like so:
char* y[2];
y[0] = strdup("hello");
y[1] = strdup("how are you");
You also need to keep in mind that your y array now "owns" the pointers, so you must call free() on each pointer in the array in order to avoid any memory leaks should you decide to change the strings each pointer is pointing to.
If you want to go with an idiomatic C++ solution though, and not revert to C-style strings, then you should be using std::string and std::vector ... doing so avoids the issues with memory leaks as well as allocating and deallocating the memory associated with dynamically allocated C-strings.
You can actually do exactly what you need exactly like with integers:
typedef const char *c_string;
c_string *y;
y = (c_string *) malloc(0 * sizeof(c_string));
int value = 5;
y = (c_string *) realloc(y,(value)*sizeof(c_string));
y[0]="hello";
y[1]="how are you";
This won't work with non-const char * though, so this example is of limited usability.
I'm in the unfortunate position to write my own vector implementation (no, using a standard implementation isn't possible, very unfortunately). The one which is used by now uses raw bytes buffers and in-place construction and deconstruction of objects, but as a side-effect, I can't look into the actual elements. So I decided to do a variant implementation which uses internally true arrays.
While working on it I noticed that allocating the arrays would cause additional calls of construtor and destructor comapred to the raw buffer version. Is this overhead somehow avoidable without losing the array access? It would be nice to have it as fast as the raw buffer version, so it could be replaced.
I'd appreciate as well if someone knows a good implementation which I could base my own on, or the very least get some ideas from. The work is quite tricky after all. :)
Edit:
Some code to explain it better.
T* data = new T[4]; // Allocation of "num" elements
data[0] = T(1);
data[1] = T(2);
delete[] data;
Now for each element of the array the default constructor has been called, and then 2 assignment methods are called. So instead just 2 constructor calls we have 4 and later 4 destructor calls instead just 2.
as a side-effect, I can't look into the actual elements.
Why not?
void* buffer = ...
T* elements = static_cast<T*>(buffer);
std::cout << elements[0] << std::endl;
Using true arrays means constructors will be called. You'll need to go to raw byte buffers - but it's not too bad. Say you have a buffer:
void *buffer;
Change that to a T *:
T *buffer;
When allocating, treat it as a raw memory buffer:
buffer = (T *) malloc(sizeof(T) * nelems);
And call constructors as necessary:
new(&buffer[x]) T();
Your debugger should be able to look into elements of the buffer as with a true array. When it comes time to free the array, of course, it's your responsibility to free the elements of the array, then pass it to free():
for (int i = 0; i < nInUse; i++)
buffer[x].~T();
free((void*)buffer);
Note that I would not use new char[] and delete[] to allocate this array - I don't know if new char[] will give proper alignment, and in any case you'd need to be careful to cast back to char* before delete[]ing the array.
I find the following implementation quite interesting: C Array vs. C++ Vector
Besides the performance comparison, his vector implementation also includes push/pop operations on the vector.
The code also has an example that shows how to use the macros:
#include "kvec.h"
int main() {
kvec_t(int) array;
kv_init(array);
kv_push(int, array, 10); // append
kv_a(int, array, 20) = 5; // dynamic
kv_A(array, 20) = 4; // static
kv_destroy(array);
return 0;
}
void aFunction_2()
{
char* c = new char[10];
c = "abcefgh";
}
Questions:
Will the: c = "abdefgh" be stored in the new char[10]?
If the c = "abcdefgh" is another memory area should I dealloc it?
If I wanted to save info into the char[10] would I use a function like strcpy to put the info into the char[10]?
Yes that is a memory leak.
Yes, you would use strcpy to put a string into an allocated char array.
Since this is C++ code you would do neither one though. You would use std::string.
void aFunction_2()
{
char* c = new char[10]; //OK
c = "abcefgh"; //Error, use strcpy or preferably use std::string
}
1- Will the: c = "abdefgh" be
allocated inner the new char[10]?
no, you are changing the pointer from previously pointing to a memory location of 10 bytes to point to the new constant string causing a memory leak of ten bytes.
2- If the c = "abcdefgh" is another
memory area should I dealloc it?
no, it hasn't been allocated on heap, its in read-only memory
3- If I wanted to save info inner the
char[10] I would use a function like
strcpy to put the info inner the
char[10]?
not sure what you mean with 'inner' here. when you allocate using new the memory is allocated in the heap and in normal circumstances can be accessed from any part of your program if you provide the pointer to the memory block.
Your answer already has been answered multiple times, but I think all answers are missing one important bit (that you did not ask for excplicitly):
While you allocated memory for ten characters and then overwrote the only pointer you have referencing this area of memory, you are created a memory leak that you can not fix anymore. To do it right, you would std::strcpy() the memory from the pre-allocated, pre-initialized constant part of the memory where the content of your string-literal has been stored into your dynamically allocated 10 characters.
And here comes the important part:
When you are done with dealing with these 10 characters, you deallocate them using delete[]. The [] are important here. Everything that you allocate using new x[] has to be deallocated with delete[]. Neither the compiler nor the runtime warn you when use a normal delete instead, so it's important to memorize this rule.
No, that is only pointer reassignment;
No, deleteing something that didn't come from new will often crash; and
Yes, strcpy will do the job… but it's not usually used in C++.
Since nobody has answered with code, std::uninitialized_copy_n (or just std::copy_n, it really doesn't make a difference here) is more C++ than strcpy:
#include <memory>
static char const abcs[] = "abcdefgh"; // define string (static in local scope)
char *c = new char[10]; // allocate
std::copy_n( abcs, sizeof abcs, c ); // initialize (no need for strlen)
// when you're done with c:
delete[] c; // don't forget []
Of course, std::string is what you should use instead:
#include <string>
std::string c( "abcdefgh" ); // does allocate and copy for you
// no need for delete when finished, that is automatic too!
No (pointer reassignment)
No
Yes, you can use strcpy(), see for instance: