How can we modify the size of array in C++? - c++

I have an array of characters allocated with new and i want to modify the size of the array. Can i use realloc function for that? What is the best way to do so?

No, you can't... realloc() can only be used with malloc()/free()
Best call for a new[] allocated array is to create a new one and then memcpy() the data from one to another.
Better way - use an std::vector or std::string instead of array if you know you'll need resizing. Internally they're pretty much the same array.

In C++ it is best to use the STL std::vector class for this kind of thing. Either that, or a std::string.

I have an array of characters allocated with new and i want to modify the size of the array.
You can't resize an array, you can only allocate a new, larger one, move the contents to the new array, and delete the old one.
Can i use realloc function for that?
If you used malloc to allocate the original array, yes. But that's usually a bad idea in C++, where you usually want to deal with arrays of non-trivial objects not raw memory.
What is the best way to do so?
Use std::string (or perhaps std::vector<char>) to manage a dynamic array of characters automatically. These also have the advantage of using RAII to reduce the risk of memory leaks and other memory management errors.

You can use realloc(), if your array is allocated dynamically(via malloc/calloc/realloc). If you have static array, you can't resize it.If you have allocated with new:
int* Copy = new int[newSize];
std::copy(oldCopy,oldCopy+size,Copy);
But the best way would be to use std::vector<type> from c++ standard library

As was said by others, you cannot resize the array that was allocated per se, but you can create a larger one, copy the content of the first array to the second and delete the first one.
Here's an example, using std::copy().
int main(int argc, char** argv) {
int* arr = new int[5];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
int* tmp = new int[10];
std::copy(arr, arr + 5, tmp);
std::copy(arr, arr, tmp + 5);
delete[] arr;
arr = tmp;
for(int i = 0; i < 10; i++) {
std::cout << arr[i] << "\n";
}
delete[] arr;
std::cin.get();
return 0;
}
This first creates an integer array and fills it. It then creates a larger array and fills it with the content of the first array twice and display that new larger array.
The principle is the same for an array of characters.
As the others have mentionned, your best bet in C++ is to use the standard library. For a resizable array of characters, you should probably use std::string or a vector of strings, but it's a bit overkill in some situations.

Related

Dynamic allocation to array of pointers and its alternatives

The standard way of allocating array using new int is:
int* arr = new int[50];
while declaring it in this manner there is going to be contiguous memory allocation and there will be a single array variable in the stack of variables.
if I want to declare it in the form of 50 different pointer variables so that each pointer would have different memory address and not necessarily contiguous the most obvious way of going for it is like this:
int * arr[50];
but in this way what would be the command / code for assigning memory ( i.e. via new int ) and what are the downsides or advantages of declaring in each manner.
The obvious way would be to iterate over all the elements and allocate memory for them:
for (int i = 0; i < 50; i++){
arr[i] = new int;
}
The downside of non-contiguous memory chunk would be cache misses.
You can read more on that here.
How to assign, is already mentioned in this answer; Hence not repeating.
For single int allocation, your below line is an overkill:
int* arr[50]; // all downsides only
Instead of that, you should use simple integers:
int arr[50];
Better to utilise facilities by standard containers such as:
std::vector<int> vi; // if the number of int-s are dynamic
std::array<int, 50> ai; // if the number of int-s are fixed
Finally, from this answer,
"Avoid pointers until you can't... So the rule of thumb is to use pointers only if there is no other choice."

Copy array then delete original

I have an array of a structure (with the parameters of name and number), and the initial array takes in elements from a document that I've made. The initial list size starts at 1000. When the list fills up, I call another method that I'm struggling with. I would like for it to copy the data into a new array that doubled the size, and then delete the old array.
If I name it: array1 and array2, I have my program use array1 throughout. I need help with the pointers that would get array2 to work as array1.
Is there a way to copy the array to a temp array of the same or new size, and then remake the initial array reassigning back to that? For this exercise, I can't use vectors. While I know how to use them, and that they solve this issue while being better, I'm trying to do it with only arrays.
using namespace std;
struct Information {
char functionality;
int SSN;
string name;
};
int numPeople = 1000;
//Gets called if the initial array (whatever size) is filled
void doubleArray(Information *array){
numPeople = numPeople * 2;
//Will now be the doubled array size
Information temp[numPeople]
for(int i = 0; i < numArray; i++){
temp[i].SSN = array[i].SSN;
temp[i].name = array[i].name;
}
//Normally makes it crash
delete[] array;
}
edit: This is what I currently have
void doubleArray(Information *person){
numPeople = numPeople * 2;
Information* temp = new Information[numPeople];
memcpy(temp, person, numPeople);
delete[] person;
person = temp;
}
It gets to numPeople = 1000 (the initial list size) but then crashes shortly after. Is the doubling array correct?
Arrays are fixed size. You cannot change the capacity of the original array.
{Use std::vector}
You can have a pointer to an array. And use the same pointer. When the array is full, you can allocate another array, copy old array items to new array, delete the old array and assign your array pointer to the new array.
{Did I mention std::vector?}
By the way, there is a data structure that performs resizing as necessary. If I recall correctly, it is std::vector. Try it out. :-)
Assuming you are using std::array (which you should be), then copying the array is very easy.
std::array<myStruct, 1000> array1{};
std::array<myStruct, 2000> array2{};
// codes...
std::copy(array1.begin(), array1.end(), array2.begin())
However, this is a specific scenario in which you only use these two arrays. It will not dynamically double the size of the array as you simply cannot do this dynamically with stack-based arrays, just like c arrays[].
What you can, and should, be using is std::vector<myStruct>. This will dynamically grow as you need it. Until you provide us with code and a more specific issue, this is the best advice that I can offer with the information provided.
If you aren't allowed to use std::vector, as one of your comments stated, then you'll want to look at dynamic allocation.
size_t sz = [whatever];
// Dynamically allocate an array of size sz.
T* T_array = new T[sz];
// Do whatever...
delete[] T_array; // new[] needs to be paired with delete[].
T_array = nullptr; // Not strictly necessary, but a good idea if you have more code after.
As the size doesn't need to be constant for a dynamic array, this will allow you to allocate memory as necessary. You can then use std::copy() to copy data from one array to the other, as Goodies mentioned.
[For more information on dynamic allocation, see here.]

how to allocate dynamic memory to int a[4][3] array

how to allocate run time memory to an array of size[4][3]?
i.e int a[4][3]
If need is to allocate memory to an array at run time than how to allocate memory to 2D array or 3D array.
Editing the answer based on comments. Allocate separately for each dimension. For a 2D array a 2 level allocation is required.
*a = (int**)malloc(numberOfRows*sizeof(int*));
for(int i=0; i<numberOfRows; i++)
{
(*arr)[i] = (int*)malloc(numberOfColumns*sizeof(int));
}
The simplest way to allocate dynamically an array of type int[4][3] is the following
int ( *a )[3] = new int[4][3];
// some stuff using the array
delete []a;
Another way is to allocate several arrays. For example
int **a = new int * [4];
for ( size_t i = 0; i < 4; i++ ) a[i] = new int[3];
// some stuff using the array
for ( size_t i = 0; i < 4; i++ ) delete []a[i];
delete []a;
What have you tried. new int[4][3] is a perfectly valid
expression, and the results can be assigned to a variable with the
appropriate type:
int (*array2D)[3] = new int[4][3];
Having said that: I can't really think of a case where this
would be appropriate. Practically speaking, anytime you need
a 2 dimensional array, you should define a class which
implements it (using std::vector<int> for the actual memory).
A pure C approach is the following:
int (*size)[4][3];
size = malloc(sizeof *size);
/* Verify size is not NULL */
/* Example of access */
(*size)[1][2] = 89;
/* Do something useful */
/* Deallocate */
free(size);
The benefit is that you consume less memory by not allocating intermediate pointers, you deal with a single block of memory and deallocation is simpler. This is especially important if you start to have more than 2 dimensions.
The drawback is that the access syntax is more complicated, as you need to dereference a pointer before being able to index.
Use calloc, i guess this will do.
int **p;
p=(int**)calloc(4,sizeof(int));
In C you can use pointer to pointer
AS #Lundin mentioned this is not 2D array. It is a lookup table using pointers to fragmented memory areas allocated all over the heap.
You need to allocate how many pointers you need and then allocate each pointer. you can allocate fixed size or varaible size depending on your requirement
//step-1: pointer to row
int **a = malloc(sizeof(int *) * MAX_NUMBER_OF_POINTERS);
//step-2: for each rows
for(i = 0; i < MAX_NUMBER_OF_POINTERS; i++){
//if you want to allocate variable sizes read them here
a[i] = malloc(sizeof(int) * MAX_SIZE_FOR_EACH_POINTER); // where as if you use character pointer always allocate one byte extra for null character
}
Where as if you want to allocate char pointers avoid using sizeof(char) inside for loop. because sizeof(char) == 1 and do not cast malloc result.
see How to declare a 2d array in C++ using new
You could use std::vector<> since it is a templated container (meaning array elements can be whatever type you need). std::vector<> allows for dynamic memory usage (you can change the size of the vector<> whenever you need to..the memory is allocated and free'd automatically).
For example:
#include <iostream>
#include <vector>
using namespace std; // saves you from having to write std:: in front of everthing
int main()
{
vector<int> vA;
vA.resize(4*3); // allocate memory for 12 elements
// Or, if you prefer working with arrays of arrays (vectors of vectors)
vector<vector<int> > vB;
vB.resize(4);
for (int i = 0; i < vB.size(); ++i)
vB[i].resize(3);
// Now you can access the elements the same as you would for an array
cout << "The last element is " << vB[3][2] << endl;
}
You can use malloc() in c or new in c++ for dynamic memory allocation.

How to expand an array dynamically in C++? {like in vector }

Lets say, i have
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
Now I want to add a 6th element to the array. How do I do it?
You have to reallocate the array and copy the data:
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
// realloc
int* temp = new int[6];
std::copy(p, p + 5, temp); // Suggested by comments from Nick and Bojan
delete [] p;
p = temp;
You cannot. You must use a dynamic container, such as an STL vector, for this. Or else you can make another array that is larger, and then copy the data from your first array into it.
The reason is that an array represents a contiguous region in memory. For your example above, let us say that p points to address 0x1000, and the the five ints correspond to twenty bytes, so the array ends at the boundary of 0x1014. The compiler is free to place other variables in the memory starting at 0x1014; for example, int i might occupy 0x1014..0x1018. If you then extended the array so that it occupied four more bytes, what would happen?
If you allocate the initial buffer using malloc you can use realloc to resize the buffer. You shouldn't use realloc to resize a new-ed buffer.
int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);
However, this is a C-ish way to do things. You should consider using vector.
Why don't you look in the sources how vector does that? You can see the implementation of this mechanism right in the folder your C++ include files reside!
Here's what it does on gcc 4.3.2:
Allocate a new contiguous chunk of memory with use of the vector's allocator (you remember that vector is vector<Type, Allocator = new_allocator>?). The default allocator calls operator new() (not just new!) to allocate this chunk, letting himself thereby not to mess with new[]/delete[] stuff;
Copy the contents of the existing array to the newly allocated one;
Dispose previously aligned chunk with the allocator; the default one uses operator delete().
(Note, that if you're going to write your own vector, your size should increase "M times", not "by fixed amount". This will let you achieve amortized constant time. For example, if, upon each excession of the size limit, your vector grows twice, each element will be copied on average once.)
Same as others are saying, but if you're resizing the array often, one strategy is to resize the array each time by doubling the size. There's an expense to constantly creating new and destroying old, so the doubling theory tries to mitigate this problem by ensuring that there's sufficient room for future elements as well.

how to grow a dynamic array of char pointers (in C++)?

I am trying to work with an array of char pointers.
Let's say I dynamically declare such an array like so:
int numrows=100;
char** array = new char*[numrows];
And then I populate it by using getline to get strings from a file, converting the strings to char arrays, then setting a pointer in my array to point to said char array like so:
string entry;
int i=0;
while (getline(file,entry)){
char* cstring = new char[entry.length()];
array[i]=strncpy(cstring,entry.c_str(),entry.length());
free(cstring);
i++;
}
(this works, but is there a better way to do this?)
The problem is, I don't know how to grow the array once i becomes greater than numrows.
I know how to do this for a single-dimensional array, but the two-dimensionality is throwing me off.
I'm thinking I should be able to grow it the way you would grow a single-dimension array, right?
if (i==numrows){
char** temp = new char*[numrows+numrows];
for (int j=0;j<i;j++){
char* cstring = new char[strlen(array[i])];
temp[i]=strncpy(cstrin,array[i],strlen(array[i]));
free(cstring);
}
delete [] array;
array = temp;
}
So if the current array becomes full, make a second array that is twice the size of the current array and fill it with the contents of the current array. Then delete array and let array point to temp. I'm fine up to making temp the new array. I can get the contents of array into temp, but when I delete array and set array = temp, the contents of array aren't the contents of temp.
So my question is how can/should I be growing this dynamic array of char pointers?
use std::vector - it is your friend
std::vector<std::string> arr;
while(getline(file, entry))
{
arr.push_back(entry);
}
done
sort can be done using vector sort with custom compare
bool less3(const std::string &s1, const std::string &s2)
{
return s1.compare(0, 3, s2, 0, 3) == 0;
}
std::sort(arr.begin(), arr.end(), less3);
I bet that less3 could be made more efficient but readability wins unless you really suffer
edit fixed as per nice comment from gman
Apart from the remarks by Tyler McHenry, and the fact that you should use the STL, the problem is most likely that you are freeing each cstring after having copied it. Perhaps you intended to free the original string instead?
for (int j=0;j<i;j++){
char* cstring = new char[strlen(array[i])];
temp[i]=strncpy(cstring,array[i],strlen(array[i]));
delete[] array[i];
}
When you first populate the array, DO NOT call free() on the string. First of all, you should use delete[], but more importantly, you still want to access that string later, right?
now i see you say that this is a class that does allow you to use STL. A class teaching c++ that forbids one of the major language features! - anyway passing along
You do not need to be copying the strings to resize the array , you just need to copy the pointers.
if (i==numrows){
char** temp = new char*[numrows+numrows];
for (int j=0;j<i;j++){
temp[j]=array[j];
}
delete [] array;
array = temp;
}
i am sure there are still out by ones there - left as homework