Resizing an array in C
No, you can't change the size of an array. You could use a dynamically allocated list of char*
instead and realloc()
as required:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main()
{
char** array = malloc(1 * sizeof(*array));
if (array)
{
array[0] = "This";
printf("%s\n------\n", array[0]);
char** tmp = realloc(array, 2 * sizeof(*array));
if (tmp)
{
array = tmp;
array[1] = "That";
printf("%s\n", array[0]);
printf("%s\n", array[1]);
}
free(array);
}
return 0;
}
See online demo: https://ideone.com/ng00k.
Resizing an array with C
Start off by creating the array:
structName ** sarray = (structName **) malloc(0 * sizeof(structName *));
Always keep track of the size separately:
size_t sarray_len = 0;
To increase or truncate:
sarray = (structName **) realloc(sarray, (sarray_len + offset) * sizeof(structName *));
Then set the size:
sarray_len += offset;
Happy to help and hope that helps.
Resizing 2D Arrays in C
Assuming you declared array
as
int **array;
and allocated as
array = malloc( sizeof *array * ROWS );
if ( array )
{
for ( size_t i = 0; i < ROWS; i++ )
array[i] = malloc( sizeof *array[i] * COLS );
}
The structure you wind up with looks something like:
+---+ +---+ +---+
array: | | -----> | | array[0] ------> | | array[0][0]
+---+ +---+ +---+
... | | array[1] ---+ | | array[0][1]
+---+ | +---+
... | | | array[0][2]
| +---+
| ...
|
| +---+
+--> | | array[1][0]
+---+
| | array[1][1]
+---+
| | array[1][2]
+---+
...
If you want to increase the number of rows in the array but leave the column sizes the same, you'd do something like
int **tmp = realloc( array, sizeof *array * (ROWS + add_rows) );
if ( tmp )
{
array = tmp;
for ( size_t i = 0; i < add_rows; i++ )
{
array[ROWS + i] = malloc( sizeof *array[ROWS + i] * COLS );
}
}
If you want to leave the number of rows the same but increase the number of columns in each row, you would do something like
for ( size_t i = 0; i < ROWS; i++ )
{
int *tmp = realloc( array[i], sizeof *array[i] * (COLS + add_cols) );
if ( tmp )
{
array[i] = tmp;
}
}
If you want to reduce the number of rows in the array, you will need to free the affected rows first:
for ( size_t i = 1; i <= del_rows; i++ )
free( array[ROWS - i] );
int *tmp = realloc( array, ROWS - del_rows );
if ( tmp )
array = tmp;
If you want to reduce the number of columns:
for ( size_t i = 0; i < ROWS: i++ )
{
int *tmp = realloc( array[i], sizeof *array[i] * (COLS - del_cols) );
if ( tmp )
array[i] = tmp;
}
From there, you should be able to figure out any combinations you need. I strongly recommend doing only one dimension at a time (that is, if you want to increase the number of rows and columns, do the rows first, then do the columns).
You always want to assign the result of realloc
to a temporary variable; if realloc
cannot satisfy the request, it will return NULL
, and if you assign it back to the original variable, you will lose your only reference to the memory that was previously allocated, leading to a memory leak.
Manually resize array in C++
The simple answer is you should always use std::vector in this case. However it might be useful to explain just why that is. So lets consider how you would implement this without std::vector so you might see just why you would want to use std::vector:
// Naive approach
Line::push(const Point& p)
{
Point* new_points = new Points[index + 1];
std::copy(std::make_move_iterator(points), std::make_move_iterator(points+index), new_points);
new_points[index] = p;
delete[] points;
points = new_points;
index += 1;
}
This approach has many problems. We are forced to reallocate and move the entire array every time an entry is inserted. However a vector will pre-allocate a reserve and use space out of the reserve for each insert, only re-allocating space once the reserve limit is surpassed. This mean vector will far out perform your code in terms of performance as less time will be spent allocating and moving data unnecessarily. Next is the issue of exceptions, this implementation has no exception guarantees, where as the std::vector provides you with a strong exception guarantee: https://en.wikipedia.org/wiki/Exception_safety. Implementing a strong exception guarantee for your class is none trivial, however you would have automatically got this had you implemented this in terms of std::vector as such
Line::push(const Point& p)
{
points.push_back(p);
}
There are also other more subtle problems with your approach, your class does not define copy or assignment operators and so gets compiler generated shallow copy versions generated which means if someone copies your class then allocated members will get deleted twice. To resolve this you need to follow the rule of 3 paradigm pre C++11 and the rule of 5 for C++ 11 onwards: https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming). However had you used a vector none of this would be needed as you would benefit from the rule of zero and be able to rely on the compiler generated defaults: https://blog.rmf.io/cxx11/rule-of-zero
How to resize array in C++?
The size of an array is static in C++. You cannot dynamically resize it. That's what std::vector
is for:
std::vector<int> v; // size of the vector starts at 0
v.push_back(10); // v now has 1 element
v.push_back(20); // v now has 2 elements
v.push_back(30); // v now has 3 elements
v.pop_back(); // removes the 30 and resizes v to 2
v.resize(v.size() - 1); // resizes v to 1
Resizing a two dimensional array in C. Memory leak
If the newsize is smaller, the elements from newsize to size must be freed.
Then the array can be reallocated.
If newsize is larger, the elements from size to newsize need to be set to NULL.
Then reallocate from element 0 to newsize.
For a pointer to pointer the pointer can be returned and assigned. The other option is to pass a pointer to the pointer int ***array
.
#include <stdio.h>
#include <stdlib.h>
int **resize ( int **array, int *newsize, int size){
int **temp = NULL;
if ( *newsize < size) {
for ( int i = *newsize; i < size; i++) {
printf ( "free[%d]\n", i);
free ( array[i]);
}
}
if ( NULL == ( temp = realloc ( array, *newsize * sizeof *array))) {
if ( 0 != *newsize) {
fprintf ( stderr, "realloc problem\n");
*newsize = size;
return array;
}
else {
return NULL;
}
}
array = temp;
for ( int i = size; i < *newsize; i++) {
array[i] = NULL;
}
for ( int i = 0; i < *newsize; i++) {
array[i] = realloc ( array[i], *newsize * sizeof **array);
}
printf("\n");
for ( int i = 0; i < *newsize; i++) {
for ( int j = 0; j < *newsize; j++) {
printf ( "[%d][%d]: %p\n", i, j, (void *)&array[i][j]);
}
}
return array;
}
int main ( void) {
char line[6] = "";
int **items = NULL;
int elements = 0;
int oldsize = 0;
printf ( "enter a number\n");
while ( fgets ( line, sizeof line, stdin)) {
if ( 1 == sscanf ( line, "%d", &elements)) {
if ( 0 <= elements) {
items = resize ( items, &elements, oldsize);
oldsize = elements;
}
if ( 0 == elements) {
free ( items);
break;
}
}
else {
printf ( "enter a number\n");
}
}
return 0;
}
Related Topics
Initializing a C++ Std::Istringstream from an in Memory Buffer
Structured Binding with [[Maybe_Unused]]
Why Does 'Int ;' Compile Fine in C, But Not in C++
Passing Variable Number of Arguments with Different Type - C++
How to Write to Middle of a File in C++
Ostream Chaining, Output Order
Overload Operators as Member Function or Non-Member (Friend) Function
How to Create a Type in C++ That Takes Less Than One Byte of Memory
Better Shading on Bw Display While Rendering Filled Surfaces
How to Use Non-Default Delimiters When Reading a Text File with Std::Fstream
Where Are Member Functions Stored for an Object
C++ Boost: What's the Cause of This Warning
Why Do String Literals (Char*) in C++ Have to Be Constants
Order of Calling Base Class Constructor from Derived Class Initialization List
Diamond Inheritance Lowest Base Class Constructor
When Do We Need to Pass the Size of Array as a Parameter
Dijkstra Shortest Path with Vertexlist = Lists in Boost Graph