Disclaimer: This is homework. I am attempting it and do not expect or want anyone to do it for me. Just a few pointers (hehe) where I'm going wrong would be appreciated.
The homework requires me to create an int* array that holds 10 elements, and then attempt to insert a million ints into it. Each insertion checks if the array needs to be resized, and if it does, I increase it's size so it can hold one more element.
When I insert 10,000 elements, it works fine, but if I try 100,000 elements, I get the following error:
*** glibc detected *** ./set2: realloc(): invalid old size: 0x00000000024dc010 ***
This is the code I'm running. I've commented it so it's easily readable.
void main()
{
//begin with a size of 10
int currentsize = 10;
int* arr = malloc(currentsize * sizeof(int));
int i;
//initalize with all elements set to INT_MAX
for(i = 0; i < currentsize; i++) {
arr[i] = INT_MAX;
}
// insert random elements
for(i = 0; i < 100000; i++) {
currentsize = add(rand() % 100,arr,currentsize);
}
free(arr);
}
/*
Method resizes array if needed, and returns the new size of the array
Also inserts the element into the array
*/
int add(int x, int* arr, int size)
{
//find the first available location
int newSize = size;
int i;
for(i = 0; i < size; i++) {
if (arr[i] == INT_MAX)
break;
}
if (i >= size) {
//need to realloc
newSize++;
arr = realloc(arr, newSize * sizeof(int) );
}
arr[i] = x;
return newSize;
}
The error is probably because you properly use realloc to change arr in the function add, but this modified value is lost when add returns. So the next call to add will receive the old, now bad value.
Also I can't understand why you're using a the for loop to search. You know you want to add at the last element, so why search? Just reallocate the array and plug the new value in the new slot.
Incidentally I'm pretty sure your teacher is trying to get you to see that reallocating for each member causes an asymptotic run time problem. Most implementations of realloc will do a lot of copying with this algorithm. This is why real programs grow the array size by a factor greater than one (often 1.5 or 2) rather than by fixed amounts.
The usual idiom is to abstract the variable size array in a struct:
typedef struct array_s {
int *elts;
int size;
} VARIABLE_ARRAY;
void init(VARIABLE_ARRAY *a)
{
a->size = 10;
a->elts = malloc(a->size * sizeof a->elts[0]);
// CHECK FOR NULL RETURN FROM malloc() HERE
}
void ensure_size(VARIABLE_ARRAY *a, size_t size)
{
if (a->size < size) {
// RESET size HERE TO INCREASE BY FACTOR OF OLD SIZE
// size = 2 * a->size;
a->elts = realloc(size * sizeof a->elts[0]);
a->size = size;
// CHECK FOR NULL RETURN FROM realloc() HERE
}
}
// Set the i'th position of array a. If there wasn't
// enough space, expand the array so there is.
void set(VARIABLE_ARRAY *a, int i, int val)
{
ensure_size(a, i + 1);
a->elts[i] = val;
}
void test(void)
{
VARIABLE_ARRAY a;
init(&a);
for (int i = 0; i < 100000; i++) {
set(&a, i, rand());
}
...
}
I would pass arr to add() as a pointer (to a pointer), so that it can be modified inside of add()
int add(int x, int** arr, int size)
{
// ...
*arr = realloc(*arr, newSize * sizeof(int) );
}
And calling it....
currentsize = add(rand() % 100, &arr, currentsize);
Note that that your code (and my suggested change) is not doing any error checking. You should be checking the return value of malloc and realloc for NULL.
Related
i want to dynamically add numbers to an array in c. My idea is to just allocate a new array with size + 1, add the number, free the root array and change the pointer from the temp to the root array. Like this:
void addNumber(int* a, int* size, int number)
{
*size = *size + 1;
int* temp = (int*)(calloc(*size, sizeof(int)));
int i, j = 0;
for(i = 0; i < *size-1; i++) {
if(a[i] < number) {
printf("add ai");
temp[j] = a[i];
j++;
} else {
printf("add number");
temp[j] = number;
}
}
if(j != *size) {
printf("add new number");
temp[j] = number;
}
free(a);
a = temp;
}
int main(int argc, char* argv[])
{
int n = 10;
int* a;
int size = 1;
a = (int*) (calloc(1, sizeof(int)));
a[0] = 1;
if(!contains(a, size, 2)) {
addNumber(a, &size, 2);
}
printArray(a,size);
return 0;
}
The problem is that in the addNumber function the code works and the *a has the right values of the new array. But in the main function the array *a has the values 1,0. So the new inserted value 2 is not added. Why? Can't get the reason.
To dynamically change the array size, you can use the realloc() routine. Apart from being eaiser to use, it can be faster than the approach of calling free() and malloc() sequentially.
It is guaranteed the reallocated block will be populated with the content of the old memory block.
The problem is that in the addNumber function the code works and the *a has the right values of the new array
There are two major flaws in your code. The first is that you your addNumber() routine doesn't return the newly allocated memory block (thus it is being leaked), you should either use double pointer or return the new block as function result.
And the second one results from the first - after a has been freed, you continue to write to it.
If you prefer to stick to your current approach, this modified code should work:
void addNumber(int** a, int* size, int number)
{
*size = *size + 1;
int* temp = (int*)(calloc(*size, sizeof(int)));
int i, j = 0;
for(i = 0; i < *size-1; i++) {
if((*a)[i] < number) {
printf("add ai");
temp[j] = (*a)[i];
j++;
} else {
printf("add number");
temp[j] = number;
}
}
if(j != *size) {
printf("add new number");
temp[j] = number;
}
free(*a);
*a = temp;
}
int main(int argc, char* argv[])
{
int n = 10;
int* a;
int size = 1;
a = (int*) (calloc(1, sizeof(int)));
a[0] = 1;
if(!contains(a, size, 2)) {
addNumber(&a, &size, 2);
}
printArray(a,size);
return 0;
}
What you're looking for is realloc(). It can be used to grow or shrink memory while retaining its contents.
/* array is now sizeof(int) * new_size bytes */
array = realloc(array, sizeof(int) * new_size);
realloc() might change the existing memory allocation, or it might allocate a whole new block of memory. This is why it's important to reassign the result back to the thing being reallocated.
But if addNumber() reallocates the array by making new memory, main() won't know it. This is for the same reason this doesn't work.
void incrementNumber(int num) {
num = num + 1;
}
int num is a number that gets passed by value. If you want it to be reflected in the caller, you need to pass it as a pointer.
void incrementNumber(int *num) {
*num = *num + 1;
}
Pointers are the same way. They're still numbers. int *a passes a pointer by value. If you change a in addNumber it won't be seen by the caller. Just like before, you need to pass it as a pointer. A pointer to a pointer used like this is known as a double pointer.
void addNumber( int **array_ptr, size_t *array_size, size_t type_size, int number ) {
/* Increment the size and make sure that bubbles up */
*array_size = *array_size + 1;
/* realloc might grow the memory, or it might allocate new memory
either way, assign the result back to its original variable
by dereferencing the double pointer.
*/
*array_ptr = realloc(*array_ptr, *array_size * type_size);
/* Since it's a double pointer, we have to first dereference it before using
it as an array */
(*array_ptr)[*array_size - 1] = number;
}
(Note that I also pass in the sizeof the elements in the array, that can't be assumed).
This is called by passing a pointer to the array.
addNumber(&a, &size, sizeof(int), 5);
After that, everything is the same.
for( int i = 0; i < size; i++ ) {
printf("%d ", a[i]);
}
puts("");
Eventually you'll want to improve this by having the array, size, and type in a struct so you can pass that around in a neat package.
typedef struct {
int *array;
size_t size;
} IntArray;
This is great to do as an exercise, you'll learn a lot and kick a lot of bad habits about static memory. But doing dynamic data structures correctly and efficiently is difficult (for example, allocating one extra slot at a time is very inefficient).
There are many, many libraries out there which provide such dynamic structures. So continue with this as an exercise, but for real code use a library such as Gnome Lib.
Why? Can't get the reason.
That's because you are modifying the value of a locally in addNumber. That does not change the value of a in main.
In order for main to have access to the newly allocated memory, you need to change addNumber to return the newly allocated pointer.
int* addNumber(int* a, int* size, int number){
...
return a;
}
and then change main to:
if(!contains(a, size, 2)){
a = addNumber(a, &size, 2);
// Assign to a the new pointer value.
}
Your 'a' in main is already a pointer, passing it to a function passes a copy of it. What you have to do is - pass the adress '&a' and receive it in funtion as double pointer '**a' and inside the function, use dereference to get values inside array ( like *a[i] and free(*a).
Change the last line to 'return temp' and collect it in main as a=addnumber(&a,&size,2);
By the way, instead of going through all these hassle why don't you just use realloc() function. It increases the size of array dynamically. After using realloc you can just add the new number at the last index.
Disclaimer: This is homework. I am attempting it and do not expect or want anyone to do it for me. Just a few pointers (hehe) where I'm going wrong would be appreciated.
The homework requires me to create an int* array that holds 10 elements, and then attempt to insert a million ints into it. Each insertion checks if the array needs to be resized, and if it does, I increase it's size so it can hold one more element.
When I insert 10,000 elements, it works fine, but if I try 100,000 elements, I get the following error:
*** glibc detected *** ./set2: realloc(): invalid old size: 0x00000000024dc010 ***
This is the code I'm running. I've commented it so it's easily readable.
void main()
{
//begin with a size of 10
int currentsize = 10;
int* arr = malloc(currentsize * sizeof(int));
int i;
//initalize with all elements set to INT_MAX
for(i = 0; i < currentsize; i++) {
arr[i] = INT_MAX;
}
// insert random elements
for(i = 0; i < 100000; i++) {
currentsize = add(rand() % 100,arr,currentsize);
}
free(arr);
}
/*
Method resizes array if needed, and returns the new size of the array
Also inserts the element into the array
*/
int add(int x, int* arr, int size)
{
//find the first available location
int newSize = size;
int i;
for(i = 0; i < size; i++) {
if (arr[i] == INT_MAX)
break;
}
if (i >= size) {
//need to realloc
newSize++;
arr = realloc(arr, newSize * sizeof(int) );
}
arr[i] = x;
return newSize;
}
The error is probably because you properly use realloc to change arr in the function add, but this modified value is lost when add returns. So the next call to add will receive the old, now bad value.
Also I can't understand why you're using a the for loop to search. You know you want to add at the last element, so why search? Just reallocate the array and plug the new value in the new slot.
Incidentally I'm pretty sure your teacher is trying to get you to see that reallocating for each member causes an asymptotic run time problem. Most implementations of realloc will do a lot of copying with this algorithm. This is why real programs grow the array size by a factor greater than one (often 1.5 or 2) rather than by fixed amounts.
The usual idiom is to abstract the variable size array in a struct:
typedef struct array_s {
int *elts;
int size;
} VARIABLE_ARRAY;
void init(VARIABLE_ARRAY *a)
{
a->size = 10;
a->elts = malloc(a->size * sizeof a->elts[0]);
// CHECK FOR NULL RETURN FROM malloc() HERE
}
void ensure_size(VARIABLE_ARRAY *a, size_t size)
{
if (a->size < size) {
// RESET size HERE TO INCREASE BY FACTOR OF OLD SIZE
// size = 2 * a->size;
a->elts = realloc(size * sizeof a->elts[0]);
a->size = size;
// CHECK FOR NULL RETURN FROM realloc() HERE
}
}
// Set the i'th position of array a. If there wasn't
// enough space, expand the array so there is.
void set(VARIABLE_ARRAY *a, int i, int val)
{
ensure_size(a, i + 1);
a->elts[i] = val;
}
void test(void)
{
VARIABLE_ARRAY a;
init(&a);
for (int i = 0; i < 100000; i++) {
set(&a, i, rand());
}
...
}
I would pass arr to add() as a pointer (to a pointer), so that it can be modified inside of add()
int add(int x, int** arr, int size)
{
// ...
*arr = realloc(*arr, newSize * sizeof(int) );
}
And calling it....
currentsize = add(rand() % 100, &arr, currentsize);
Note that that your code (and my suggested change) is not doing any error checking. You should be checking the return value of malloc and realloc for NULL.
I'm working on a C implementation for Conway's game of life, I have been asked to use the following header:
#ifndef game_of_life_h
#define game_of_life_h
#include <stdio.h>
#include <stdlib.h>
// a structure containing a square board for the game and its size
typedef struct gol{
int **board;
size_t size;
} gol;
// dynamically creates a struct gol of size 20 and returns a pointer to it
gol* create_default_gol();
// creates dynamically a struct gol of a specified size and returns a pointer to it.
gol* create_gol(size_t size);
// destroy gol structures
void destroy_gol(gol* g);
// the board of 'g' is set to 'b'. You do not need to check if 'b' has a proper size and values
void set_pattern(gol* g, int** b);
// using rules of the game of life, the function sets next pattern to the g->board
void next_pattern(gol* g);
/* returns sum of all the neighbours of the cell g->board[i][j]. The function is an auxiliary
function and should be used in the following function. */
int neighbour_sum(gol* g, int i, int j);
// prints the current pattern of the g-board on the screen
void print(gol* g);
#endif
I have added the comments to help out with an explanation of what each bit is.
gol.board is a 2-level integer array, containing x and y coordinates, ie board[x][y], each coordinate can either be a 1 (alive) or 0 (dead).
This was all a bit of background information, I'm trying to write my first function create_default_gol() that will return a pointer to a gol instance, with a 20x20 board.
I then attempt to go through each coordinate through the 20x20 board and set it to 0, I am getting a Segmentation fault (core dumped) when running this program.
The below code is my c file containing the core code, and the main() function:
#include "game_of_life.h"
int main()
{
// Create a 20x20 game
gol* g_temp = create_default_gol();
int x,y;
for (x = 0; x < 20; x++)
{
for (y = 0; y < 20; y++)
{
g_temp->board[x][y] = 0;
}
}
free(g_temp);
}
// return a pointer to a 20x20 game of life
gol* create_default_gol()
{
gol* g_rtn = malloc(sizeof(*g_rtn) + (sizeof(int) * 20 * 20));
return g_rtn;
}
This is the first feature I'd like to implement, being able to generate a 20x20 board with 0's (dead) state for every coordinate.
Please feel free to criticise my code, I'm looking to determine why I'm getting the segmentation fault, and if I'm allocating memory properly in the create_default_gol() function.
Thanks!
The type int **board; means that board must contain an array of pointers, each of which points to the start of each row. Your existing allocation omits this, and just allocates *g_rtn plus the ints in the board.
The canonical way to allocate your board, supposing that you must stick to the type int **board;, is:
gol* g_rtn = malloc(sizeof *g_rtn);
g_rtn->size = size;
g_rtn->board = malloc(size * sizeof *g_rtn->board);
for (int i = 0; i < size; ++i)
g_rtn->board[i] = malloc(size * sizeof **g_rtn->board);
This code involves a lot of small malloc chunks. You could condense the board rows and columns into a single allocation, but then you also need to set up pointers to the start of each row, because board must be an array of pointers to int.
Another issue with this approach is alignment. It's guaranteed that a malloc result is aligned for any type; however it is possible that int has stricter alignment requirements than int *. My following code assumes that it doesn't; if you want to be portable then you could add in some compile-time checks (or run it and see if it aborts!).
The amount of memory required is the sum of the last two mallocs:
g_rtn->board = malloc( size * size * sizeof **g_rtn->board
+ size * sizeof *g_rtn->board );
Then the first row will start after the end of the row-pointers (a cast is necessary because we are converting int ** to int *, and using void * means we don't have to repeat the word int):
g_rtn->board[0] = (void *) (g_rtn->board + size);
And the other rows each have size ints in them:
for (int i = 1; i < size; ++i)
g_rtn->board[i] = g_rtn->board[i-1] + size;
Note that this is a whole lot more complicated than just using a 1-D array and doing arithmetic for the offsets, but it was stipulated that you must have two levels of indirection to access the board.
Also this is more complicated than the "canonical" version. In this version we are trading code complexity for the benefit of having a reduced number of mallocs. If your program typically only allocates one board, or a small number of boards, then perhaps this trade-off is not worth it and the canonical version would give you fewer headaches.
Finally - it would be possible to allocate both *g_rtn and the board in the single malloc, as you attempted to do in your question. However my advice (based on experience) is that it is simpler to keep the board separate. It makes your code clearer, and your object easier to use and make changes to, if the board is a separate allocation to the game object.
create_default_gol() misses to initialise board, so applying the [] operator to it (in main() ) the program accesses "invaid" memory and with ethis provokes undefined behaviour.
Although enough memory is allocated, the code still needs to make board point to the memory by doing
gol->board = ((char*) gol) + sizeof(*gol);
Update
As pointed out by Matt McNabb's comment board points to an array of pointers to int, so initialisation is more complicate:
gol * g_rtn = malloc(sizeof(*g_rtn) + 20 * sizeof(*gol->board));
g_rtn->board = ((char*) gol) + sizeof(*gol);
for (size_t i = 0; i<20; ++i)
{
g_rtn->board[i] = malloc(20 * sizeof(*g_rtn->board[i])
}
Also the code misses to set gol's member size. From what you tell us it is not clear whether it shall hold the nuber of bytes, rows/columns or fields.
Also^2 coding "magic numbers" like 20 is bad habit.
Also^3 create_default_gol does not specify any parameters, which explictily allows any numberm and not none as you might perhaps have expected.
All in all I'd code create_default_gol() like this:
gol * create_default_gol(const size_t rows, const size_t columns)
{
size_t size_rows = rows * sizeof(*g_rtn->board));
size_t size_column = columns * sizeof(**g_rtn->board));
gol * g_rtn = malloc(sizeof(*g_rtn) + size_rows);
g_rtn->board = ((char*) gol) + sizeof(*gol);
if (NULL ! = g_rtn)
{
for (size_t i = 0; i<columns; ++i)
{
g_rtn->board[i] = malloc(size_columns); /* TODO: Add error checking here. */
}
g_rtn->size = size_rows * size_columns; /* Or what ever this attribute is meant for. */
}
return g_rtn;
}
gol* create_default_gol()
{
int **a,i;
a = (int**)malloc(20 * sizeof(int *));
for (i = 0; i < 20; i++)
a[i] = (int*)malloc(20 * sizeof(int));
gol* g_rtn = (gol*)malloc(sizeof(*g_rtn));
g_rtn->board = a;
return g_rtn;
}
int main()
{
// Create a 20x20 game
gol* g_temp = create_default_gol();
int x,y;
for (x = 0; x < 20; x++)
{
for (y = 0; y < 20; y++)
{
g_temp->board[x][y] = 10;
}
}
for(x=0;x<20;x++)
free(g_temp->board[x]);
free(g_temp->board);
free(g_temp);
}
main (void)
{
gol* gameOfLife;
gameOfLife = create_default_gol();
free(gameOfLife);
}
gol* create_default_gol()
{
int size = 20;
gol* g_rtn = malloc(sizeof *g_rtn);
g_rtn = malloc(sizeof g_rtn);
g_rtn->size = size;
g_rtn->board = malloc(size * sizeof *g_rtn->board);
int i, b;
for (i = 0; i < size; ++i){
g_rtn->board[i] = malloc(sizeof (int) * size);
for(b=0;b<size;b++){
g_rtn->board[i][b] = 0;
}
}
return g_rtn;
}
Alternatively, since you also need to add a create_gol(size_t new_size) of custom size, you could also write it as the following.
main (void)
{
gol* gameOfLife;
gameOfLife = create_default_gol();
free(gameOfLife);
}
gol* create_default_gol()
{
size_t size = 20;
return create_gol(size);
}
gol* create_gol(size_t new_size)
{
gol* g_rtn = malloc(sizeof *g_rtn);
g_rtn = malloc(sizeof g_rtn);
g_rtn->size = new_size;
g_rtn->board = malloc(size * sizeof *g_rtn->board);
int i, b;
for (i = 0; i < size; ++i){
g_rtn->board[i] = malloc(sizeof (int) * size);
for(b=0;b<size;b++){
g_rtn->board[i][b] = 0;
}
}
return g_rtn;
}
Doing this just minimizes the amount of code needed.
I am an unexperienced C-programmer: I want all the numbers below 5000 that are multiples of 5. Here is how I do this currently:
int main()
{
int i;
const int max =5000-1;
for(i=2; i<(max+1); i++)
{
if(!(i%5))
{
printf("%d\n", i);
}
}
return 0;
}
Say that I want them all listed in an array. What I could do is just to pre-allocate an integer array and fill out the various position. Naturally I can't know the exact required length beforehand, so I would over estimate it length.
However, I come from a C++ background, so normally what I would do there is to pushback a vector, all clean and tidy. But what is the professional way to do this in C? Would you guys pre-allocate or dynamically resize the array?
I am currently using Herbert Schildt's "Turbo C/C++", I'm sure there are much better (and up-to-date) references out there when I get more into things.
realloc does everything you're talking about. Allocating an array, growing an array, shrinking an array: it does it all.
int max = 5000; /* why subtract one if you have to add one to use it? */
int *arr = NULL;
int i;
arr = realloc(arr, max * sizeof *arr); /* allocate generous array */
for (i = 0; i < max; i++) {
/* ... */
}
max = 10000;
arr = realloc(arr, max * sizeof *arr); /* grow array */
max = 100;
arr = realloc(arr, max * sizeof *arr); /* shrink array */
Now there is some popular advice that you should always save the return value from realloc as a separate variable and check it for NULL before overwriting your real pointer variable. This is because there are bizarre situations where the realloc may fail, even on something as innocuous as shrinking an array. This can happen if the malloc subsystem is implemented using fixed-sized buckets, among other possibilities. A shrinking request may fail with a fixed-sized bucket system if there simply aren't any more "small" regions available.
If realloc fails, it returns NULL, but the original allocation is left intact. If you just write the return value into your pointer variable, that data will lost. So, in general, you should try to do this instead:
int *tmp;
tmp = realloc(arr, max * sizeof *arr);
if (tmp) {
arr = tmp;
} else {
/* maybe issue an error message? */
}
If you want to allocate the perfect size, you could try this :
#include <stdio.h>
#include <stdlib.h>
int main(){
int i, j;
int max = 5000;
int * ourNumbers = 0;
int count = 0;
for(i = 2; i < max; i++){
if (i % 5 == 0){
count += 1;
}
}
printf("\ncount = %d\n", count);
ourNumbers = (int *) malloc(sizeof (int) * count);
// and after you can populate your array with those values;
// like this you will allocate the exact memory
}
I know that is not so efficient, but I hope it will help you :)
I have the following C code :
int *a;
size_t size = 2000*sizeof(int);
a = malloc(size);
which works fine. But if I have the following :
char **b = malloc(2000*sizeof *b);
where every element of b has different length.
How is it possible to do the same thing for b as i did for a; i.e. the following code would hold correct?
char *c;
size_t size = 2000*sizeof(char *);
c = malloc(size);
First, you need to allocate array of pointers like char **c = malloc( N * sizeof( char* )), then allocate each row with a separate call to malloc, probably in the loop:
/* N is the number of rows */
/* note: c is char** */
if (( c = malloc( N*sizeof( char* ))) == NULL )
{ /* error */ }
for ( i = 0; i < N; i++ )
{
/* x_i here is the size of given row, no need to
* multiply by sizeof( char ), it's always 1
*/
if (( c[i] = malloc( x_i )) == NULL )
{ /* error */ }
/* probably init the row here */
}
/* access matrix elements: c[i] give you a pointer
* to the row array, c[i][j] indexes an element
*/
c[i][j] = 'a';
If you know the total number of elements (e.g. N*M) you can do this in a single allocation.
The typical form for dynamically allocating an NxM array of type T is
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * M);
}
}
If each element of the array has a different length, then replace M with the appropriate length for that element; for example
T **a = malloc(sizeof *a * N);
if (a)
{
for (i = 0; i < N; i++)
{
a[i] = malloc(sizeof *a[i] * length_for_this_element);
}
}
Equivalent memory allocation for char a[10][20] would be as follows.
char **a;
a=malloc(10*sizeof(char *));
for(i=0;i<10;i++)
a[i]=malloc(20*sizeof(char));
I hope this looks simple to understand.
The other approach would be to allocate one contiguous chunk of memory comprising header block for pointers to rows as well as body block to store actual data in rows. Then just mark up memory by assigning addresses of memory in body to the pointers in header on per-row basis. It would look like follows:
int** 2dAlloc(int rows, int* columns) {
int header = rows * sizeof(int*);
int body = 0;
for(int i=0; i<rows; body+=columnSizes[i++]) {
}
body*=sizeof(int);
int** rowptr = (int**)malloc(header + body);
int* buf = (int*)(rowptr + rows);
rowptr[0] = buf;
int k;
for(k = 1; k < rows; ++k) {
rowptr[k] = rowptr[k-1] + columns[k-1];
}
return rowptr;
}
int main() {
// specifying column amount on per-row basis
int columns[] = {1,2,3};
int rows = sizeof(columns)/sizeof(int);
int** matrix = 2dAlloc(rows, &columns);
// using allocated array
for(int i = 0; i<rows; ++i) {
for(int j = 0; j<columns[i]; ++j) {
cout<<matrix[i][j]<<", ";
}
cout<<endl;
}
// now it is time to get rid of allocated
// memory in only one call to "free"
free matrix;
}
The advantage of this approach is elegant freeing of memory and ability to use array-like notation to access elements of the resulting 2D array.
If every element in b has different lengths, then you need to do something like:
int totalLength = 0;
for_every_element_in_b {
totalLength += length_of_this_b_in_bytes;
}
return malloc(totalLength);
I think a 2 step approach is best, because c 2-d arrays are just and array of arrays. The first step is to allocate a single array, then loop through it allocating arrays for each column as you go. This article gives good detail.
2-D Array Dynamic Memory Allocation
int **a,i;
// for any number of rows & columns this will work
a = malloc(rows*sizeof(int *));
for(i=0;i<rows;i++)
*(a+i) = malloc(cols*sizeof(int));
malloc does not allocate on specific boundaries, so it must be assumed that it allocates on a byte boundary.
The returned pointer can then not be used if converted to any other type, since accessing that pointer will probably produce a memory access violation by the CPU, and the application will be immediately shut down.