C pass variable size 2-D array to function - c

I'm trying to refactor my code to make it better/more readable so I'm trying change a 2-D variable array allocation as follows
// OLD CODE
int **map;
map = calloc(number, sizeof(int *));
if (!(map)) {
free(map);
return 1;
}
for (int i = 0; i < number; i++) {
map[i] = calloc(number, sizeof(int));
if (!(map[i])) {
while (--i >= 0) {
free(map[i]);
}
free(map);
return 1;
}
}
// NEW CODE
int (*map)[number] = malloc(sizeof (int[number][number]));
if (!(map)){
free(map);
return 1;
}
The problem is that all my functions that use map take int **map and by changing the declaration of map like i did the IDE tells me incorrect type int[]* instead of int**
What should i use instead of int**? Using int[]* map in the function declaration tells me can't resolve variable map

Turns out the below code is not a C99 alternative #M.M, but a GCC extension.
Undocumented GCC Extension: VLA in struct
As a C99 GCC extension alternative to int (*map)[number] = malloc(sizeof (int[number][number])); for code simplification and maintain compatibility with existing function set, allocate all the memory needed with 1 *alloc() call.
This does require that when code is done with the map, all the memory is free'd with one free(map). Further, individual rows of map[] can no longer be re-allocated, but can be swapped within the map[].
int **map_allocate(size_t row, size_t column) {
struct {
int *ip[row]; // Array of pointers, followed by a ...
int i[row][column]; // 2D array of int
} *u;
u = calloc(1, sizeof *u);
if (u == NULL) {
return NULL;
}
for (size_t i = 0; i<row; i++) {
u->ip[i] = u->i[row];
}
return &u->ip[0];
}
Note: no casting and field i[][] is properly aligned.

To use one allocation with standard code, unlike the other answer, is a bit trickier as one needs to insure that a combined memory allocation of pointers and int needs to meet alignment concerns in the unusual case of int alignment requirements exceed pointer alignment ones. This is more easily shown with long long as below.
If this makes "code easier to read" is left to OP's judgment.
#include <stdlib.h>
#include <stdio.h>
long long **map_allocate_ll(size_t row, size_t column) {
long long **map;
long long *ints;
size_t pointers_sz = sizeof *map * row;
// extend pointer size to `*ints` boundary
pointers_sz = (pointers_sz + sizeof *ints - 1)/sizeof *ints * sizeof *ints;
size_t ints_sz = sizeof *ints * row * column;
printf("psize %zu, isize %zu\n", pointers_sz, ints_sz);
map = calloc(1, pointers_sz + ints_sz);
if (map == NULL) {
return NULL;
}
ints = (void*) ((char*) map + pointers_sz);
printf("map %p\n", (void *) map);
for (size_t i = 0; i<row; i++) {
map[i] = &ints[i * column];
printf("map[%zu] %p\n", i, (void *) map[i]);
}
return map;
}
int main() {
free(map_allocate_ll(5,3));
}
Sample output
psize 24, isize 120
map 0x80081868
map[0] 0x80081880
map[1] 0x80081898
map[2] 0x800818b0
map[3] 0x800818c8
map[4] 0x800818e0

Related

Creating and returning multi-dimensional arrays

I read on some ways to dynamically create and use a 2D array, and I've settled on this way:
file:
5 4
+---+
|xxx|
|xxx|
+---+
main.c:
char** loadArray() {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w &h);
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose();
return buf;
}
int main() {
char** array = loadArray();
for (int i = 0; i < 4; i++) { // magic number, only because I know the size
printf("%s\n", array[i]);
}
return 0;
}
While this does compile, it gives a warning: incompatible pointer types returning 'char (*)[w]' from a function with result type 'char **', and segfaults if I try to run it.
Several questions (mainly for C, but C++ specific answers are welcome for future reference, when I get there):
What is the correct return type for a multidimensional array? The warning isn't quite helpful I think, since it offers a variable term, which I obviously don't have until I read the file.
At this point, I'm just trying to get returning 2D arrays to work, but when I do and move on, I'm going to need the dimensions of the array for proper usage later on. My first idea would be to return structs instead, where I can save the dimension and the array itself. However, after further thought, the variable size makes me think that I wouldn't be able to have a single struct template to use as the function's return type, and I would have to find some other way to get the size along with the array. Are ideas?
Thank you for your time.
Pointer to pointer and pointer to array are quite different things. You can't return the array dimension as such in the return type so you'd have to use an incomplete array:
char (*(loadArray()))[] {
...
}
Evidently this is not very readable so you'd better pass through a typedef:
typedef char line[];
line* loadArray() {
...
}
You'd also have to get your hands on the dimensions w and h, so you'd have to pass pointers to the values as arguments. But that would be another question.
What is the correct return type for a multidimensional array?
There is no "correct" type, it all depends on how you want to represent the data and what architecture you want to design.
The warning isn't quite helpful I think, since it offers a variable term
The warning is very helpful, because it indicates an error in the code - you are casting a pointer to an array to a pointer to a pointer. Ignoring that warning ultimately leads to printf("%s\n", array[i]); which is undefined behavior.
Are ideas?
You may return a pointer to a dynamically allocated array of pointers to dynamically allocated array of values.
char **loadArray(void) {
size_t w, h;
// Initialize w and h.
char **arr;
arr = malloc(w * sizeof(*arr));
if (!arr) return NULL;
for (size_t i = 0; i < w; ++i) {
arr[i] = malloc(h * sizeof(*arr[i]));
if (!arr[i]) {
for (size_t j = 0; j < i; ++j) {
free(arr[j]);
}
frer(arr);
return NULL;
}
}
// Fill arr from file. Handle errors. Handle deallocation.
return arr;
}
which is the usual way to program in C and one would expect char ** to act that way. I can thing of an example from POSIX , where scandir function takes a pointer to a double pointer struct dirent ***namelist argument which is assigned to a such dynamically allocated 2d array.
But let's take a bit over-engineered (or not) design (in mostly C-ish pseudocode):
// represents the thing
struct thething_s {
char *string;
};
int thething_print(struct thething_s *t, FILE *f) {
return fprintf(f, ....);
}
void thething_free(struct thething_s *t) {
free(t->string);
}
int thething_load_from_file(struct thething_s *t, FILE *f, size_t len) {
t->string = malloc(len);
if (!t->string) return -1;
if (scanf(....) != 1) return -2;
return 0;
}
// represents an array of things
struct thingsarr_s {
struct thethings_s *things;
size_t w;
size_t h;
};
int thigsarr_load_from_file(struct thingsarr_s *t, FILE *f) {
// Initialize t->w and t->h.
t->things = malloc(t->w * sizeof(*t->things));
if (!arr) return -1;
for (size_t i = 0; i < w; ++i) {
if (thething_load_from_file(&t->things[i], f, t->h) != 0) {
for (size_t j = 0; j < i; ++j) {
thethings_free(t->things[j]);
}
free(t->things);
return -1000 - i;
}
}
return 0;
}
const struct thething_s *thingsarr_get_thing(const struct thingsarr_s *t, size_t idx)
{
assert(idx < t->len);
return t->things[idx];
}
struct thething_s *thingsarr_get_thing_nonconst(struct thingsarr_s *t, size_t idx) {
return (struct thething_s *)thingsarr_get_thing(t, idx);
}
void thingsarr_free(struct thingsarr_s *t) {
for (.,.) {
thething_free(&t->things[i]);
}
free(t->things);
}
Which is "best" strongly depends on the context, specific needs and specific application.
The pointer types char ** and char (*)[w] are very different. There is a common misconception that arrays and pointers are the same thing in C, but that is not the case.
You want the return type of the function to be char (*)[w], but that return type is impossible to declare because w is an unknown value. Also, the caller doesn't know the width and height of the returned array, because that information is internal to the loadArray function.
Setting the return type of the loadArray function to void* allows it to just return a pointer to the array without knowing the width or height. The width and height values can be sent to the caller using pointer arguments so that the caller can reconstruct the array type.
The following modifications of the original C code implements the above change. (C++ does not support variable length array types as far as I know, so this is C only.)
#include <stdio.h>
#include <stdlib.h>
void* loadArray(int *pw, int *ph) {
FILE *in = fopen("file", "r");
int w, h;
fscanf(in, "%d %d\n", &w, &h);
*pw = w;
*ph = h;
char (*buf)[w] = malloc(sizeof(char[h][w]));
for (int i = 0; i < h; i++) {
fscanf(in, "%s\n", buf[i]);
}
fclose(in);
return buf;
}
int main(void) {
int w, h;
void* larray = loadArray(&w, &h);
char(*array)[w] = larray;
for (int i = 0; i < h; i++) {
printf("%s\n", array[i]);
}
return 0;
}

How to initialize multiple arrays with unknown sizes via a function in C

I have a program in C, in which I initialize multiple number of arrays each with a bunch of lines. However, i'd like to avoid that since it increases the length of my main function. For example I have this;
int * pickup_Ind;
double *pickup_Val;
pickup_Ind = (int *) malloc(sizeof(int) * (size1));
pickup_Val = (double *) malloc(sizeof(double) * (size1));
int * lInd;
double *lVal;
lInd = (int *) malloc(sizeof(int) * size2);
lVal = (double *) malloc(sizeof(double) * size2);
int * simul_Ind;
double *simul_Val;
simul_Ind = (int *) malloc(sizeof(int) * (size3));
simul_Val = (double *) malloc(sizeof(double) * (size3));
I know I can reduce the number of lines by for example writing as:
int * pickup_Ind = (int *) malloc(sizeof(int) * (size1));
But still i will need to do this for every array. How to write this in a compact form with a function (which i will store in a header file), and then call this function from main. Not to mention i do not want to declare them as global variables, but to be able to use them in main. I tried the function below.
void initialize_bounds(int *arr1,int size1)
{
arr1= (int *) malloc(sizeof(int) * (size1));
for(int i=0;i<size1;i++)
arr1[i]=i;
}
But if i call this function via the following in main, i get error "Varuable test being used without initialized"
int* test;
initialize_bounds(test);
So to sum up, if i could write something like this, my problem is solved:
int *pickup_Ind,*pickup_Val,*lind,*lval;
int size1,size2;
initalize_bounds(pickup_Ind,pickup_Val,size1,size2);
You could write a function
void initialize_bounds(int **ind, double **val, int size) {
*ind = malloc(sizeof (**ind)*size);
for (int i = 0; i < size; i++) {
(*ind)[i] = i;
}
*val = malloc(sizeof (**val)*size);
}
and call it like
int * pickup_Ind;
double *pickup_Val;
initialize_bounds(&pickup_Ind, &pickup_Val, size1);
to initialize both arrays in one line. You still have to place one call to it per array-pair, however.
In the C language, arguments are passed to functions by value - so, actually, a copy is made and the original variable (in the calling code) cannot be changed. So, if you want a function to modify (say) an int argument, you pass it a pointer to that int.
Likewise, if you want a function to modify a pointer, you have to pass a pointer to that pointer.
So, in the case of the initialize_bounds function you have shown, you would need this:
void initialize_bounds(int** arr1,int size1) // 1st arg is a pointer to the pointer!
{
*arr1 = (int *) malloc(sizeof(int) * (size1)); // De-reference our `arr1` pointer
for(int i=0;i<size1;i++)
(*arr1)[i]=i;
}
Then, you can use this to initialize a pointer in your main function with a call like this:
int* test;
initialize_bounds(&test); // We need to pass the ADDRESS of the pointer we want to modify!
You can write a function that returns a freshly allocated and initialized array.
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
/* Header file */
int* AllocateArray(size_t size);
void DeallocateArray(int *array);
int main(void) {
const size_t size = 10;
int *const array = AllocateArray(size);
for (size_t i = 0; i < size; ++i) {
printf("%d ", array[i]);
}
printf("\n");
DeallocateArray(array);
return 0;
}
/* Implementation */
int* AllocateArray(size_t size) {
int *const array = malloc(size * sizeof(int));
if (array == NULL) {
// Allocation failed, handle it...
}
for (size_t i = 0; i < size; ++i) {
array[i] = i;
}
return array;
}
void DeallocateArray(int *array) {
if (array == NULL) {
return;
}
free(array);
}
I'd use something higher level, e.g. stretchy buffers. See this video for a live coding session that implements those - props to Per Vognsen for making this code, and for placing into public domain (i.e. completely free to use for any purpose, but I'm not a lawyer, so take anything I say with caution :).
You'd want to include bitwise/ion/common.c in your source file, and then the array allocation becomes simple. Stretchy buffers are perhaps the closest you get to the convenience of C++'s std::vector in C. They offer an API that doesn't feel like a C++ API transcribed in C - it is at the correct level, and lets you use plain pointers in a very sensible way (e.g. a buf_len of a NULL pointer is zero, not a crash, buf_push(mybuf, element) appends an element to the array and extends it if necessary, etc.
#include <assert.h>
#include <string.h>
#include <stdlib.h>
// note that common.c includes nothing, so you have to set it up
#include "common.c"
#define buf_resize(b, n) ((n) <= buf_len(b) ? (b) : (((b) = buf__grow((b), (n), sizeof(*(b)), 0)), ((b) ? buf__hdr((b))->len = (n) : 0), (b)))
typedef struct {
int * pickup_Ind;
double *pickup_Val;
int * lInd;
double *lVal;
int * simul_Ind;
double *simul_Val;
} Data;
enum {
size1 = ...,
size2 = ...,
size3 = ...
}
Data make_Data(void) {
Data d;
memset(&d, 0, sizeof(d));
assert(buf_len(d->pickup_Ind) == 0);
buf_resize(d.pickup_Ind, size1);
buf_resize(d.pickup_Val, size1);
buf_resize(d.lInd, size2);
buf_resize(d.lVal, size2);
buf_resize(d.simul_Ind, size3);
buf_resize(d.simul_Val, size3);
}
int main(int argc, char **argv) {
Data d = make_Data();
assert(buf_len(d.pickup_Ind) == size1);
d.pickup_Ind[0] = 10;
assert(buf_len(d.pickup_Ind) == size1);
buf_push(d.pickup_Ind, 11);
assert(buf_len(d.pickup_Ind) == size1 + 1);
}
If you're building up the arrays by adding elements to them one-by-one, it'll make sense to reserve the capacity for the expected size of the array via buf_fit (it only reserves the memory but the buffer retains its length (e.g. zero)). The capacity reservation is entirely optional, though. It's there to prevent reallocation of the arrays while you add elements to them.
Thus:
Data make_Data(void) {
Data d;
memset(&d, 0, sizeof(d));
assert(buf_len(d->pickup_Ind) == 0);
buf_fit(d.pickup_Ind, size1);
buf_fit(d.pickup_Val, size1);
buf_fit(d.lInd, size2);
buf_fit(d.lVal, size2);
buf_fit(d.simul_Ind, size3);
buf_fit(d.simul_Val, size3);
}
int main(int argc, char **argv) {
Data d = make_Data();
assert(buf_len(d.pickup_Ind) == 0); // zero length: no data in the array (yet!)
assert(buf_cap(d.pickup_Ind) >= size1); // but it has the capacity we need
buf_push(d.pickup_Ind, 10);
buf_push(d.pickup_Ind, 11);
assert(buf_len(d.pickup_ind) == 2);
}
If you'll want to use stretchy buffers in multiple source files, you'll run afoul of the one declaration rule (ODR). Thus, you'll need to factor out macro definitions and function declarations out of common.c and into common.h.
If the Data is only allocated once, there's no need to free it prior to exiting the program: the operating system already does it for you. Otherwise, you may wish to add a function to do this job:
void free_Data(Data *d) {
buf_free(d.pickup_Ind);
buf_free(d.pickup_Val);
buf_free(d.lInd);
buf_free(d.lVal);
buf_free(d.simul_Ind);
buf_free(d.simul_Val);
assert(buf_len(d.pickup_Ind) == 0);
}

C: adding element to dynamically allocated array

I've tried to search out a solution via Google: I couldn't find anything that helped; it even seemed as if I was doing this correctly. The only pages I could find regarding sending my dynamically allocated array through a function dealt with the array being inside a struct, which is scalar of course, so behaves differently. I don't want to use a struct right now -- I'm trying to learn about DAM and working with pointers and functions.
That said, I'm sure it's very elementary, but I'm stuck. The code compiles, but it freezes up when I run the executable. (I'm using minGW gcc, if that matters. And I'm not clear at all, right now, on how to use gdb.)
Here's the code (eventually, I want the entire code to be an ArrayList-like data structure):
#include <stdio.h>
#include <stdlib.h>
void add( int element, int *vector);
void display_vector( int *vector );
void initialize_vector( int *vector );
int elements = 0;
int size = 10;
int main(void)
{
int *vector = 0;
initialize_vector(vector);
add(1, vector);
//add(2, vector);
//add(3, vector);
//add(4, vector);
//add(5, vector);
//add(6, vector);
//add(7, vector);
//add(8, vector);
//add(9, vector);
//add(10, vector);
//add(11, vector);
display_vector(vector);
return 0;
}
void add( int element, int *vector)
{
vector[elements++] = element;
return;
}
void display_vector( int *vector )
{
int i;
for( i = 0; i < elements; i++)
{
printf("%2d\t", vector[i]);
if( (i + 1) % 5 == 0 )
printf("\n");
}
printf("\n");
return;
}
void initialize_vector( int *vector )
{
vector = (int *)malloc(sizeof(int) * size);
}
Edited to make a little bit more clear.
The problem is your init routine is working with a copy of "vector" and is malloc'ing into that copy rather than the original vector pointer. You loose the pointer to the memory block on the return from the initialize.
Change parameter for vector to a handle (pointer to pointer) in this function
void initialize_vector( int **vector )
{
*vector = (int *)malloc(sizeof(int) * size);
}
Then change the call to init to this
initialize_vector(&vector);
I didn't compile this, but it should fix the code.
In C, function arguments are passed by value, which means there is a local copy for every arguments you passed to a function, if you change an argument in a function, you only change the local copy of that argument. So if you want to change the value of an argument in a function, you need to pass its address to that function, derefer that address and assign to the result in that function.
Enough for the theory, here is how to fix your code:
void initialize_vector( int **vector );
initialize_vector(&vector);
void initialize_vector( int **vector )
{
*vector = (int *)malloc(sizeof(int) * size);
}
In addition of other replies, I would suggest another approach.
Assuming at least C99 compliant compiler, I would rather suggest to keep the allocated size in a member of a structure ending with a flexible array member (see also this) like:
typedef struct vector_st {
unsigned count; // used length
unsigned size; // allocated size, always >= length
int vectarr[];
} Vector;
Then you would construct such a vector with
Vector* make_vector (unsigned size) {
Vector* v = malloc(sizeof(Vector)+size*sizeof(int));
if (!v) { perror("malloc vector"); exit (EXIT_FAILURE); };
memset (v->vectarr, 0, size*sizeof(int));
v->count = 0;
v->size = size;
}
To add an element into a vector, returning the original vector or a grown one:
Vector* append_vector (Vector*vec, int elem) {
assert (vec != NULL);
unsigned oldcount = vec->count;
if (oldcount < vec->size) {
vec->vectarr[vec->count++] = elem;
return vec;
} else {
unsigned newsize = ((4*oldcount/3)|7) + 1;
Vector* oldvec = vec;
vec = malloc(sizeof(Vector)+newsize*sizeof(int));
if (!vec) { perror("vector grow"); exit(EXIT_FAILURE); };
memcpy (vec->vectarr, oldvec->vectarr, oldcount*sizeof(int));
memset (vec->vectarr + oldcount, 0,
(newsize-oldcount) * sizeof(int));
vec->vectarr[oldcount] = elem;
vec->count = oldcount+1;
vec->size = newsize;
free (oldvec);
return vec;
}
}
and you could code:
Vector* myvec = make_vector(100);
myvec = append_vector(myvec, 35);
myvec = append_vector(myvec, 17);
for (int i=0; i<150; i++)
myvec = append_vector(myvec, i*2);
To release such a vector, just use free(myvec);
If you really don't want to use any struct you should keep in separate variables the used length of your vector, the allocated size of your vector, the pointer to your dynamically allocated array:
unsigned used_count; // useful "length"
unsigned allocated_size; // allocated size, always not less than used_count
int *dynamic_array; // the pointer to the dynamically allocated array
If you want to be able to manage several vectors, then either pack together the above useful length, allocated size and dynamic array into some struct dynamic_array_st (whose pointer you would pass to appropriate routines like make_dynamic_vector(struct dynamic_array_st*), append_dynamic_vector(struct dynamic_array_st*, int), etc ....) or else pass them as three separate formals to similar routines, and then you'll need to pass their address because the routines would change them, e.g. create_dynamic_vector(unsigned *countptr, unsigned *sizeptr, int**vectarrptr) that you would invoke as create_dynamic_vector(&mycount, &mysize, &myvectarr); etc.
I do think that a flexible array member is still the cleanest approach.

How to allocate and deallocate heap memory for 2D array?

I'm used to PHP, but I'm starting to learn C. I'm trying to create a program that reads a file line by line and stores each line to an array.
So far I have a program that reads the file line by line, and even prints each line as it goes, but now I just need to add each line to an array.
My buddy last night was telling me a bit about it. He said I'd have to use a multidimensional array in C, so basically array[x][y]. The [y] part itself is easy, because I know the maximum amount of bytes that each line will be. However, I don't know how many lines the file will be.
I figure I can make it loop through the file and just increment an integer each time and use that, but I feel that there might be a more simple way of doing it.
Any ideas or even a hint in the right direction? I appreciate any help.
To dynamically allocate a 2D array:
char **p;
int i, dim1, dim2;
/* Allocate the first dimension, which is actually a pointer to pointer to char */
p = malloc (sizeof (char *) * dim1);
/* Then allocate each of the pointers allocated in previous step arrays of pointer to chars
* within each of these arrays are chars
*/
for (i = 0; i < dim1; i++)
{
*(p + i) = malloc (sizeof (char) * dim2);
/* or p[i] = malloc (sizeof (char) * dim2); */
}
/* Do work */
/* Deallocate the allocated array. Start deallocation from the lowest level.
* that is in the reverse order of which we did the allocation
*/
for (i = 0; i < dim1; i++)
{
free (p[i]);
}
free (p);
Modify the above method. When you need another line to be added do *(p + i) = malloc (sizeof (char) * dim2); and update i. In this case you need to predict the max numbers of lines in the file which is indicated by the dim1 variable, for which we allocate the p array first time. This will only allocate the (sizeof (int *) * dim1) bytes, thus much better option than char p[dim1][dim2] (in c99).
There is another way i think. Allocate arrays in blocks and chain them when there is an overflow.
struct _lines {
char **line;
int n;
struct _lines *next;
} *file;
file = malloc (sizeof (struct _lines));
file->line = malloc (sizeof (char *) * LINE_MAX);
file->n = 0;
head = file;
After this the first block is ready to use. When you need to insert a line just do:
/* get line into buffer */
file.line[n] = malloc (sizeof (char) * (strlen (buffer) + 1));
n++;
When n is LINE_MAX allocate another block and link it to this one.
struct _lines *temp;
temp = malloc (sizeof (struct _lines));
temp->line = malloc (sizeof (char *) * LINE_MAX);
temp->n = 0;
file->next = temp;
file = file->next;
Something like this.
When one block's n becomes 0, deallocate it, and update the current block pointer file to the previous one. You can either traverse from beginning single linked list and traverse from the start or use double links.
There's no standard resizable array type in C. You have to implement it yourself, or use a third-party library. Here's a simple bare-bones example:
typedef struct int_array
{
int *array;
size_t length;
size_t capacity;
} int_array;
void int_array_init(int_array *array)
{
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_free(int_array *array)
{
free(array->array);
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_push_back(int_array *array, int value)
{
if(array->length == array->capacity)
{
// Not enough space, reallocate. Also, watch out for overflow.
int new_capacity = array->capacity * 2;
if(new_capacity > array->capacity && new_capacity < SIZE_T_MAX / sizeof(int))
{
int *new_array = realloc(array->array, new_capacity * sizeof(int));
if(new_array != NULL)
{
array->array = new_array;
array->capacity = new_capacity;
}
else
; // Handle out-of-memory
}
else
; // Handle overflow error
}
// Now that we have space, add the value to the array
array->array[array->length] = value;
array->length++;
}
Use it like this:
int_array a;
int_array_init(&a);
int i;
for(i = 0; i < 10; i++)
int_array_push_back(&a, i);
for(i = 0; i < a.length; i++)
printf("a[%d] = %d\n", i, a.array[i]);
int_array_free(&a);
Of course, this is only for an array of ints. Since C doesn't have templates, you'd have to either put all of this code in a macro for each different type of array (or use a different preprocessor such as GNU m4). Or, you could use a generic array container that either used void* pointers (requiring all array elements to be malloc'ed) or opaque memory blobs, which would require a cast with every element access and a memcpy for every element get/set.
In any case, it's not pretty. Two-dimensional arrays are even uglier.
Instead of an array here, you could also use a linked list, The code is simpler, but the allocation is more frequent and may suffer from fragmentation.
As long as you don't plan to do much random access (Which is O(n) here), iteration is about as simple as a regular array.
typedef struct Line Line;
struct Line{
char text[LINE_MAX];
Line *next;
};
Line *mkline()
{
Line *l = malloc(sizeof(Line));
if(!l)
error();
return l;
}
main()
{
Line *lines = mkline();
Line *lp = lines;
while(fgets(lp->text, sizeof lp->text, stdin)!=NULL){
lp->next = mkline();
lp = lp->next;
}
lp->next = NULL;
}
If you are using C you will need to implement the resizing of the array yourself. C++ and the SDL has this done for you. It is called a vector. http://www.cplusplus.com/reference/stl/vector/
While a multidimensional array can solve this problem, a rectangular 2D array would not really be the natural C solution.
Here is a program that initially reads the file into a linked list, and then allocates a vector of pointers of the right size. Each individual character does then appear as array[line][col] but in fact each row is only as long as it needs to be. It's C99 except for <err.h>.
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct strnode {
char *s;
struct strnode *next;
} strnode;
strnode *list_head;
strnode *list_last;
strnode *read1line(void) {
char space[1024];
if(fgets(space, sizeof space, stdin) == NULL)
return NULL;
strnode *node = malloc(sizeof(strnode));
if(node && (node->s = malloc(strlen(space) + 1))) {
strcpy(node->s, space);
node->next = NULL;
if (list_head == NULL)
list_head = node;
else
list_last->next = node;
list_last = node;
return node;
}
err(1, NULL);
}
int main(int ac, char **av) {
int n;
strnode *s;
for(n = 0; (s = read1line()) != NULL; ++n)
continue;
if(n > 0) {
int i;
strnode *b;
char **a = malloc(n * sizeof(char *));
printf("There were %d lines\n", n);
for(b = list_head, i = 0; b; b = b->next, ++i)
a[i] = b->s;
printf("Near the middle is: %s", a[n / 2]);
}
return 0;
}
You can use the malloc and realloc functions to dynamically allocate and resize an array of pointers to char, and each element of the array will point to a string read from the file (where that string's storage is also allocated dynamically). For simplicity's sake we'll assume that the maximum length of each line is less than M characters (counting the newline), so we don't have to do any dynamic resizing of individual lines.
You'll need to keep track of the array size manually each time you extend it. A common technique is to double the array size each time you extend, rather than extending by a fixed size; this minimizes the number of calls to realloc, which is potentially expensive. Of course that means you'll have to keep track of two quantities; the total size of the array and the number of elements currently read.
Example:
#define INITIAL_SIZE ... // some size large enough to cover most cases
char **loadFile(FILE *stream, size_t *linesRead)
{
size_t arraySize = 0;
char **lines = NULL;
char *nextLine = NULL;
*linesRead = 0;
lines = malloc(INITIAL_SIZE * sizeof *lines);
if (!lines)
{
fprintf(stderr, "Could not allocate array\n");
return NULL;
}
arraySize = INITIAL_SIZE;
/**
* Read the next input line from the stream. We're abstracting this
* out to keep the code simple.
*/
while ((nextLine = getNextLine(stream)))
{
if (arraySize <= *linesRead)
{
char **tmp = realloc(lines, arraysSize * 2 * sizeof *tmp);
if (tmp)
{
lines = tmp;
arraySize *= 2;
}
}
lines[(*linesRead)++] = nextLine;
)
return lines;
}

C Programming: malloc() for a 2D array (using pointer-to-pointer)

yesterday I had posted a question: How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?
From the answers I got, I was able to understand what mistake I was doing.
I'm facing a new problem now, can anyone help out with this?
I want to dynamically allocate a 2D array, so I'm passing a Pointer-to-Pointer from my main() to another function called alloc_2D_pixels(...), where I use malloc(...) and for(...) loop to allocate memory for the 2D array.
Well, after returning from the alloc_2D_pixels(...) function, the pointer-to-pointer still remains NULL, so naturally, when I try accessing or try to free(...) the Pointer-to-Pointer, the program hangs.
Can anyone suggest me what mistakes I'm doing here?
Help!!!
Vikram
SOURCE:
main()
{
unsigned char **ptr;
unsigned int rows, cols;
if(alloc_2D_pixels(&ptr, rows, cols)==ERROR) // Satisfies this condition
printf("Memory for the 2D array not allocated"); // NO ERROR is returned
if(ptr == NULL) // ptr is NULL so no memory was allocated
printf("Yes its NULL!");
// Because ptr is NULL, with any of these 3 statements below the program HANGS
ptr[0][0] = 10;
printf("Element: %d",ptr[0][0]);
free_2D_alloc(&ptr);
}
signed char alloc_2D_pixels(unsigned char ***memory, unsigned int rows, unsigned int cols)
{
signed char status = NO_ERROR;
memory = malloc(rows * sizeof(unsigned char** ));
if(memory == NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
}
else
{
int i;
for(i = 0; i< cols; i++)
{
memory[i] = malloc(cols * sizeof(unsigned char));
if(memory[i]==NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
}
}
}
// Inserted the statements below for debug purpose only
memory[0][0] = (unsigned char)10; // I'm able to access the array from
printf("\nElement %d",memory[0][0]); // here with no problems
return status;
}
void free_2D_pixels(unsigned char ***ptr, unsigned int rows)
{
int i;
for(i = 0; i < rows; i++)
{
free(ptr[i]);
}
free(ptr);
}
One mistake is posting code that won't compile :). Below is corrected code with my comments in
/* this style */:
/* Next four lines get your code to compile */
#include <stdio.h>
#include <stdlib.h>
#define NO_ERROR 0
#define ERROR 1
/* prototypes for functions used by main but declared after main
(or move main to the end of the file */
signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols);
void free_2D_pixels(unsigned char** ptr, unsigned int rows);
/* main should return int */
int main()
{
unsigned char** ptr;
/* need to define rows and cols with an actual value */
unsigned int rows = 5, cols = 5;
if(alloc_2D_pixels(&ptr, rows, cols) == ERROR) // Satisfies this condition
printf("Memory for the 2D array not allocated"); // ERROR is returned
if(ptr == NULL) // ptr is NULL so no memory was allocated
printf("Yes its NULL!");
else
{
/* Added else clause so below code only runs if allocation worked. */
/* Added code to write to every element as a test. */
unsigned int row,col;
for(row = 0; row < rows; row++)
for(col = 0; col < cols; col++)
ptr[0][0] = (unsigned char)(row + col);
/* no need for &ptr here, not returning anything so no need to pass
by reference */
free_2D_pixels(ptr, rows);
}
return 0;
}
signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols)
{
signed char status = NO_ERROR;
/* In case we fail the returned memory ptr will be initialized */
*memory = NULL;
/* defining a temp ptr, otherwise would have to use (*memory) everywhere
ptr is used (yuck) */
unsigned char** ptr;
/* Each row should only contain an unsigned char*, not an unsigned
char**, because each row will be an array of unsigned char */
ptr = malloc(rows * sizeof(unsigned char*));
if(ptr == NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
}
else
{
/* rows/cols are unsigned, so this should be too */
unsigned int i;
/* had an error here. alloced rows above so iterate through rows
not cols here */
for(i = 0; i < rows; i++)
{
ptr[i] = malloc(cols * sizeof(unsigned char));
if(ptr[i] == NULL)
{
status = ERROR;
printf("ERROR: Memory allocation failed!");
/* still a problem here, if exiting with error,
should free any column mallocs that were
successful. */
}
}
}
/* it worked so return ptr */
*memory = ptr;
return status;
}
/* no need for *** here. Not modifying and returning ptr */
/* it also was a bug...would've needed (*ptr) everywhere below */
void free_2D_pixels(unsigned char** ptr, unsigned int rows)
{
/* should be unsigned like rows */
unsigned int i;
for(i = 0; i < rows; i++)
{
free(ptr[i]);
}
free(ptr);
}
In your alloc_2D_pixels function, you need another level of indirection when accessing memory. As it is now, you only modify the parameter, not the pointer pointed to by the parameter. For example,
memory = malloc(rows * sizeof(unsigned char** ));
// becomes
*memory = malloc(rows * sizeof(unsigned char** ));
// and later...
memory[i] = malloc(cols * sizeof(unsigned char));
// becomes
(*memory)[i] = malloc(cols * sizeof(unsigned char));
(basically, anywhere you are using memory, you need to use (*memory); the parentheses are only needed when you are using subscripts to ensure that the operators are applied in the correct order)
It also looks like, You are using uninitialized rows and cols variables
Using multidimensional arrays in this way in C is "suboptimal" for performance.
In no unclear words: Please do not use - and definitely not initialize - multidimensional arrays in the way you've illustrated. Multiple calls to malloc() will create you a batch of disjoint memory locations that doesn't map well to how actual graphics (as contiguous, single buffers) are stored anywhere. Also, if you have to do it hundreds or thousands of times, malloc() can be hideously expensive.
Also, due to the fact that you're using malloc() very often, it's also a nightmare (and bug to bite you eventually) for cleaning up. You've even mentioned that in the comments in your code, and yet ... why ?
If you absolutely must have this ptr[rows][cols] thing, create it better like this:
signed char alloc_2D_pixels(unsigned char*** memory,
unsigned int rows,
unsigned int cols)
{
int colspan = cols * sizeof(char);
int rowspan = rows * sizeof(char*);
unsigned char **rowptrs = *memory = malloc(rowspan + rows * colspan));
/* malloc failure handling left to the reader */
unsigned char *payload = ((unsigned char *)rowptrs) + rowspan;
int i;
for (i = 0; i < rows; payload += colspan, i++)
rowptrs[i] = payload;
}
that way you're allocating only a single block of memory and the whole thing can be freed in one go - ditch free_2D_pixels().

Resources