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.
Related
I'm trying out triple pointers for the first time.
This question is where I got the info on how to allocate a triple pointer and this is how the triple pointer has been allocated:
//In this case size will always be 4
int size = countLines(file);
printf("size: %d\n", size);
char*** tripleptr = malloc(sizeof(*tripleptr)*size);
int i = 0, k = 0, j = 0;
for(; i < size; i++){
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size);
for(; k< size; k++){
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512);
}
}
If I try to copy a string literal into position [0][0] like this
strcpy(tripleptr[0][0], "something");
it works perfectly (same thing for [0][1] to [0][3]), but
strcpy(tripleptr[1][0], "something");
doesn't (it makes the program go into Segmentation Fault).
What is it that could be causing such a weird behavior?
I can't find any indexing mistake in the memory allocation part
The problem is in your loops:
int i = 0, k = 0, j = 0;
for(; i < size; i++){
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size);
for(; k< size; k++){
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512);
}
}
You initialized i and k before entering the nested loop, but you don't reset k when the inner loop restarts on the next iteration. This means that you only allocated memory for the first row of strings. So tripleptr[1][0] is uninitialized, and dereferencing that pointer gives you undefined behavior.
Explicitly initialize youf loop control variables each time:
int i, k;
for(i=0; i < size; i++){
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size);
for(k=0; k< size; k++){
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512);
}
}
the following proposed code:
illustrates how the block of code should be done
indicates how much memory is actually being allocated
reminds you that the code needs to check for errors
indicates how to handle the error, if one occurs
and now, the proposed code:
//In this case size will always be 4
int size = countLines(file);
printf("size: %d\n", size);
char*** tripleptr = malloc(sizeof(*tripleptr)*size);
for(int i = 0; i < size; i++)
{
tripleptr[i] = malloc(sizeof(*(tripleptr[i]))*size); // is 16 bytes each iteration, assuming a pointer is 4 bytes
for(int k = 0; k< size; k++)
{
tripleptr[i][k] = malloc(sizeof(*(tripleptr[i][k]))*512); // is 4k bytes each iteration
}
}
Note: for robustness:
when calling any of the heap allocation functions: malloc(), realloc(), calloc() : always check (!=NULL) the returned value to assure the operation was successful.
If not successful, call perror( "my error message" ); as that will output to stderr, both your error message and the text reason the system thinks the error occurred. And remember to pass each successfully allocated heap memory pointer to free() before exiting
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.
I am able to declare in a good way two matrices A and B.
But, when using the memcpy (to copy B from A), B gives me arrays of 0s.
How can I do? Is my code correct for using memcpy?
int r = 10, c = 10, i, j;
int (*MatrixA)[r];
MatrixA=malloc(c * sizeof(*MatrixA));
int (*MatrixB)[r];
MatrixB=malloc(c * sizeof(*MatrixB));
memcpy(MatrixB,MatrixA,c * sizeof(MatrixA));
for(i=1;i<r+1;i++)
{
for (j = 1; j < c+1; j++)
{
MatrixA[i][j]=j;
printf("A[%d][%d]= %d\t",i,j,MatrixA[i][j]);
}
printf("\n");
}
printf("\n");printf("\n");printf("\n");printf("\n");printf("\n");
for(i=1;i<r+1;i++)
{
for (j = 1; j < c+1; j++)
{
printf("B[%d][%d]= %d\t",i,j,MatrixB[i][j]);
}
printf("\n");
}
You copied contents before initializing MatrixA .And also you access index out of bound (r+1 evaluates 11 which is out of bound) causing UB. Do this instead -
for(i=0;i<r;i++) // i starts from 0
{
for (j =0; j < c; j++) // j from 0
{
MatrixA[i][j]=j;
printf("A[%d][%d]= %d\t",i,j,MatrixA[i][j]);
}
printf("\n");
}
memcpy(MatrixB,MatrixA,c * sizeof(*MatrixA)); // copy after setting MatrixA
for(i=0;i<r;i++) // similarly indexing starts with 0
{
for (j =0; j < c; j++)
{
printf("B[%d][%d]= %d\t",i,j,MatrixB[i][j]);
}
printf("\n");
}
Is my code correct for using memcpy?
No, your code is wrong, but that's less of a memcpy problem. You're simply doing C arrays wrong.
int r = 10, c = 10, i, j;
int (*MatrixA)[r];
MatrixA=malloc(c * sizeof(*MatrixA));
Ok, MatrixA is now a pointer to a 10-element array of integers right? So the compiler reserves memory for ten ints; however, in the malloc line, you overwrite that with a pointer to a memory region of ten times the size of a single integer. A code analysis tool will tell you that you've built a memory leak.
These mistakes continue throughout your code; you will have to understand the difference between statically allocated C arrays and dynamic allocation using malloc.
I have a small program that generates an SHA1 digest for arguments passed via command line and stores them in an array of pointers to char arrays (I think):
#include <stdio.h>
#include <openssl/sha.h>
int entries = 0; // Keep track of entries added
int main(int argc, char **argv)
{
// Allocate space for the digest array
unsigned char **mds = malloc(1);
// Add entries to the digest, one for each argument passed
for(int k = 1; k < argc; k++) {
mds[k - 1] = malloc(SHA_DIGEST_LENGTH);
SHA1(argv[k], strlen(argv[k]), mds[k - 1]);
entries++;
}
// Print each 20-byte digest
for(int j = 0; j < entries; j++) {
for(int i = 0; i < SHA_DIGEST_LENGTH; i++) { printf("%02x ", *(mds[j] + i)); }
printf("\n");
}
}
Originally I had unsigned char **mds = calloc(argc, SHA_DIGEST_LENGTH); and I was going to try to use realloc() everytime I wanted to add another entry (if I didn't know how many entries I was going to have later).
But then I found out that I didn't need to do that and I didn't even need to allocate any space at all? Just a byte and it still works just fine. That doesn't seem right to me.
Am I just lucking out or something? What am I missing?
Am I just lucking out or something?
Yes.
What am I missing?
Your program writes outside of the allocated memory. Doing so causes undefined behaviour. Anything could happen, including the appearance of correct behaviour.
Adding some free() calls will probably turn up some crashers, but no guarantees - undefined behaviour is undefined, after all.
You are writing in memory not allocated to you. Lucky that you have no crashes so far.
Try using valgrind if it is available on your platform. It will tell you about memory errors both of this variety and when you allocate memory that you forget to free. The program will run slower but you only need to do it for testing purposes.
This part:
// Allocate space for the digest array
unsigned char **mds = malloc(1);
allocates a memory block of size 1 byte and casts its address to unsigned char**. Then later in the first iteration already, when you do:
mds[k - 1] = malloc(SHA_DIGEST_LENGTH);
the malloc returns an address, which is written into the invalid memory causing undefined behavior.
You need to allocate appropriate memory block that will hold pointers and in every iteration you will initialize each of these pointers to point to the memory block that will hold string:
// allocate array of pointers:
unsigned char **mds = malloc( (argc - 1) * sizeof(unsigned char*) );
for (int k = 1; k < argc; k++) {
mds[k - 1] = malloc(SHA_DIGEST_LENGTH);
SHA1(argv[k], strlen(argv[k]), mds[k - 1]);
entries++;
}
...
// cleaning up:
for (int k = 1; k < argc; k++) {
free(mds[k - 1]);
}
free(mds);
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].