So I created a dynamically sized 2d array using the following logic:
int **newBoard;
newBoard = (int **) malloc(sizeof(int *) * rows);
newBoard[0] = (int *) malloc(sizeof(int) * cols * rows);
for (i = 0; i < rows; i++) {
newBoard[i] = (*newBoard + cols * i);
}
But now I am having trouble freeing the memory I allocated. Whenever I try to I receive a "free(): invalid pointer: 0x00000000007343c8 ***" error message. I am currently trying to free the memory like:
for (i = 0; i < rows; i++) {
free(newBoard[i]);
}
free(newBoard);
Can anyone help me out and tell me how to free this correctly??
When you do
newBoard[0] = (int *) malloc(sizeof(int) * cols * rows);
you are allocating a continous block of memory for cols * rows spaces of int objects.
You can only free it once using the start of the block, you cannot free it at an
offset of the start of the memory and you cannot free it multiple times, only
once.
for (i = 0; i < rows; i++) {
newBoard[i] = (*newBoard + cols * i);
}
Here the newBoard[i] are getting an offset of the continues block of memory,
so you cannot free more than once at different offsets, you have to free it
once at the start of the block.
free(newBoard[0]);
free(newBoard);
would be correct.
Please don't cast malloc, this is bad practice. And you should check if
malloc returns NULL.
I personally think that this is a clever way to do only 2 mallocs instead of
row+1 mallocs, but it has downsides, too. You have to be very careful with it. Freeing single blocks of memory that
are not needed is not possible, reallocation of single newBoard[i] is also not
possible. You have to have a lot of discipline in order to avoid mistakes like
multiple frees, that's why I think that the traditional way of doing, is
better overall. I'd do:
for(i = 0; i < rows; ++i)
newBoard[i] = malloc(cols * sizeof *newBoard[i]);
then you can free like you did.
Related
This is one of those questions where there are so many answers, and yet none do the specific thing.
I tried to look at all of these posts —
1 2 3 4 5 6 7 8 9 — and every time the solution would be either using VLAs, using normal arrays with fixed dimensions, or using pointer to pointer.
What I want is to allocate:
dynamically (using a variable set at runtime)
rectangular ("2d array") (I don't need a jagged one. And I guess it would be impossible to do it anyway.)
contiguous memory (in #8 and some other posts, people say that pointer to pointer is bad because of heap stuff and fragmentation)
no VLAs (I heard they are the devil and to always avoid them and not to talk to people who suggest using them in any scenario).
So please, if there is a post I skipped, or didn't read thoroughly enough, that fulfils these requirements, point me to it.
Otherwise, I would ask of you to educate me about this and tell me if this is possible, and if so, how to do it.
You can dynamically allocate a contiguous 2D array as
int (*arr)[cols] = malloc( rows * sizeof (int [cols]) );
and then access elements as arr[i][j].
If your compiler doesn’t support VLAs, then cols will have to be a constant expression.
Preliminary
no VLAs (I heard they are the devil and to always avoid them and not to talk to people who suggest using them in any scenario.
VLAs are a problem if you want your code to work with Microsoft's stunted C compiler, as MS has steadfastly refused to implement VLA support, even when C99, in which VLA support was mandatory, was the current language standard. Generally speaking, I would suggest avoiding Microsoft's C compiler altogether if you can, but I will stop well short of suggesting the avoidance of people who advise you differently.
VLAs are also a potential problem when you declare an automatic object of VLA type, without managing the maximum dimension. Especially so when the dimension comes from user input. This produces a risk of program crash that is hard to test or mitigate at development time, except by avoiding the situation in the first place.
But it is at best overly dramatic to call VLAs "the devil", and I propose that anyone who actually told you "not to talk to people who suggest using them in any scenario" must not have trusted you to understand the issues involved or to evaluate them for yourself. In particular, pointers to VLAs are a fine way to address all your points besides "no VLAs", and they have no particular technical issues other than lack of support by (mostly) Microsoft. Support for these will be mandatory again in C2X, the next C language specification, though support for some other forms of VLA use will remain optional.
Your requirements
If any of the dimensions of an array type are not given by integer constant expressions, then that type is by definition a variable-length array type. If any dimension but the first of an array type is not given by an integer constant expressions then you cannot express the corresponding pointer type without using a VLA.
Therefore, if you want a contiguously allocated multidimensional array (array of arrays) for which any dimension other than the first is chosen at runtime, then a VLA type must be involved. Allocating such an object dynamically works great and has little or no downside other than lack of support by certain compilers (which is a non-negligible consideration, to be sure). It would look something like this:
void do_something(size_t rows, size_t columns) {
int (*my_array)[columns]; // pointer to VLA
my_array = malloc(rows * sizeof(*my_array));
// ... access elements as my_array[row][col] ...
}
You should have seen similar in some of the Q&As you reference in the question.
If that's not acceptable, then you need to choose which of your other requirements to give up. I would suggest the "multi-dimensional" part. Instead, allocate (effectively) a one-dimensional array, and use it as if it had two dimensions by performing appropriate index computations upon access. This should perform almost as well, because it's pretty close to what the compiler will set up automatically for a multidimensional array. You can make it a bit easier on yourself by creating a macro to assist with the computations. For example,
#define ELEMENT_2D(a, dim2, row, col) ((a)[(row) * (dim2) + (col)])
void do_something(size_t rows, size_t columns) {
int *my_array;
my_array = malloc(rows * columns * sizeof(*my_array));
// ... access elements as ELEMENT_2D(my_array, columns, row, col) ..
}
Alternatively, you could give up the contiguous allocation and go with an array of pointers instead. This is what people who don't understand arrays, pointers, and / or dynamic allocation typically do, and although there are some applications, especially for arrays of pointers to strings, this form has mostly downside relative to contiguous allocation for the kinds of applications where one wants an object they think of as a 2D array.
Often an array of pointers is allocated and then memory is allocated to each pointer.
This could be inverted. Allocate a large contiguous block of memory. Allocate an array of pointers and assign addresses from within the contiguous block.
#include <stdio.h>
#include <stdlib.h>
int **contiguous ( int rows, int cols, int **memory, int **pointers) {
int *temp = NULL;
int **ptrtemp = NULL;
// allocate a large block of memory
if ( NULL == ( temp = realloc ( *memory, sizeof **memory * rows * cols))) {
fprintf ( stderr, "problem memory malloc\n");
return pointers;
}
*memory = temp;
// allocate pointers
if ( NULL == ( ptrtemp = realloc ( pointers, sizeof *pointers * rows))) {
fprintf ( stderr, "problem memory malloc\n");
return pointers;
}
pointers = ptrtemp;
for ( int rw = 0; rw < rows; ++rw) {
pointers[rw] = &(*memory)[rw * cols]; // assign addresses to pointers
}
// assign some values
for ( int rw = 0; rw < rows; ++rw) {
for ( int cl = 0; cl < cols; ++cl) {
pointers[rw][cl] = rw * cols + cl;
}
}
return pointers;
}
int main ( void) {
int *memory = NULL;
int **ptrs = NULL;
int rows = 20;
int cols = 17;
if ( ( ptrs = contiguous ( rows, cols, &memory, ptrs))) {
for ( int rw = 0; rw < rows; ++rw) {
for ( int cl = 0; cl < cols; ++cl) {
printf ( "%3d ", ptrs[rw][cl]);
}
printf ( "\n");
}
free ( memory);
free ( ptrs);
}
return 0;
}
Suppose you need a 2D array of size W x H containing ints (where H is the number of rows, and W the number of columns).
Then you can do the the following:
Allocation:
int * a = malloc(W * H * sizeof(int));
Access element at location (i,j):
int val = a[j * W + i];
a[j * W + i] = val;
The whole array would occupy a continuous block of memory, and can be dynamically allocated (without VLAs). Being a continuous block of memory offers an advantage over an array of pointers due to [potentially] fewer cache misses.
In such an array, the term "stride" refers to the offset between one row to another. If you need to use padding e.g. to make sure all lines start at some aligned address, you can use a stride which is bigger than W.
I did a benchmark between:
the classic pointer to array of pointers to individually malloc'd memory
one pointer to contignuous memory, accessed with a[x * COLS + y]
a mix of both - pointer to array of pointers to sliced up malloc'd contignuous memory
TL;DR:
the second one appears to be faster by 2-12% compared to the others, which are sort of similar in performance.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROWS 100
#define COLS 100
#define LOOPS 100
#define NORMAL 0
#define SINGLE 1
#define HYBRID 2
int **x_normal; /* global vars to make it more equal */
int *y_single;
int *z_hybrid_memory;
int **z_hybrid_pointers;
int copy_array[ROWS][COLS];
void x_normal_write(int magic) { /* magic number to prevent compiler from optimizing it */
int i, ii;
for (i = 0; i < ROWS; i++) {
for (ii = 0; ii < COLS; ii++) {
x_normal[i][ii] = (i * COLS + ii + magic);
}
}
}
void y_single_write(int magic) {
int i, ii;
for (i = 0; i < ROWS; i++) {
for (ii = 0; ii < COLS; ii++) {
y_single[i * COLS + ii] = (i * COLS + ii + magic);
}
}
}
void z_hybrid_write(int magic) {
int i, ii;
for (i = 0; i < ROWS; i++) {
for (ii = 0; ii < COLS; ii++) {
z_hybrid_pointers[i][ii] = (i * COLS + ii + magic);
}
}
}
void x_normal_copy(void) {
int i, ii;
for (i = 0; i < ROWS; i++) {
for (ii = 0; ii < COLS; ii++) {
copy_array[i][ii] = x_normal[i][ii];
}
}
}
void y_single_copy(void) {
int i, ii;
for (i = 0; i < ROWS; i++) {
for (ii = 0; ii < COLS; ii++) {
copy_array[i][ii] = y_single[i * COLS + ii];
}
}
}
void z_hybrid_copy(void) {
int i, ii;
for (i = 0; i < ROWS; i++) {
for (ii = 0; ii < COLS; ii++) {
copy_array[i][ii] = z_hybrid_pointers[i][ii];
}
}
}
int main() {
int i;
clock_t start, end;
double times_read[3][LOOPS];
double times_write[3][LOOPS];
/* MALLOC X_NORMAL 1/2 */
x_normal = malloc(ROWS * sizeof(int*)); /* rows */
for (i = 0; i < ROWS; i+=2) { /* malloc every other row to ensure memory isn't contignuous */
x_normal[i] = malloc(COLS * sizeof(int)); /* columns for each row (1/2) */
}
/* MALLOC Y_SINGLE */
y_single = malloc(ROWS * COLS * sizeof(int)); /* all in one contignuous memory */
/* MALLOC Z_HYBRID */
z_hybrid_memory = malloc(ROWS * COLS * sizeof(int)); /* memory part - with a big chunk of contignuous memory */
z_hybrid_pointers = malloc(ROWS * sizeof(int*)); /* pointer part - like in normal */
for (i = 0; i < ROWS; i++) { /* assign addresses to pointers from "memory", spaced out by COLS */
z_hybrid_pointers[i] = &z_hybrid_memory[(i * COLS)];
}
/* MALLOC X_NORMAL 2/2 */
for (i = 1; i < ROWS; i+=2) { /* malloc every other row to ensure memory isn't contignuous */
x_normal[i] = malloc(COLS * sizeof(int)); /* columns for each row (2/2) */
}
/* TEST */
for (i = 0; i < LOOPS; i++) {
/* NORMAL WRITE */
start = clock();
x_normal_write(i);
end = clock();
times_write[NORMAL][i] = (double)(end - start);
/* SINGLE WRITE */
start = clock();
y_single_write(i);
end = clock();
times_write[SINGLE][i] = (double)(end - start);
/* HYBRID WRITE */
start = clock();
z_hybrid_write(i);
end = clock();
times_write[HYBRID][i] = (double)(end - start);
/* NORMAL READ */
start = clock();
x_normal_copy();
end = clock();
times_read[NORMAL][i] = (double)(end - start);
/* SINGLE READ */
start = clock();
y_single_copy();
end = clock();
times_read[SINGLE][i] = (double)(end - start);
/* HYBRID READ */
start = clock();
z_hybrid_copy();
end = clock();
times_read[HYBRID][i] = (double)(end - start);
}
/* REPORT FINDINGS */
printf("CLOCKS NEEDED FOR:\n\nREAD\tNORMAL\tSINGLE\tHYBRID\tWRITE\tNORMAL\tSINGLE\tHYBRID\n\n");
for (i = 0; i < LOOPS; i++) {
printf(
"\t%.1f\t%.1f\t%.1f\t\t%.1f\t%.1f\t%.1f\n",
times_read[NORMAL][i], times_read[SINGLE][i], times_read[HYBRID][i],
times_write[NORMAL][i], times_write[SINGLE][i], times_write[HYBRID][i]
);
/* USE [0] to get totals */
times_read[NORMAL][0] += times_read[NORMAL][i];
times_read[SINGLE][0] += times_read[SINGLE][i];
times_read[HYBRID][0] += times_read[HYBRID][i];
times_write[NORMAL][0] += times_write[NORMAL][i];
times_write[SINGLE][0] += times_write[SINGLE][i];
times_write[HYBRID][0] += times_write[HYBRID][i];
}
printf("TOTAL:\n\t%.1f\t%.1f\t%.1f\t\t%.1f\t%.1f\t%.1f\n",
times_read[NORMAL][0], times_read[SINGLE][0], times_read[HYBRID][0],
times_write[NORMAL][0], times_write[SINGLE][0], times_write[HYBRID][0]
);
printf("AVERAGE:\n\t%.1f\t%.1f\t%.1f\t\t%.1f\t%.1f\t%.1f\n",
(times_read[NORMAL][0] / LOOPS), (times_read[SINGLE][0] / LOOPS), (times_read[HYBRID][0] / LOOPS),
(times_write[NORMAL][0] / LOOPS), (times_write[SINGLE][0] / LOOPS), (times_write[HYBRID][0] / LOOPS)
);
return 0;
}
Though maybe this is not the best approach since the result can be tainted by random stuff - such as perhaps the proximity of the source arrays to the destination array for copy functions (though the numbers are consistent for reads and writes. Perhaps someone can expand on this.)
I'm new to programming and am trying to do some practice problems in C. I've come across the following prompt:
/*
Pascal's Triangle
Given numRows, generate the first numRows of Pascal's triangle.
For example, given numRows = 5,
Return
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
* Return an array of arrays.
* The sizes of the arrays are returned as *columnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
I finished the problem using a two-dimensional array as a first attempt and then tried doing it by using malloc (as specified in the problem) and got a bit stuck. I looked over some solutions and found one that somewhat matched my approach:
// Source: https://github.com/vli02/leetcode/blob/master/118.%20Pascal's%20Triangle.c
int** generate(int numRows, int** columnSizes) {
int i, j;
int *buff, **p;
p = malloc(numRows * sizeof(int *));
*columnSizes = malloc(numRows * sizeof(int));
//assert(p && *columnSizes);
for (i = 1; i <= numRows; i ++) {
buff = malloc(i * sizeof(int));
//assert(buff);
p[i - 1] = buff;
(*columnSizes)[i - 1] = i;
buff[0] = 1;
for (j = 1; j < i - 1; j ++) {
buff[j] = p[i - 2][j - 1] + p[i - 2][j];
}
buff[i - 1] = 1;
}
return p;
}
All I want to ask is, how is this solution correct if the corresponding address to the buff pointer is changed through every loop, but the blocks of memory allocated in each loop are never freed? Wouldn't this cause a memory leak? As far as I've seen, malloc will not free the previously allocated memory. I've just begun coding in C, so I'm not sure if something is happening under the hood that I should know about. Any help would be greatly appreciated.
so I am new to C programming and allocating memory. So I have written a program that does matrix multiplication. I have allocated memory for the 1d array within the 2d array for matrix 1 and same with matrix 2. Below is my code and I do not understand why I am getting a heap buffer overflow. Input contains a file that contains dimensions and components of both matrixes. An example file format might contain the following format
3 3
1 2 3
4 5 6
7 8 9
3 3
1 2 3
4 5 6
7 8 9
The first line 3 and 3 would mean 3 rows and 3 columns of matrix 1. Hence when reading it from the file it would be stored in rows1 and columns1. Next, 1-9 would be contained in the first matrix. 3 and 3 would be 3 rows of matrix 2 and 3 columns of matrix 2. Hence it would be stored in rows2 and columns2. All these numbers are separated by tabs. The above file was the one of many I tested and it got my a heap buffer overflow.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void print(int** square, int rows,int columns);
int main(int argc, char** argv) {
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("error\n");
return 0;
}
int rows1 = 0; int columns1 = 0; int num = 0;
fscanf(fp, "%d", &rows1);
fscanf(fp, "%d", &columns1);
int** square = (int**) malloc(sizeof(int*) * rows1);
for (int i = 0; i < rows1; i++) {
square[i] = (int*) malloc(sizeof(int) * columns1);
}
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns1; j++) {
fscanf(fp, "%d", &num);
square[i][j] = num;
}
}
int rows2 = 0; int columns2; int num2 = 0;
fscanf(fp, "%d", &rows2);
fscanf(fp, "%d", &columns2);
int** square2 = (int**) malloc(sizeof(int*) * rows2);
for (int i = 0; i < rows2; i++) {
square2[i] = (int*) malloc(sizeof(int) * columns2);
}
for (int i = 0; i < rows2; i++) {
for (int j = 0; j < columns2; j++) {
fscanf(fp, "%d", &num2);
square2[i][j] = num2;
}
}
if (columns1 != rows2) {
printf("bad-matrices\n");
return 0;
}
int ans = 0;
int** answer = (int**) malloc(sizeof(int*) * rows1);
for (int i = 0; i < rows1; i++) {
answer[i] = (int*) malloc(sizeof(int) * columns2);
}
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns2; j++) {
for (int k = 0; k < rows2; k++) {
ans += square[i][k] * square2[k][j];
}
answer[i][j] = ans;
ans = 0;
}
}
print(answer, rows1, columns2);
fclose(fp);
return 0;
}
void print(int** square, int rows, int columns) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
printf("%d\t", square[i][j]);
}
printf("\n");
}
return;
}
Outcome:
==31599== ERROR: AddressSanitizer: heap-buffer-overflow on address.....
"heap-buffer-overflow" means that you created a buffer of a certain size, but tried to access beyond the bounds of the buffer. This normally means that either you have a loop that's using the wrong value for an upper bound, or that one of your buffers is not actually the size that you think it is.
It's hard to tell for sure what's going on here. The code copy/pasted into my gcc appears to work as expected (I don't have access to AddressSanitizer at the moment though). The first thing I noticed about your code was that it uses values read from the input file both for buffer sizes and for loop bounds without any sort of sanity checking. My recommendation is to step through this code in your debugger and make sure that the values that get read from disk and the computed buffer sizes are all what you expect them to be. All it takes is for one of those scanf() calls to encounter something unexpected, return zero, and throw all of your computations off.
Also, it might be useful if you include the entire output of the compiler's error message (dont' forget to compile in debug mode). The AddressSanitizer output normally includes a stack trace that can point you to the line number where the problem occurred. Also useful would be the name and version number of your compiler, plus whatever command-line options you're using.
Using malloc
First, your code is fine, but that doesn't meant is doesn't contain problems. First, let's look at your use of malloc, e.g.
int** answer = (int**) malloc(sizeof(int*) * rows1);
There is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?. Further, and this is more style than anything else, the '*'s showing the levels of indirection go with the variable not the type. Why?
int* a, b, c;
That certainly does not declare 3-pointers to int. It declares a single pointer and two integers, e.g.
int *a, b, c;
When setting the type-size for the allocation, if you always use the dereferenced pointer itself, you will never get your type-size wrong, e.g.
int **answer = malloc (rows1 * sizeof *answer);
If Allocate it, You Must Validate It, & It's Up To You to free it
For every allocation, you should check that the pointer returned by malloc, calloc, realloc is not NULL. Allocation functions do fail when you run out of memory. Always check.
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Simply declare a function to free your pointer arrays, and pass each to the free function along with the row-count before your program exits, e.g.
void freearr (int **a, int rows)
{
for (int i = 0; i < rows; i++)
free (a[i]);
free (a);
}
and
...
fclose(fp);
freearr (square, rows1);
freearr (square2, rows2);
freearr (answer, rows1);
return 0;
Why Do I Get: ERROR: AddressSanitizer: heap-buffer-overflow on address.....?
This is more a result of your compiler telling you to double-check your use of array bounds. Specifically here it most likely results from:
int answer = malloc (rows1 * sizeof *asnwer);
for (int i = 0; i < rows1; i++)
answer[i] = malloc (columns2 * sizeof *answer[i]);
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns2; j++) {
for (int k = 0; k < rows2; k++) {
ans += square[i][k] * square2[k][j];
}
answer[i][j] = ans;
Note: how answer is sized using the bounds of rows1 and columns2, while square is allocated using rows1, columns1 and square2 with rows2, columns2. Your compiler can help you spot potential heap overflow by keeping track of the variables used to size the allocation. Some compilers are better than others at this.
If the compiler cannot determine that the limits you are using to iterate over your array, it can throw the warning about potential buffer overflow. (all it should care about is the value of the limits used, but like I said, some compilers are better than others...)
After allocating with the limits set out above, you then proceed to iterate over the pointer arrays with different limits that were read into separate and unrelated variables. Using rows1, columns2 to iterate over square, square2 & answer. Think about it, while you know columns1 == columns2, then compiler has no guarantee of that. Same for rows2 == rows1.
Your compiler has no guarantee that using rows1 with square2 won't write beyond its allocated size. Likewise it has no guarantee that using columns2 won't violate the bounds of square. Your test of columns1 != rows2 doesn't provide any guarantee for rows1 == columns2 or rows1 == rows2, etc...
So white all of the limits used are fine -- your compiler cannot guarantee it and warns. However, since you tediously picked though your code to know your limits are good, all it takes is a fraction of a second to confirm it, e.g.
$ valgrind ./bin/read2darrq dat/arr_2-3x3.txt
==29210== Memcheck, a memory error detector
==29210== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29210== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==29210== Command: ./bin/read2darrq dat/arr_2-3x3.txt
==29210==
90 96 102
216 231 246
342 366 390
==29210==
==29210== HEAP SUMMARY:
==29210== in use at exit: 0 bytes in 0 blocks
==29210== total heap usage: 13 allocs, 13 frees, 732 bytes allocated
==29210==
==29210== All heap blocks were freed -- no leaks are possible
==29210==
==29210== For counts of detected and suppressed errors, rerun with: -v
==29210== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I'm trying to free mem from 2 dimensional array the same way like in this: [C: Correctly freeing memory of a multi-dimensional array
//initialization
int **tab;
int i,j;
int x_max=5,y_max=7;
tab = calloc(x_max+1, sizeof(int));
for(j = 0; j <=x_max+1; j++)
{
tab[j] = calloc(y_max+2, sizeof(int));
}
and than:
for (i = 0; i <=x_max+1; i++)
{
free(tab[i]);
}
free(tab);
This seems to be like in the example in above link, but my program keeps crashing (when I comment freeing mem part everything works good.) Also when I try to debug program line by line everything works. (Debugger finished with status 0)
First of all, it's not a 2D array. It's a jagged array.
Your initial allocation is problematic. You want to allocate x_max+1 pointers, not ints. And you are accessing outside of the bounds since you allocated x_max+1 pointers, yet access upto x_max+2 pointers.
It's usually preferred to use the thing itself to allocate memory such as:
tab = calloc(x_max+1, sizeof *tab);
so that you don't need to worry about the type being changed later.
tab = calloc(x_max+1, sizeof(int));
for(j = 0; j <=x_max+1; j++)
{
tab[j] = calloc(y_max+2, sizeof(int));
}
should be
tab = calloc(x_max+1, sizeof *tab); /* equivalent to: tab = calloc(x_max+1, sizeof(int*)); */
for(j = 0; j < x_max+1; j++)
{
tab[j] = calloc(y_max+2, sizeof(int));
}
You should also check the return value of calloc() for failures.
I tried the following to reallocate a 2D float array whose size chages from 2X2 to 3X3. The code throws a segfault while trying to realloc memory for weights[2].
num_vertices = 2;
float **weights = malloc(num_vertices*sizeof(float *)); // weight array matrix
for(i = 0; i < num_vertices; i++){
weights[i] = malloc(num_vertices*sizeof(float));
}
num_vertices = 3;
weights = realloc(weights, num_vertices*sizeof(float *)); // weight array matrix
for(i = 0; i < num_vertices; i++){
weights[i] = realloc(weights[i], num_vertices*sizeof(float));
}
Of course, I can free the 2D array and malloc again, but I was looking for a more elegant solution. Any ideas?
The problem is that weights[2] contains garbage after you realloc weights.
You probably want to do something like this:
new_vertices = 3;
weights = realloc(weights, new_vertices*sizeof(float *));
for(i = 0; i < new_vertices; i++)
{
if (i >= num_vertices)
weights[i] = NULL;
weights[i] = realloc(weights[i], new_vertices*sizeof(float));
}
num_vertices = new_vertices;
Note that you have a potential memory leak if realloc ever fails. Since you have no error checking yet though this probably doesn't matter for now.
The realloc of weights[2] is trying to realloc unallocated memory, since weights[2] was never assigned any pointer.
Usually, if you want a 2D array, just use wegihts[width*y + x] to index into the array, instead of making an array of pointers.
You can't loop to the new vertice count, as that part of the outer array is not allocated yet and contain uninitialized data. Instead loop to the new num_vertices - 1 and reallocate, then create a brand new weights[num_verticees - 1].