I have a dynamic two - dimensional array , size is height*width.
I want to change array size by using realloc.
This is my code but it is not working.
What should I do? Help me!!
int main(){
char **img;
img = (char**)malloc(sizeof(char*)*height);
for(i=0;i<height;i++){
img[i] = (char*) malloc(sizeof(char)*width);
}
resize(height*2, width*2, img);
}
void resize(int height, int width, char **img){
int i;
img = (char**)realloc(img, sizeof(char)*height);
for(i=0;i<h;i++){
img[i] = (char*)realloc(img[i], width);
}
}
There are two main issues. First, realloc may move the memory block to a new position. Therefore realloc has a return value pointing to either the "old" memory block if no move were necessary, to a new block if a move were necessary, or NULL if an error occurred. Yet you neglect this fact in resize, as it cannot change the pointer object a caller passes in. I'd suggest to adapt the prototype such that resize returns a (probably new) pointer just like realloc does.
Second, when reallocating each row, there might be uninitialized values in the array, probably pointing to "somewhere". Reallocating such an uninitialized value is undefined behaviour. I'd suggest to set the "new" rows to NULL such that realloc can behave correctly afterwards. Therefore it is necessary to know the "old" height, since you have no chance otherwise to distinguish a regularly initialized pointer from a "garbage" pointer.
See the adapted code. Hope it helps.
char** resize(int oldHeight, int oldWidth, int height, int width, char **img){
int i;
img = realloc(img, sizeof(char)*height);
for (int i=oldHeight; i<height; i++)
img[i] = NULL;
for(i=0;i<height;i++){
img[i] = realloc(img[i], width);
for (int col=oldWidth; col < width; col++) {
img[i][col] = 0;
}
}
return img;
}
int main(){
int height = 10;
int width = 20;
char **img;
img = malloc(sizeof(char*)*height);
for(int i=0;i<height;i++){
img[i] = malloc(sizeof(char)*width);
}
img = resize(height, width, height*2, width*2, img);
}
Besides you
are not dealing with a 2D-array and
and the code leak memory if the new height is smaller then the old height and
you do not need to cast void-pointers in C and
all ints should be size_ts
there are two major bugs here, as the code
passes the wrong size to reallocate the outer array. It multiplies height by sizeof (char) instead of sizeof (char*).
misses to initialise the additional pointers realloced to the "outer" array with NULL before passing them to realloc() via the inner resizing-loop.
So the minimal adjustments assuming the new height is greater or equal the old height could look like
void resize(size_t height, size_t height_current, size_t width, char **img){
int i;
img = (char**)realloc(img, sizeof(char*)*height);
for(i=height_current;i<height;i++){
img[i] = NULL;
}
for(i=0;i<width;i++){ // correct copypasta mistake here
img[i] = (char*)realloc(img[i], width);
}
}
A nicer version could look like this
void resize(size_t height, size_t height_current, size_t width, size_t char **img)
{
if (height != height_current)
{
if (height < height_current)
{
for (size_t i = height; i < height_current; ++i)
{
free(img[i]);
}
}
img = realloc(img, height * sizeof *img);
if (height > height_current)
{
for (size_t i = height_current; i < height; ++i)
{
img[i] = NULL;
}
}
}
for (size_t i = 0; i < width; ++i)
{
img[i] = realloc(img[i], width * sizeof *img[i]);
}
}
Call it like this:
resize(height*2, height, width*2, img);
Also you really want to add error checking to all calls to malloc() and realloc() as they might very well fail!
To do this correctly, you must know at least the number of rows before resizing. One possibility is to define a struct containing additional information (kind of OOP approach, have all relevant data together), like the following example (also storing the number of columns, just for completeness, untested code here):
#include <stdlib.h>
#include <string.h>
typedef struct Lookup Lookup;
struct Lookup
{
size_t rows;
size_t cols;
char **data;
};
static void Lookup_destroy(Lookup *self)
{
if (!self) return;
for (size_t r = 0; r < self->rows; ++r)
{
free(self->data[r]);
}
free(self->data);
free(self);
}
static Lookup *Lookup_create(size_t rows, size_t cols)
{
Lookup *self = malloc(sizeof *self);
if (!self) return 0;
self->rows = rows;
self->cols = cols;
self->data = malloc(rows * sizeof *(self->data));
if (!self->data)
{
free(self);
return 0;
}
memset(self->data, 0, rows * sizeof *(self->data));
for (size_t r = 0; r < rows; ++r)
{
self->data[r] = malloc(cols * sizeof *(self->data[r]));
if (!self->data[r])
{
Lookup_destroy(self);
return 0;
}
}
return self;
}
static Lookup *Lookup_resize(Lookup *self, size_t rows, size_t cols)
{
if (!self) return Lookup_create(rows, cols);
// free rows that are no longer needed, if any:
for (size_t r = rows; r < self->rows; ++r)
{
free(self->data[r]);
self->data[r] = 0;
}
// reallocate array of rows:
char **newdata = realloc(self->data, rows * sizeof *newdata);
if (!newdata)
{
Lookup_destroy(self);
return 0;
}
// update row array and row count:
self->data = newdata;
size_t oldrows = self->rows;
self->rows = rows;
// initialize new rows to NULL, if any:
if (rows > oldrows)
{
memset(self->data + oldrows, 0,
(rows - oldrows) * sizeof *(self->data));
}
// reallocate individual rows:
for (size_t r = 0; r < rows; ++r)
{
char *newrow = realloc(self->data[r], cols * sizeof *newrow);
if (!newrow)
{
Lookup_destroy(self);
return 0;
}
self->data[r] = newrow;
}
// update col count:
self->cols = cols;
return self;
}
Note how the result of realloc() is always stored to a temporary variable first, this is needed to correctly handle errors. This code simply throws away the whole object in case of any error -- you can do different things with more code of course.
You could use it in your code like this:
int main(){
Lookup img;
img = Lookup_create(height, width);
// check for NULL here
img = Lookup_resize(img, height*2, width*2);
// and check for NULL here
}
Related
Having trouble understanding and getting to work String operations in the following code.
Please help, me and my study colleagues are losing our minds over this. ty.
This is a simple method to fill a multi dimensional array with custom strings - which for some reason we cannot figure out for the life of us does simply not work - spits out random junk from the memory instead. Also allocation amounts don't seem to be quite right.
#include <stdio.h>
#include <malloc.h>
#include <string.h>
char*** createKeyPad(int rows, int cols, int num_chars) {
if(num_chars <= 0) return NULL;
char needed = 'a';
char** aptr = NULL;
char*** rptr = NULL;
aptr = (char**) malloc(rows * cols * sizeof(char*));
if(aptr == NULL) {
return NULL;
}
rptr = (char***) malloc(rows * sizeof(char**));
if(rptr == NULL) {
free(aptr);
return NULL;
}
for(int row = 0; row < rows; row++) {
rptr[row] = aptr + (row * cols);
}
for(int row = 0; row < rows; row++) {
for(int col = 0; col < cols; col++) {
char* string;
for(int i = 0; i < num_chars; i++) {
string[i] = needed;
}
string[num_chars] = '\0';
rptr[row][col] = string;
printf("%s", string);
}
}
printf("%s", "hallo");
return rptr;
}
int main() {
printf("Hello, World!\n");
char*** keypad = createKeyPad(5, 5, 3);
for(int row = 0; row < 5; row++) {
for(int col = 0; col < 5; col++) {
printf("%s", keypad[row][col]);
}
printf("\n");
}
}
You have plenty problems in this code.
string is a dangling pointer - ie it was not initialized and does not reference a valid char array
even if string was referencing a valid object you assign the same pointer to all (pseudo)array elements.
Do not use *** pointers.
use the correct type for sizes
Use positive checks and try to minimize function returns.
arrays are indexed from 0 in C and even if the string was referencing an array of num_chars elements, string[num_chars] = '\0'; is accessing an element outside the array bounds.
I would use array pointers and use only one allocation to allocate the space for the whole 3D array.
Use objects instead of types in sizeofs
int createKeyPad(size_t rows, size_t cols, size_t numChars, char (**pad)[cols][numChars])
{
int result = 0;
if(numChars > 1)
{
*pad = malloc(rows * sizeof(**pad));
if(*pad)
{
result = 1;
for(size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
for(size_t i = 0; i < numChars - 1; i++)
{
(*pad)[row][col][i] = row * cols + col + '0';
}
(*pad)[row][col][numChars - 1] = 0;
}
}
}
}
return result;
}
int main(void)
{
printf("Hello, World!\n");
char (*keypad)[5][3];
if(createKeyPad(5, 5, 3, &keypad))
{
for(size_t row = 0; row < 5; row++)
{
for(size_t col = 0; col < 5; col++)
{
printf("%s ", keypad[row][col]);
}
printf("\n");
}
}
free(keypad);
}
https://godbolt.org/z/6zY4zbGW3
The main problem is that char* string; followed by string[i] = needed; is dereferencing an invalid pointer because string is not pointing to anything valid.
In the code's current style of allocating one block for each level and dividing the block up, the memory for all the strings could be allocated in one big block:
char* sptr = (char*) malloc(rows * cols * (num_chars + 1) * sizeof(char));
(Note: The (char*) typecast is not required. Also the * sizeof(char) is not required since sizeof(char) is 1 by definition, but I put it in there in case the code is changed to use something other than char at a later date.)
Then the string variable in the nested loop can be initialized as follows:
char* string = sptr + (row * cols + col) * (num_chars + 1);
I understand I'm splitting the array over the double pointer, but how can I deallocate if I lost the data track?
#include <stdio.h>
#include <stdlib.h>
#define width 20
#define height 20
void allocate_matrix(int ***matrix)
{
double **local_matrix, *data;
local_matrix = (double **)malloc(sizeof(double *) * height);
data = (double *)malloc(sizeof(double) * width * height);
for (int i = 0; i < height; i++)
{
local_matrix[i] = &(data[i * width]);
}
*matrix = local_matrix;
}
void deallocate_matrix(int **matrix) {
}
int main(void) {
int **matrix;
allocate_matrix(&matrix);
deallocate_matrix(matrix);
return 0;
}
You didn't lose track of the second pointer. If you look at your loop body:
local_matrix[i] = &(data[i * width]);
When i is 0, local_matrix[0] is assigned &data[0] which is the same as data. So that's what you need to free:
void deallocate_matrix(int **matrix) {
free(matrix[0]);
free(matrix);
}
First of all, you are allocating space for double then use it as int, which doesn't make sense (and will not compile).
But the main problem here is that you shouldn't be allocating this as fragmented segments but as a contiguous 2D array. Please study Correctly allocating multi-dimensional arrays. This will give a major performance boost and may (arguably) make the code a bit easier to read as well.
If we follow the advise in that post, then your code could be rewritten as:
#include <stdio.h>
#include <stdlib.h>
void allocate_matrix(size_t height, size_t width, int (**matrix)[height][width])
{
int (*local_matrix) [height][width];
local_matrix = malloc(sizeof *local_matrix);
if(local_matrix == NULL)
{
// handle errors
}
*matrix = local_matrix;
}
int main (void)
{
const size_t height = 20;
const size_t width = 20;
int (*matrix)[height][width];
allocate_matrix(height, width, &matrix);
int(*pmatrix)[width] = *matrix; // pointer to first 1D array for easier syntax
for(size_t h=0; h<height; h++)
{
for(size_t w=0; w<width; w++)
{
pmatrix[h][w] = h+w; // assign some sort of data
printf("%d ", pmatrix[h][w]);
}
printf("\n");
}
free(matrix);
return 0;
}
As you can see this also eliminated the need for a complex deallocation routine, since we can just pass the pointer directly to free() and deallocate everything at one single place.
the following proposed code:
needs the header file: stdlib.h for the prototypes for exit() and malloc() and EXIT_FAILURE
performs the desired functionality
you might want to modify the calculation of the initialization values of the matrix
and now, the proposed code:
double **allocate_matrix(void)
{
local_matrix** = malloc( sizeof(double *) * height );
if( ! local_matrix )
{
perror( "malloc for matrix height failed:");
exit( EXIT_FAILURE );
}
for( size_t y = 0; y<height; y++ )
{
local_matrix[y] = malloc( sizeof(double) * width );
if( !local_matrix[y] )
{
//cleanup and exit
}
for ( size_t i = 0; i < width; i++)
{
local_matrix[y][i] = i;
}
}
return local_matrix;
}
int main( void )
{
double **matrix;
matrix = allocate_matrix();
for( size_t y= 0; y< height; y++ )
{
free( matrix[ y ] ):
}
free( matrix );
}
// A part of Code
int dim1=height;
int dim2=width;
int dim3=3;
int k;
unsigned char *** image = (unsigned char ***)malloc(dim1*dim2*3);
for (i = 0; i< dim1; i++) {
image[i] = (unsigned char **)malloc(dim2*sizeof(unsigned char *));
for (j = 0; j < dim2; j++) {
image[i][j] = (unsigned char *)malloc(dim3*sizeof(unsigned char ));
}
}
// B part of Code
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
fread(&image[i][j][0],sizeof(unsigned char),1,fp);
fread(&image[i][j][1],sizeof(unsigned char),1,fp);
fread(&image[i][j][2],sizeof(unsigned char),1,fp);
}
}
As you can see from above I am trying to declare a 3d array that will contain the pixel information of a bmp image. The fp pointer is to a binary file that the data is contained there.
My question is how is it possible when I try to fread using dynamic memory allocation to get wrong results in image table (meaning a blank image is printed even though the rest of my code that i dont include here is correct).
On the other hand when i remove the A part of the Code and replace it with "unsigned char image[height][width][3]" it works.
So what am i doing wrong in the memory allocation or in the use of fread? Because obviously the problem is there.
In order to make it easier lets assume that the size is 252x252x3.
typedef struct
{
unsigned char R;
unsigned char G;
unsigned char B;
}RGB;
void *allocateReadImage(size_t width, size_t height, FILE *fi)
{
RGB (*picture)[width] = malloc(sizeof(*picture) * height);
if(picture && fi)
{
if(fread(picture, sizeof(*picture), height, fi) != height)
{
free(picture);
picture = NULL;
}
}
return picture;
}
usage:
RGB *mypicture = allocateReadImage(1600, 1200, inputfile);
if(!mypicture) { /*some error handling*/ }
The code works if i use the name of the struct array directly for the allocation, but not from the function argument. Otherwise it returns memory error.
typedef struct COORD
{
int xp;
int yp;
} coord;
coord** xy;
void allocate(coord** COORD)
{
int i;
//allocate COORD[500][460]
COORD = (coord**)malloc(sizeof(coord*)*500);
for(i=0; i<500; i++)
{
COORD[i] = (coord*)malloc(sizeof(coord)*460);
}
// freeing
for (i=0; i<500; i++) free(COORD[i]);
free(COORD);
}
//function call: allocate(xy);
//That is the code that leeds to the error
Using just xy instead of COORD works. And i am all wondering why is that not working.
You are mixing up various coding styles here. It's not clear what exactly you want to achieve. Pick one according to your task.
Temporary buffer
You need a large temporary buffer that should be allocated on the heap and that does not need to be seen from outside. Just create a local variable:
void do_stuff(int w, int h)
{
coord **p;
int i;
p = malloc(h * sizeof(*p));
for (i = 0; i < h; i++) p[i] = malloc(w * sizeof(**p));;
// do stuff
for (i = 0; i < h; i++) free(p[i]);
free(p);
}
Allocate memory for further use
You want to allocate storage that your client code can use. Then provide two functions, one that allocates and one that frees the memory:
coord **create(int w, int h)
{
coord **p;
int i;
p = malloc(h * sizeof(*p));
for (i = 0; i < h; i++) p[i] = malloc(w * sizeof(**p));
return p;
}
void destroy(coord **p, int h)
{
int i;
for (i = 0; i < h; i++) free(p[i]);
free(p);
}
Your client code can then use the memory between these calls:
coord **p = create(500, 460);
// do stuff
drestroy(p, 500);
(Note that you have to pass the height to destroy, which is a bit unfortunate. It might be cleaner to create a wrapper struct that hold information about width and height and the pointer.)
Allocate memory for a global variable
You have a single instance of a global pointer. Then your functions always operate on that pointer and you don't need any further information on it (except the dimensions):
coord **global = NULL;
void destroy_global(int h)
{
int i;
for (i = 0; i < h; i++) free(global[i]);
free(global);
global = NULL;
}
void create_global(int w, int h)
{
int i;
if (global != NULL) free_global();
global = alloc(h * sizeof(*global));
for (i = 0; i < h; i++) global[i] = malloc(w * sizeof(**global));
}
Note that you should include <stdlib.h> for all memory functions and the NULL macro.
Addendum According to your comment, you want to allocate memory for a bitmap. That's option 2 above.
I recommend to create an object structure. You can pass a pointerv to that structure as handle to a bunch of functions. You can create the object with a function that returns that handle.
The following sketches a rough design for a bitmap object.
typedef struct Pixel Pixel;
typedef struct Bitmap Bitmap;
struct Pixel {
uint8_t r, g, b;
};
struct Bitmap {
int height;
int width;
Pixel **pixel;
};
Bitmap *bitmap_new(int w, int h)
{
Bitmap *bmp = malloc(sizeof(*bmp));
int i;
bmp->height = h;
bmp->width = w;
bmp->pixel = malloc(h * sizeof(*bmp->pixel));
for (i = 0; i < h; i++) {
bmp->pixel[i] = malloc(w * sizeof(**bmp->pixel));
}
return p;
}
void bitmap_delete(Bitmap *bmp)
{
int i;
for (i = 0; i < h; i++) free(bmp->pixel[i]);
free(bmp->pixel);
free(bmp);
}
Bitmap *bitmap_read(const char *fn)
{
Bitmap *bmp;
FILE *f = fopen(fn, "rb");
// read and allocate
return bmp;
}
void bitmap_blank(Bitmap *bmp, int r, int g, int b)
{
for (i = 0; i < bitmap->height; i++) {
for (j = 0; j < bitmap->width; j++) {
bmp->pixel[i][j].r = r;
bmp->pixel[i][j].g = g;
bmp->pixel[i][j].b = b;
}
}
}
void bitmap_mirror_x(Bitmap *bmp)
{
// do stuff
}
int bitmap_write(Bitmap *bmp, const char *fn)
{
FILE *f = fopen(fn, "rb");
// write bitmap to file
return 0;
}
The design is similar to the interface to FILE *: fopen gives you a handle (or NULL; error checking is omitted in the code above) and fread, fprintf, fseek and family take a pointer to the file as argument. Finally call fclose to close the file on disk and to free any ressources fopen has claimed.
Have you tried to compile this code? There are a number of errors.
First, the type of main should always be 'int main(int argc, char *argv[])'
Second, you need to '#include <stdlib.h>' at the top of your file to get the return type of malloc/free and friends.
Third, you are not declaring 'i'.
Fourth, you are using the same name 'COORD' as both a struct name and as a variable. Don't do this, it will cause you problems.
Sending incorrect code makes it very difficult to figure out what the root of your problem is, but I suspect it's the overloading of 'COORD'.
typedef struct COORD
{
int xp;
int yp;
} coord;
coord** xy;
void allocate(coord** COORD)
{
int i;
//allocate COORD[500][460]
COORD = (coord**)malloc(sizeof(coord*)*500);
for(i=0; i<500; i++)
{
COORD[i] = (coord*)malloc(sizeof(coord)*460);
}
// freeing
for (i=0; i<500; i++) free(COORD[i]);
free(COORD);
}
//function call: allocate();
//That is the code that works
The problem is that the function allocate() cannot change the value of xy outside itself. This is because C is call by value, the called function only gets the values of its arguments, not any kind of references to the expressions in the caller's context.
It needs to be:
void allocate(coord ***c)
{
}
and:
coord **xy;
allocate(&xy);
which of course is silly: the proper design would be for allocate() to return the new address:
coord ** allocate(void)
{
}
with use like:
coord **xy = allocate();
Probably it would be even better to have the dimensions as parameters to the function, since magic numbers are generally not a good thing:
coord ** allocate(size_t width, size_t height);
typedef struct
{
int xp;
int yp;
} Coord;
Coord **xy;
Coord** allocate(size_t height, size_t width)
{
int i;
Coord **arr;
arr = malloc(sizeof(Coord*)*height);
for(i=0; i<height; i++) {
arr[i] = malloc(sizeof(coord)*width);
}
return arr;
}
void allocate2(Coord ***p_arr, size_t height, size_t width)
{
int i;
Coord **arr;
arr = *p_arr;
arr = malloc(sizeof(Coord*)*height);
for(i=0; i<height; i++) {
arr[i] = malloc(sizeof(coord)*width);
}
}
void deallocate(Coord **arr, size_t height)
{
for (i=0; i<500; i++) {
free(arr[i]);
}
free(arr);
}
int main()
{
Coord **arr_2;
Coord ***p_arr_3;
allocate2(&xy, 500, 460);
/* do something with global array, xy, e.g. */
xy[1][2].xp = 100;
xy[1][2].yp = 200;
deallocate(xy, 500);
arr_2 = allocate(500, 460);
/* do something with local array, arr_2 */
deallocate(arr_2, 500);
allocate2(p_arr_3, 500, 460);
/* do something with ptr to local array, p_arr_3 */
deallocate(*p_arr_3, 500);
return 0;
}
I am new to C and during my learning I want to return a two dimensional array from a function, so that I can use it in my main program. Can anyone explain me the same with example. Thanks in advance.
It depends how it is implemented. You can either work with just a one-dimensional array where you know the length of each (row) and the next row begins immediately after the previous one. OR, you can have an array of pointers to arrays. The extra cost though is you need to de-reference two pointers to get to one element of data.
// 2D array of data, with just one array
char* get_2d_ex1(int rows, int cols) {
int r, c, idx;
char* p = malloc(rows*cols);
for (r=0; r<rows; r++) {
for (c=0; c<cols; c++) {
idx = r*cols + c; // this is key
p[idx] = c; // put the col# in its place, for example.
}
}
return p;
}
Declare your function as returning a pointer to a pointer. If we use int as an example:
int **samplefunction() {
int** retval = new int*[100];
for (int i = 1; i < 100; i++) {
retval[i] = new int[100];
}
// do stuff here to retval[i][j]
return retval;
}
Here's an example of how you might create, manipulate and free a "2d array":
#include <stdlib.h>
#define ROWS 5
#define COLS 10
int **create_2d_array(size_t rows, size_t cols)
{
size_t i;
int **array = (int**)malloc(rows * sizeof(int*));
for (i = 0; i < rows; i++)
array[i] = (int*)malloc(cols * sizeof(int));
return array;
}
void free_2d_array(int **array, size_t rows, size_t cols)
{
size_t i;
for (i = 0; i < rows; i++)
free(array[i]);
free(array);
}
int main(void)
{
int **array2d = create_2d_array(ROWS, COLS);
/* ... */
array2d[3][4] = 5;
/* ... */
free_2d_array(array2d, ROWS, COLS);
return 0;
}
To create a "2d array"/matrix, all you have to do is create a dynamic array of pointers (in this case int*) of the size of the rows/width:
int **array = (int**)malloc(rows * sizeof(int*));
Then you set each of those pointers to point to a dynamic array of int of the size of the columns/height:
array[i] = (int*)malloc(cols * sizeof(int));
Note that the casts on malloc aren't required, it's just a habit I have.