Free array returned from function - c

apologies if this has appeared elsewhere, I've not been able to find a clear answer.
I've been using Ed S's answer, Option 1 (linked below) to allocate memory, populate the array, then return it back to the caller.
He recommends freeing the memory after you've finished with it, however when I added the free() line, I get a core dump.
I've had a poke around with GDB, but my skills probably aren't what the need to be.
Thanks in advance for any help you can give.
Link to answer: Returning an array using C
Code:
#include <stdio.h>
#include <stdlib.h>
char * createArray();
int main(int argc, char *argv[]){
printf("Creating Array...\n");
// pointer to an int
char *p;
// size of the array
int i,j;
// width of array
int width = 7;
// height of array
int height = 5;
// get an array from the function
p = createArray(width, height);
// check if p was created properly
if (p){
// print out the array
for (i = 0; i < width; ++i){
for (j = 0; j < height; ++j){
printf("[%c] ", *(p + (i * width) + j));
}
printf("\n");
}
// here's where it hits the fan
free(p);
}
return 0;
}
char * createArray(int w, int h){
// allocate some memory for the array
char *r = malloc(w * h * sizeof(char));
// check if the memory allocation was successful
if(!r){
return NULL;
}
int i, j;
int count = 0;
for (i = 0; i < w; ++i){
for (j = 0; j < h; ++j){
*(r + (i * w) + j) = 'X';
++count;
}
}
return r;
}

With this
char *r = malloc(w * h * sizeof(char));
You allocate w * h (7 * 5 = 35 bytes) of memory. But
*(r + (i * w) + j) = 'X';
can access well beyond the 35 bytes you have allocated (you'll see if you test the possible values for i * w + j in the loop), resulting in undefined behaviour.
This possibly overwrites the malloc's internal data structures and thus you happen to get core dump when you free().

You made a mistake on these lines
*(r + (i * w) + j) = 'X';
and
printf("[%c] ", *(p + (i * width) + j));
To keep inside the boundaries of your "2D" array -it's one dimensional but you are working around it like a compiler would-it should be i * length in there:
*(r + (i * h) + j) = 'X';`
and
printf("[%c] ", *(p + (i * height) + j)); `
If you use this, you should be able to stay within the boundaries without making a mess.

Related

C - free function crashes

I tried checking the addresses and its all looking normal, printing works and everything else works as well.
But when it tries to free the memory, the program crashes.
CODE:
#include <stdio.h>
#include <stdlib.h>
#define FIRST_DIM 2
#define SECOND_DIM 3
#define THIRD_DIM 2
#define TOTAL 12
void getNums(float* pArr);
void sortArr(float* pArr);
void printArr(float* pArr);
int main(void)
{
// Variable assignment
unsigned int i = 0, j = 0;
float*** pppArr = NULL;
// Memory assignment
pppArr = (float***)calloc(FIRST_DIM, sizeof(float**));
if (!(pppArr))
{
printf("Failed Allocating Memory..\n");
system("PAUSE");
return 1;
}
for (i = 0; i < FIRST_DIM; i++)
{
*(pppArr + i) = (float**)calloc(SECOND_DIM, sizeof(float*));
if (!(*(pppArr + i)))
{
printf("Failed Allocating Memory..\n");
system("PAUSE");
return 1;
}
}
for (i = 0; i < FIRST_DIM; i++)
{
for (j = 0; j < SECOND_DIM; j++)
{
*(*(pppArr + i) + j) = (float*)calloc(THIRD_DIM, sizeof(float));
if (!(*(*(pppArr + i) + j)))
{
printf("Failed Allocating Memory..\n");
system("PAUSE");
return 1;
}
printf("%p && %d\n", *(*(pppArr + i) + j), **(*(pppArr + i) + j));
}
}
printf("ASD");
// Getting numbers, sorting them and printing them out
getNums(**pppArr);
sortArr(**pppArr);
printArr(**pppArr);
// End of program
// Releasing memory
for (i = 0; i < FIRST_DIM; i++)
{
for (j = 0; j < SECOND_DIM; j++)
{
free(*(*(pppArr + i) + j));
}
}
for (i = 0; i < FIRST_DIM; i++)
{
printf("%p\n", *(pppArr + i));
free(*(pppArr + i));
}
free(pppArr);
system("pause");
return 0;
}
/* This function gets values for the given array from the user */
void getNums(float* pArr)
{
unsigned int i = 0;
for (i = 0; i < TOTAL; i++)
{
printf("Enter Number %d: ", i);
scanf("%f", pArr + i);
getchar();
}
}
/* This function prints out the given array */
void printArr(float* pArr)
{
unsigned int i = 0;
for (i = 0; i < TOTAL; i++)
{
printf("Number %d: %.2f\n", i, *(pArr + i));
}
}
/* This function sorts the given array from lowest to highest*/
void sortArr(float* pArr)
{
unsigned int i = 0, j = 0;
float temp = 0;
for (i = 0; i < TOTAL; i++)
{
for (j = 0; j < TOTAL - 1; j++)
{
if (*(pArr + j) > *(pArr + j + 1))
{
temp = *(pArr + j);
*(pArr + j) = *(pArr + j + 1);
*(pArr + j+ 1) = temp;
}
}
}
}
is there something im missing?
When you use pointers and dynamic allocation, the memory you allocate will most likely not be contiguous, but you will get separate memory areas for each allocation. That means when you treat it as one large contiguous memory area in your functions you exhibit undefined behavior.
An actual array, like
float arr[FIRST_DIM][SECOND_DIM][THIRD_DIM];
Now that will be contiguous.
See e.g. this old answer of mine for a more "graphical" explanation of the difference between arrays of arrays, and pointers to pointers.
This code is indexing out of bounds rather severely. The memory allocated for pppArr has three levels of indirection. It is not a multi-dimensional array (i.e., not an array of arrays), but is a pointer to an array of pointers to arrays of pointers. Three levels of indirection. There are 6 separate float slices, each with 2 contiguous elements (i.e., THIRD_DIM).
When calling getNums, sortArr, and printArr, you are passing **pppArr. This is equivalent to passing pppArr[0][0], which points to a single 2-element sequence of float values. The functions may only access THIRD_DIM elements, i.e. 2. Instead, they are trying to access 12 elements (i.e., TOTAL), which of course corrupts memory and leads to undefined behavior.
As far as I can tell, it looks like you're trying to access the storage as a single one-dimensional array. If so, then the easiest way to fix it is to eliminate 2 levels of indirection, and get rid of FIRST_DIM, SECOND_DIM, and THIRD_DIM, and just allocate a single, flat array with LENGTH elements. The pointer would have type float *.

C Allocating array of 500 and more longs

So.. I have something like this. It is supposed to create arrays with 10, 20, 50 100 .. up to 5000 random numbers that then sorts with Insertion Sort and prints out how many comparisions and swaps were done .. However, I am getting a runtime exception when I reach 200 numbers large array .. "Access violation writing location 0x00B60000." .. Sometimes I don't even reach 200 and stop right after 10 numbers. I have literally no idea.
long *arrayIn;
int *swap_count = (int*)malloc(sizeof(int)), *compare_count = (int*)malloc(sizeof(int));
compare_count = 0;
swap_count = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
compare_count = 0;
swap_count = 0;
free(arrayIn);
}
}
}
EDIT: ok with this free(arrayIn); I get this " Stack cookie instrumentation code detected a stack-based buffer overrun." and I get nowhere. However without it it's "just" "Access violation writing location 0x00780000." but i get up to 200numbers eventually
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
arr[i] = (RAND_MAX + 1)*rand() + rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
I am sure your compiler told you what was wrong.
You are passing a long** to a function that expects a int* at the line
fill_array(&arrayIn, n);
function prototype is
void fill_array(int *arr, int n)
Same problem with the other function. From there, anything can happen.
Always, ALWAYS heed the warnings your compiler gives you.
MAJOR EDIT
First - yes, the name of an array is already a pointer.
Second - declare a function prototype at the start of your code; then the compiler will throw you helpful messages which will help you catch these
Third - if you want to pass the address of a simple variable to a function, there is no need for a malloc; just use the address of the variable.
Fourth - the rand() function returns an integer between 0 and RAND_MAX. The code
a[i] = (RAND_MAX + 1) * rand() + rand();
is a roundabout way of getting
a[i] = rand();
since (RAND_MAX + 1) will overflow and give you zero... If you actually wanted to be able to get a "really big" random number, you would have to do the following:
1) make sure a is a long * (with the correct prototypes etc)
2) convert the numbers before adding / multiplying:
a[i] = (RAND_MAX + 1L) * rand() + rand();
might do it - or maybe you need to do some more casting to (long); I can never remember my order of precedence so I usually would do
a[i] = ((long)(RAND_MAX) + 1L) * (long)rand() + (long)rand();
to be 100% sure.
Putting these and other lessons together, here is an edited version of your code that compiles and runs (I did have to "invent" a print_array) - I have written comments where the code needed changing to work. The last point above (making long random numbers) was not taken into account in this code yet.
#include <stdio.h>
#include <stdlib.h>
// include prototypes - it helps the compiler flag errors:
void fill_array(int *arr, int n);
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count);
void print_array(int *arr, int n, int *swap_count, int *compare_count);
int main(void) {
// change data type to match function
int *arrayIn;
// instead of mallocing, use a fixed location:
int swap_count, compare_count;
// often a good idea to give your pointers a _p name:
int *swap_count_p = &swap_count;
int *compare_count_p = &compare_count;
// the pointer must not be set to zero: it's the CONTENTs that you set to zero
*compare_count_p = 0;
*swap_count_p = 0;
int i, j;
for (j = 10; j <= 1000; j*=10) {
for (i = 1; i <= 5; i++){
if (i == 1 || i == 2 || i == 5) {
int n = i * j;
arrayIn = malloc(sizeof(long)*n);
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count_p, compare_count_p);
print_array(arrayIn, n, swap_count_p, compare_count_p);
swap_count = 0;
compare_count = 0;
free(arrayIn);
}
}
}
return 0;
}
void fill_array(int *arr, int n) {
int i;
for (i = 0; i < n; i++) {
// arr[i] = (RAND_MAX + 1)*rand() + rand(); // causes integer overflow
arr[i] = rand();
}
}
void InsertionSort(int *arr, int n, int *swap_count, int *compare_count) {
int i, j, t;
for (j = 0; j < n; j++) {
(*compare_count)++;
t = arr[j];
i = j - 1;
*swap_count = *swap_count + 2;
while (i >= 0 && arr[i]>t) { //tady chybí compare_count inkrementace
*compare_count = *compare_count + 2;
arr[i + 1] = arr[i];
(*swap_count)++;
i--;
(*swap_count)++;
}
arr[i + 1] = t;
(*swap_count)++;
}
}
void print_array(int *a, int n, int* sw, int *cc) {
int ii;
for(ii = 0; ii < n; ii++) {
if(ii%20 == 0) printf("\n");
printf("%d ", a[ii]);
}
printf("\n\nThis took %d swaps and %d comparisons\n\n", *sw, *cc);
}
You are assigning the literal value 0 to some pointers. You are also mixing "pointers" with "address-of-pointers"; &swap_count gives the address of the pointer, not the address of its value.
First off, no need to malloc here:
int *swap_count = (int*)malloc(sizeof(int)) ..
Just make an integer:
int swap_coint;
Then you don't need to do
swap_coint = 0;
to this pointer (which causes your errors). Doing so on a regular int variable is, of course, just fine.
(With the above fixed, &swap_count ought to work, so don't change that as well.)
As I told in the comments, you are passing the addresses of pointers, which point to an actual value.
With the ampersand prefix (&) you are passing the address of something.
You only use this when you pass a primitive type.
E.g. filling the array by passing an int. But you are passing pointers, so no need to use ampersand.
What's actually happening is that you are looking in the address space of the pointer, not the actual value the pointer points to in the end. This causes various memory conflicts.
Remove all & where you are inputting pointers these lines:
fill_array(&arrayIn, n);
InsertionSort(&arrayIn, n, &swap_count, &compare_count);
print_array(&arrayIn, n, &swap_count, &compare_count);
So it becomes:
fill_array(arrayIn, n);
InsertionSort(arrayIn, n, swap_count, compare_count);
print_array(arrayIn, n, swap_count, compare_count);
I also note that you alloc memory for primitive types, which could be done way simpler:
int compare_count = 0;
int swap_count = 0;
But if you choose to use the last block of code, DO use &swap_count and &compare_count since you are passing primitive types, not pointers!

Assign Memory to 3D array using triple pointer

I have to assign memory to a 3D array using a triple pointer.
#include <stdio.h>
int main()
{
int m=10,n=20,p=30;
char ***z;
z = (char***) malloc(sizeof(char**)*m*n*p);
return 0;
}
Is this correct way of doing this?(I think what i am doing is incorrect.)
To completely allocate a 3D dynamic array you need to do something like the following:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int m=10,n=20,p=30;
char ***z;
z = malloc(m * sizeof(char **));
assert(z != NULL);
for (i = 0; i < m; ++i)
{
z[i] = malloc(n * sizeof(char *));
assert(z[i] != NULL);
for (j = 0; j < n; ++j)
{
z[i][j] = malloc(p);
assert(z[i][j] != NULL);
}
}
return 0;
}
Freeing the data is left as an exercise for the reader.
There's no need to cast the return value of malloc(), in C.
And if you expect to store m * n * p characters directly (and compute the address yourself), then you should of course not scale the allocation by the size of a char **.
You mean:
int m = 10, n = 20, p = 30;
char *z = malloc(m * n * p * sizeof *z);
This will allocate 10 * 20 * 30 = 6000 bytes. This can be viewed as forming a cube of height p, with each "slice" along the vertical axis being n * m bytes.
Since this is for manual addressing, you cannot use e.g. z[k][j][i] to index, instead you must use z[k * n * m + j * m + i].
If you don't need the memory to be allocated in a single, contiguous chunk (which IME is the usual case), you would do something like this:
char ***z;
z = malloc(sizeof *z * m); // allocate m elements of char **
if (z)
{
int i;
for (i = 0; i < m; i++)
{
z[i] = malloc(sizeof *z[i] * n); // for each z[i],
if (z[i]) // allocate n elements char *
{
int j;
for (j = 0; j < n;j++)
{
z[i][j] = malloc(sizeof *z[i][j] * p); // for each z[i][j],
if (z[i][j]) // allocate p elements of char
{
// initialize each of z[i][j][k]
}
}
}
}
}
Note that you will need to free this memory in reverse order:
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
free(z[i][j];
free(z[i]);
}
free(z);
If you really need the memory to be allocated in a contiguous chunk, you have a couple of choices. You could allocate a single block and compute your offsets manually:
char *z = malloc(sizeof *z * m * n * p); // note type of z!
...
z[i * m + j * n + k] = some_value();
When you're done, you just need to do a single free:
free(z);
If you have a C99 compiler or a C11 compiler that supports variable-length arrays, you could do something like this:
int m=..., n=..., p=...;
char (*z)[n][p] = malloc(sizeof *z * m);
This declares z as a pointer to an nxp array of char, and we allocate m such elements. The memory is allocated contiguously and you can use normal 3-d array indexing syntax (z[i][j][k]). Like the above method, you only need a single free call:
free(z);
If you don't have a C99 compiler or a C11 compiler that supports VLAs, you would need to make n, and p compile-time constants, such as
#define n 20
#define p 30
otherwise that last method won't work.
Edit
m doesn't need to be a compile-time constant in this case, just n and p.
You would need the following nested loop -
z = (char**)malloc(sizeof(char*) * m);
for (int i = 0; i < m; ++i)
{
*(z + i) = (char*)malloc(sizeof(char*) * n);
for (int j = 0; j < n; ++j)
{
*(*(z + i)) = (char)malloc(p);
}
}
May not be synactically accurate, but it should be something along these lines.
You want sizeof(char) not sizeof(char**) as the latter will give you the size of a pointer which on most modern systems will be 4 bytes instead of the 1 you're expecting.

How do we allocate a 2-D array using One malloc statement

I have been asked in an interview how do i allocate a 2-D array and below was my solution to it.
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
}
I thought I had done a good job but then he asked me to do it using one malloc() statement not two. I don't have any idea how to achieve it.
Can anyone suggest me some idea to do it in single malloc()?
Just compute the total amount of memory needed for both nrows row-pointers, and the actual data, add it all up, and do a single call:
int **array = malloc(nrows * sizeof *array + (nrows * (ncolumns * sizeof **array));
If you think this looks too complex, you can split it up and make it a bit self-documenting by naming the different terms of the size expression:
int **array; /* Declare this first so we can use it with sizeof. */
const size_t row_pointers_bytes = nrows * sizeof *array;
const size_t row_elements_bytes = ncolumns * sizeof **array;
array = malloc(row_pointers_bytes + nrows * row_elements_bytes);
You then need to go through and initialize the row pointers so that each row's pointer points at the first element for that particular row:
size_t i;
int * const data = array + nrows;
for(i = 0; i < nrows; i++)
array[i] = data + i * ncolumns;
Note that the resulting structure is subtly different from what you get if you do e.g. int array[nrows][ncolumns], because we have explicit row pointers, meaning that for an array allocated like this, there's no real requirement that all rows have the same number of columns.
It also means that an access like array[2][3] does something distinct from a similar-looking access into an actual 2d array. In this case, the innermost access happens first, and array[2] reads out a pointer from the 3rd element in array. That pointer is then treatet as the base of a (column) array, into which we index to get the fourth element.
In contrast, for something like
int array2[4][3];
which is a "packed" proper 2d array taking up just 12 integers' worth of space, an access like array[3][2] simply breaks down to adding an offset to the base address to get at the element.
int **array = malloc (nrows * sizeof(int *) + (nrows * (ncolumns * sizeof(int)));
This works because in C, arrays are just all the elements one after another as a bunch of bytes. There is no metadata or anything. malloc() does not know whether it is allocating for use as chars, ints or lines in an array.
Then, you have to initialize:
int *offs = &array[nrows]; /* same as int *offs = array + nrows; */
for (i = 0; i < nrows; i++, offs += ncolumns) {
array[i] = offs;
}
Here's another approach.
If you know the number of columns at compile time, you can do something like this:
#define COLS ... // integer value > 0
...
size_t rows;
int (*arr)[COLS];
... // get number of rows
arr = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < COLS; j++)
arr[i][j] = ...;
}
If you're working in C99, you can use a pointer to a VLA:
size_t rows, cols;
... // get rows and cols
int (*arr)[cols] = malloc(sizeof *arr * rows);
if (arr)
{
size_t i, j;
for (i = 0; i < rows; i++)
for (j = 0; j < cols; j++)
arr[i][j] = ...;
}
How do we allocate a 2-D array using One malloc statement (?)
No answers, so far, allocate memory for a true 2D array.
int **array is a pointer to pointer to int. array is not a pointer to a 2D array.
int a[2][3] is an example of a true 2D array or array 2 of array 3 of int
To allocate memory for a true 2D array, with C99, use malloc() and save to a pointer to a variable-length array (VLA)
// Simply allocate and initialize in one line of code
int (*c)[nrows][ncolumns] = malloc(sizeof *c);
if (c == NULL) {
fprintf(stderr, "out of memory\n");
return;
}
// Use c
(*c)[1][2] = rand();
...
free(c);
Without VLA support, if the dimensions are constants, code can use
#define NROW 4
#define NCOL 5
int (*d)[NROW][NCOL] = malloc(sizeof *d);
You should be able to do this with (bit ugly with all the casting though):
int** array;
size_t pitch, ptrs, i;
char* base;
pitch = rows * sizeof(int);
ptrs = sizeof(int*) * rows;
array = (int**)malloc((columns * pitch) + ptrs);
base = (char*)array + ptrs;
for(i = 0; i < rows; i++)
{
array[i] = (int*)(base + (pitch * i));
}
I'm not a fan of this "array of pointers to array" to solve the multi dimension array paradigm. Always favored a single dimension array, at access the element with array[ row * cols + col]? No problems encapsulating everything in a class, and implementing a 'at' method.
If you insist on accessing the members of the array with this notation: Matrix[i][j], you can do a little C++ magic. #John solution tries to do it this way, but he requires the number of column to be known at compile time. With some C++ and overriding the operator[], you can get this completely:
class Row
{
private:
int* _p;
public:
Row( int* p ) { _p = p; }
int& operator[](int col) { return _p[col]; }
};
class Matrix
{
private:
int* _p;
int _cols;
public:
Matrix( int rows, int cols ) { _cols=cols; _p = (int*)malloc(rows*cols ); }
Row operator[](int row) { return _p + row*_cols; }
};
So now, you can use the Matrix object, for example to create a multiplication table:
Matrix mtrx(rows, cols);
for( i=0; i<rows; ++i ) {
for( j=0; j<rows; ++j ) {
mtrx[i][j] = i*j;
}
}
You should now that the optimizer is doing the right thing and there is no call function or any other kind of overhead. No constructor is called. As long as you don't move the Matrix between function, even the _cols variable isn't created. The statement mtrx[i][j] basically does mtrx[i*cols+j].
It can be done as follows:
#define NUM_ROWS 10
#define NUM_COLS 10
int main(int argc, char **argv)
{
char (*p)[NUM_COLS] = NULL;
p = malloc(NUM_ROWS * NUM_COLS);
memset(p, 81, NUM_ROWS * NUM_COLS);
p[2][3] = 'a';
for (int i = 0; i < NUM_ROWS; i++) {
for (int j = 0; j < NUM_COLS; j++) {
printf("%c\t", p[i][j]);
}
printf("\n");
}
} // end of main
You can allocate (row*column) * sizeof(int) bytes of memory using malloc.
Here is a code snippet to demonstrate.
int row = 3, col = 4;
int *arr = (int *)malloc(row * col * sizeof(int));
int i, j, count = 0;
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
*(arr + i*col + j) = ++count; //row major memory layout
for (i = 0; i < r; i++)
for (j = 0; j < c; j++)
printf("%d ", *(arr + i*col + j));

dynamic allocating array of arrays in C

I don't truly understand some basic things in C like dynamically allocating array of arrays.
I know you can do:
int **m;
in order to declare a 2 dimensional array (which subsequently would be allocated using some *alloc function). Also it can be "easily" accessed by doing *(*(m + line) + column). But how should I assign a value to an element from that array? Using gcc the following statement m[line][column] = 12; fails with a segmentation fault.
Any article/docs will be appreciated. :-)
The m[line][column] = 12 syntax is ok (provided line and column are in range).
However, you didn't write the code you use to allocate it, so it's hard to get whether it is wrong or right. It should be something along the lines of
m = (int**)malloc(nlines * sizeof(int*));
for(i = 0; i < nlines; i++)
m[i] = (int*)malloc(ncolumns * sizeof(int));
Some side-notes:
This way, you can allocate each line with a different length (eg. a triangular array)
You can realloc() or free() an individual line later while using the array
You must free() every line, when you free() the entire array
Your syntax m[line][colummn] is correct. But in order to use a 2D array in C, you must allocate memory for it. For instance this code will allocated memory for a table of given line and column.
int** AllocateArray(int line, int column) {
int** pArray = (int**)malloc(line*sizeof(int*));
for ( int i = 0; i < line; i++ ) {
pArray[i] = (int*)malloc(column*sizeof(int));
}
return pArray;
}
Note, I left out the error checks for malloc for brevity. A real solution should include them.
It's not a 2d array - it's an array of arrays - thus it needs the multiple allocations.
Here's a modified version of quinmars' solution which only allocates a single block of memory and can be used with generic values by courtesy of void *:
#include <stdlib.h>
#include <string.h>
#include <assert.h>
void ** array2d(size_t rows, size_t cols, size_t value_size)
{
size_t index_size = sizeof(void *) * rows;
size_t store_size = value_size * rows * cols;
char * a = malloc(index_size + store_size);
if(!a) return NULL;
memset(a + index_size, 0, store_size);
for(size_t i = 0; i < rows; ++i)
((void **)a)[i] = a + index_size + i * cols * value_size;
return (void **)a;
}
int printf(const char *, ...);
int main()
{
int ** a = (int **)array2d(5, 5, sizeof(int));
assert(a);
a[4][3] = 42;
printf("%i\n", a[4][3]);
free(a);
return 0;
}
I'm not sure if it's really safe to cast void ** to int ** (I think the standard allows for conversions to take place when converting to/from void * ?), but it works in gcc. To be on the safe side, you should replace every occurence of void * with int * ...
The following macros implement a type-safe version of the previous algorithm:
#define alloc_array2d(TYPE, ROWS, COLS) \
calloc(sizeof(TYPE *) * ROWS + sizeof(TYPE) * ROWS * COLS, 1)
#define init_array2d(ARRAY, TYPE, ROWS, COLS) \
do { for(int i = 0; i < ROWS; ++i) \
ARRAY[i] = (TYPE *)(((char *)ARRAY) + sizeof(TYPE *) * ROWS + \
i * COLS * sizeof(TYPE)); } while(0)
Use them like this:
int ** a = alloc_array2d(int, 5, 5);
init_array2d(a, int, 5, 5);
a[4][3] = 42;
Although I agree with the other answers, it is in most cases better to allocate the whole array at once, because malloc is pretty slow.
int **
array_new(size_t rows, size_t cols)
{
int **array2d, **end, **cur;
int *array;
cur = array2d = malloc(rows * sizeof(int *));
if (!array2d)
return NULL;
array = malloc(rows * cols * sizeof(int));
if (!array)
{
free(array2d);
return NULL;
}
end = array2d + rows;
while (cur != end)
{
*cur = array;
array += cols;
cur++;
}
return array2d;
}
To free the array simply do:
free(*array); free(array);
Note: this solution only works if you don't want to change the order of the rows, because you could then lose the address of the first element, which you need to free the array later.
Humm. How about old fashion smoke and mirrors as an option?
#define ROWS 5
#define COLS 13
#define X(R, C) *(p + ((R) * ROWS) + (C))
int main(void)
{
int *p = (int *) malloc (ROWS * COLS * sizeof(int));
if (p != NULL)
{
size_t r;
size_t c;
for (r = 0; r < ROWS; r++)
{
for (c = 0; c < COLS; c++)
{
X(r,c) = r * c; /* put some silly value in that position */
}
}
/* Then show the contents of the array */
for (r = 0; r < ROWS; r++)
{
printf("%d ", r); /* Show the row number */
for (c = 0; c < COLS; c++)
{
printf("%d", X(r,c));
}
printf("\n");
}
free(p);
}
else
{
/* issue some silly error message */
}
return 0;
}
Using malloc(3) for allocate the first array and putting in there pointers created by malloc(3) should work with array[r][c] because it should be equivalent to *(*(array + r) + c), it is in the C standard.

Resources