How can I free memory in a dynamically allocated array? [duplicate] - c

This question already has answers here:
2D array dynamic memory allocation crashes [duplicate]
(2 answers)
Closed 6 years ago.
I'm a newbie trying to learn how to make dynamics arrays in C. The code doesn't give me any errors when I build it using code:blocks, but when I run it crashes. I think the crash has to do with the way I'm freeing my memory, because the code is giving me the desired output before crashing.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j;
int *p = (int *)malloc(sizeof(*p));
printf("Hello World! I have created a dynamic array of 20x30 integers! \n");
for (i = 0; i <= 19; i++)
{
p[i] = (int )malloc(sizeof(int*));
printf(" %2d ", i);
for (j = i + 1; j <= 29 + i; j++)
{
p[i] = 0;
printf("%2d", j);
}
printf("\n");
}
for (i = 0; i <= 19; i++);
{
free(p[i]);
}
free(p);
return 0;
}

Here's the problem.
First, your first malloc call allocates space for a 1-element array.
You'll want to change it from
int *p = (int *)malloc(sizeof(*p));
to
int *p = (int *)malloc(sizeof(int*) * 20);
And then your second malloc call is slightly incorrect as well.
p[i] = (int )malloc(sizeof(int*));
should be changed to
p[i] = (int *)malloc(sizeof(int));
You just put the asterisk in the wrong place.
Finally, you really only create a 20-element array. All you do in the inner for loop is assign each cell in the array the value 0 times. If you want to make a 20x30 array, you can always take the easy route and create a 1D array and use some math (which is ultimately what the compiler does with non-dynamic 2D arrays anyway):
int main()
{
int *p = (int *)malloc(sizeof(int) * 600);
...
for (i = 0; i <= 19; i++)
{
printf(" %2d ", i);
for (j = 0; j <= 29; j++)
{
p[i * 30 + j] = 0; // It's i * 30, not i * 20 because you have to skip the space that the 'j' dimension takes up.
printf("%2d", j);
}
printf("\n");
}
free((void*)p); //I found the program crashes without the void* cast
}
I've tested this code and it runs.
Hope this helps.

Related

Dynamically allocating space for a 2D array

I am a novice C programmer trying to write a function that dynamically allocates space for a 2D array. I am getting a segmentation fault when running this code & i'm not sure why.
#include <stdio.h>
#include <stdlib.h>
int allocate_space_2D_array(int **arr, int r, int c) {
int i,j;
arr = malloc(sizeof(int *) * r);
for (i = 0; i < r; i++)
arr[i] = malloc(sizeof(int *) * c);
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%p", arr[r][c]);
}
printf("\n");
}
return arr;
}
I expected to be able to print out and see the contiguous memory locations of each spot in the array, but I am never reaching that point in my code, because when I run it, i get a segmentation fault. Would appreciate any help.
Seeing your program i see 3 errors one while you allocate memory for 2D-array,one while you're printing and another one is how you declare the function.
First malloc is ok,the second one is wrong cause you already allocated memory for r(size of row) pointers so it's just like if you have * arr[r],so to allocate memory correctly now you should allocate memory just for int and not for int*.
Second error while printing you put as index for row and column the values r and c,but r and c are the size of matrix , as we know the size of an array or 2D-array goes from 0 to size-1,in your case goes from 0 to r-1 and from 0 to c-1.
Third error you should declare the function not as int but as int** cause you want to return a matrix so the return type is not int but int**.
I change your code to make it work correctly,it should be work.
int** allocate_space_2D_array(int **arr, int r, int c) {
int i,j;
arr = malloc(sizeof(int *) * r);
for (i = 0; i < r; i++)
arr[i] = malloc(sizeof(int ) * c);
for (i = 0; i < r; i++) {
for (j = 0; j < c; j++) {
printf("%p", arr[i][j]);
}
printf("\n");
}
return arr;
}

Put a 2D array into existed memory using double pointer in C [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
totally a newbie in C. I'm trying to put a 2D array into an existing memory space created by malloc. Here is the code:
int main()
{
int **a; //double pointer
int i;
void *ptr = malloc(sizeof(int)*4); //2x2 array
a = (int **)ptr; //start of the array
for(i=0; i<2; i++)
a[i] = (int *)a + i*2;
printf("a: %p\n", a);
printf("a[0]: %p\n", a[0]);
printf("a[1]: %p\n", a[1]);
}
output:
a: 0x1976010
a[0]: 0x1976010
a[1]: 0x1976018
but when I try to access the element:
for(i=0; i<2; i++)
for(j=0; j<2; j++)
a[i][j] = j + i*10;
I got segment fault. Where did I do wrong? Thanks in advance!
If you have an existing (aka already allocated) memory area that you want to use for a 2D array (or rather for an array of array), you should not use a double pointer. Instead you should use a pointer to array of size N
Like
int (*a)[2]; // declare a as a pointer to array (size 2) of int
A complete program could be:
int main()
{
// Allocate a memory area for holding 4 int
void *ptr = malloc(sizeof(int)*4);
int (*a)[2]; // a as a pointer to array (size 2) of int
a = ptr; // make a point to your memory area
// Now a can be used as a "2D array" and data will be stored in the malloc'ed memory
for (int i=0; i<2; ++i)
for (int j=0; j<2; ++j)
a[i][j] = i*100 + j;
for (int i=0; i<2; ++i)
for (int j=0; j<2; ++j)
printf("a[%d][%d]=%d\n", i, j, a[i][j]);
free(ptr);
return 0;
}
Output:
a[0][0]=0
a[0][1]=1
a[1][0]=100
a[1][1]=101
When it comes to dynamic 2D arrays, there's unfortunately a lot of myths and hogwash, widely used bad practice and so on. Forget about pointer-to-pointers, is needlessly complex, error prone and slow.
A detailed explanation of the correct way to do this can be found here: Correctly allocating multi-dimensional arrays.
The correct way to allocate a 2D array dynamically is this:
#include <stdlib.h>
#include <stdio.h>
int main()
{
const size_t X = 2;
const size_t Y = 2;
int (*a)[Y] = malloc( sizeof(int[X][Y]) );
int count = 1;
for(size_t x=0; x<X; x++)
{
for(size_t y=0; y<Y; y++)
{
a[x][y] = count++; // assign some value here
printf("%d ", a[x][y]);
}
printf("\n");
}
free(a);
}
Where int (*a)[Y] is an array pointer to the first element of the 2D array. The first element being a 1D array of type int [Y].
You got segmentation fault because a (a double pointer) is actually having a single pointer value.
There are multiple ways to use 2D array. The following is one of them.
#define ROW (2)
#define COL (3)
int main()
{
int (*a)[COL] = malloc(sizeof(int[ROW][COL]));
if(NULL == a) return -1; //Check if allocation is successfull.
int i, j;
for(i=0; i<ROW; i++)
for(j=0; j< COL; j++)
a[i][j] = i*ROW + j; //Assign some values.
printf("a: %p\n", a);
printf("a[0][0]: %d\n", a[0][0]); //Printing a value.
free(a); //Free the allocated memory.
}
EDIT
This isn't a correct answer, as pointed out by Lundin. There are much better ways to do this I wasn't aware of!
This line
a[i][j] = j + i*10;
is treating a[0] and a[1] as pointers themselves to other arrays, so it's reading their values
a[0]: 0x1976010
a[1]: 0x1976018
as memory locations, and segfaulting.
If you want to dynamically allocate 2d arrays, allocate one dimension of int*s, then iterate through it and allocate memory to each of the indices as ints.
int main()
{
#define DIM_X 2
#define DIM_Y DIM_X
int i = 0;
int j = 0;
int** x = 0;
void* a = malloc(sizeof(int*)*DIM_X);
x = (int**)a;
for (i = 0; i < 2; i++)
{
x[i] = (int*)malloc(sizeof(int)*DIM_Y);
}
// ...
for (i = 0; i < DIM_X; i++)
{
free(x[i]);
}
free(x);
return 0;
}
You could also do some tricky logic to keep everything contiguous, but it may be harder to read.
for (i = 0, j = 0; i < 2; i++)
{
a[(i * 2) + j] = j + (i * 10);
j++;
if (2 < j) j = 0;
}
You have to allocate also storage for the pointers.
int main()
{
int **a; //double pointer
int i;
void *ptr = malloc(sizeof(int *)*2+sizeof(int)*4); //2x2 array
//plus 2xpointers
a = (int **)ptr; //start of the array
for(i=0; i<2; i++)
a[i] = (int *)a + 2 + i * 2; //plus 2 because the first 2 elements
//are your pointers
printf("a: %p\n", a);
printf("a[0]: %p\n", a[0]);
printf("a[1]: %p\n", a[1]);
}

How do we correctly dynamically allocate memory multiple times?

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define MAX_STRING_SIZE 20
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int N, Q;
int i, j, k, l, m, x;
char **str;
scanf("%d\n", &N);
str = (char **)malloc(sizeof(char *) * N);
for(i = 0; i < N; i++){
str[i] = malloc(MAX_STRING_SIZE * sizeof(char));
scanf("%s",str[i]);
}
printf("%d\n",N);
for(j = 0; j < N; j++){
printf("%s",str[j]);
printf("\n");
}
scanf("%d",&Q);
printf("%d\n",Q);
char **qry_str;
qry_str = (char **)malloc(sizeof(char *) * Q);
for(l = 0; l < Q; l++){
qry_str = malloc(MAX_STRING_SIZE * sizeof(char));
scanf("%s",qry_str[l]);
}
for(m = 0; m < N; m++){
printf("%s",qry_str[m]);
printf("\n");
}
for(k = 0; k < N; k++)
free(str[k]);
free(str);
for(x = 0; x < N; x++)
free(qry_str[x]);
free(qry_str);
return 0;
}
I am new to programming, and I am trying to allocate memory for two 2d strings using malloc function, but when I try to input data for the second string qry_str, (null) appears on the screen, and the program exits.
My question is:
How do we dynamically allocate memory for 2D arrays in C multiple times?
Do I need to free the memory first before using it again? (Though when I try to do that it causes segmentation fault error.)
Is this the problem due to my compiler? (I am using gcc.)
In your second case, you're overwriting qry_str inside the loop, which is not what is intended. You most probably want
for(l = 0; l < Q; l++){
qry_str[l] = malloc(MAX_STRING_SIZE * sizeof(char));
scanf("%s",qry_str[l]);
}
That said, a few suggestion:
You don't need four separate counters i, j, l, m. The first clause of for statement re-assigns the counter to 0 anyway, even if you reuse only one.
sizeof(char) is gurantted to be 1 in C. Instead, you should consider writing the statements like
qry_str[l] = malloc(MAX_STRING_SIZE * sizeof *qry_str));
to make them more robust.
Always check for the return values for scanf() family to ensure success.

Segmentation fault when accessing a 2D array in a structure whose pointer is returned from a function

I made a structure who has two members (int and int**), and I return the pointer to this structure from one function to main(). It is fine to access the int value in the structure. However, in main() I got Segmentation fault : 11 when I tried to access the element of the 2D array.
#include<stdio.h>
#include<stdlib.h>
typedef struct Square {
int value;
int **array;
} Square;
Square * generate();
int main(int argc, char *argv[]){
Square *sqrptr = generate();
printf("%d\n", sqrptr -> value);
/* It prints 1 */
/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3 ; j++){
printf("%d ", *(*((sqrptr -> array) + i) + j));
}
printf("\n");
}
/* It gives segmentation fault */
return 0;
}
Square * generate(){
Square mySquare;
mySquare.value = 1;
mySquare.array = malloc(sizeof(int*) * 3);
/* Initialize the 2D array */
for (int i = 0; i < 3; i++){
*(mySquare.array + i) = malloc(sizeof(int) * 3);
for (int j = 0; j < 3; j++){
*(*(mySquare.array + i) + j) = 0;
}
}
/* Print out the 2D array */
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3l ; j++){
printf("%d ", *(*(mySquare.array + i) + j));
}
printf("\n");
}
/* I can see the complete 2D array here */
Square *sqrptr = &mySquare;
return sqrptr;
}
I have tried to generate the Square in main(), and use one pointer of the structure to access my 2D array. It works fine, so I guess I have missed something when I use a pointer returned from other functions. On the other hand, I can access the int value successfully, so I have no clues now.
Could someone please explain the underlying reason for this segmentation fault? Thanks!
You're returning a pointer to a local variable (&mySquare). Stack memory (where local variables reside) is when the function returns, so the resulting pointer is pointing to invalid memory. Allocate the struct, and return the pointer to heap memory:
Square *my_square = malloc(sizeof *my_square);
//do stuff
return my_square;
Or pass a pointer to a stack variable as argument:
Square * generate(Square *my_square)
{
//in case pointer wasn't provided, allocate
if (my_square == NULL) {
my_square = malloc(sizeof *my_square);
if (!my_square)
return NULL; // or exit or whatever
}
//initialize members. To initialize array to 3x3 zero matrix, you can use:
for (int i=0;i<3;++i)
my_square.array[i] = calloc(3, sizeof *my_square->array[i]);
//or even, if you change array member to type int*:
my_square.array = calloc(3*3, sizeof *my_square->array);
//at the end:
return my_square;
}
The latter is arguably the most flexible solution: if you want to work on stack, you call the function like so:
Square my_stack_square;
generate(&my_stack_square);
If you need to use heap memory, you can use:
Square *my_heap_square = generate(NULL);
As Jonathan Leffler pointed out, for a small struct such as this, returning by value isn't too much of a cost. Getting a struct on heap can be achieved in the same way as returning any other type:
Square generate( void )
{
Square my_square;
//initialize
return my_square;
}
//call like so:
Square sq = generate();
The idea here is that you'll use a local variable in the generate function to create a new square, initialize the fields, and then return it. Because in C everything is passed by value, this essentially means the function will assign the value of the local variable from the generate function to the caller's scoped sq variable. For small structs such as this, that's perfectly fine.
What's more, a common thing for compilers to do is to optimise these kinds of functions to the equivalent of the second example I posted: Essentially your function will be creating a new Sqaure object on the stack memory of the caller. This can happen, that's not to say it will. It depends on the optimization levels used when compiling, and on the size of the struct you're returning.
Basically, if you want to keep the code as close to what you have now, it's probably easiest to stick to the first version (returning a heap pointer).
The more flexible approach is the second one (as it allows you to use stack and heap, depending on how you call the function).
For now, using the third approach is perfectly fine: the compiler will most likely optimize the code to whatever makes most sense anyway.
Try this:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct Square {
int value;
int **array;
} Square;
Square * generate();
int main(int argc, char *argv[]){
Square *sqrptr = generate();
printf("%d\n", sqrptr -> value);
/* It prints 1 */
/* Print out the 2D array */
int i,j;
for (i = 0; i < 3; i++){
for (j = 0; j < 3 ; j++){
printf("%d ", *(*((sqrptr -> array) + i) + j));
}
printf("\n");
}
/* It gives segmentation fault */
return 0;
}
Square * generate(){
Square* mySquare = (Square*) malloc(sizeof(Square)); //c++ compiler
//Square* mySquare = (void*) malloc(sizeof(Square)); //c compiler
mySquare->value = 1;
mySquare->array = malloc(sizeof(int*) * 3);
/* Initialize the 2D array */
int i,j;
for (i = 0; i < 3; i++){
*(mySquare->array + i) = malloc(sizeof(int) * 3);
for (j = 0; j < 3; j++){
*(*(mySquare->array + i) + j) = 0;
}
}
/* Print out the 2D array */
for (i = 0; i < 3; i++){
for (j = 0; j < 3l ; j++){
printf("%d ", *(*(mySquare->array + i) + j));
}
printf("\n");
}
/* I can see the complete 2D array here */
return mySquare;
}

Allocating contiguous memory for a 3D array in C

I need to allocate contiguous space for a 3D array. (EDIT:) I GUESS I SHOULD HAVE MADE THIS CLEAR IN THE FIRST PLACE but in the actual production code, I will not know the dimensions of the array until run time. I provided them as constants in my toy code below just to keep things simple. I know the potential problems of insisting on contiguous space, but I just have to have it. I have seen how to do this for a 2D array, but apparently I don't understand how to extend the pattern to 3D. When I call the function to free up the memory, free_3d_arr, I get an error:
lowest lvl
mid lvl
a.out(2248,0x7fff72d37000) malloc: *** error for object 0x7fab1a403310: pointer being freed was not allocated
Would appreciate it if anyone could tell me what the fix is. Code is here:
#include <stdio.h>
#include <stdlib.h>
int ***calloc_3d_arr(int sizes[3]){
int ***a;
int i,j;
a = calloc(sizes[0],sizeof(int**));
a[0] = calloc(sizes[0]*sizes[1],sizeof(int*));
a[0][0] = calloc(sizes[0]*sizes[1]*sizes[2],sizeof(int));
for (j=0; j<sizes[0]; j++) {
a[j] = (int**)(a[0][0]+sizes[1]*sizes[2]*j);
for (i=0; i<sizes[1]; i++) {
a[j][i] = (int*)(a[j]) + sizes[2]*i;
}
}
return a;
}
void free_3d_arr(int ***arr) {
printf("lowest lvl\n");
free(arr[0][0]);
printf("mid lvl\n");
free(arr[0]); // <--- This is a problem line, apparently.
printf("highest lvl\n");
free(arr);
}
int main() {
int ***a;
int sz[] = {5,4,3};
int i,j,k;
a = calloc_3d_arr(sz);
// do stuff with a
free_3d_arr(a);
}
Since you are using C, I would suggest that you use real multidimensional arrays:
int (*a)[sz[1]][sz[2]] = calloc(sz[0], sizeof(*a));
This allocates contiguous storage for your 3D array. Note that the sizes can be dynamic since C99. You access this array exactly as you would with your pointer arrays:
for(int i = 0; i < sz[0]; i++) {
for(int j = 0; j < sz[1]; j++) {
for(int k = 0; k < sz[2]; k++) {
a[i][j][k] = 42;
}
}
}
However, there are no pointer arrays under the hood, the indexing is done by the magic of pointer arithmetic and array-pointer-decay. And since a single calloc() was used to allocate the thing, a single free() suffices to get rid of it:
free(a); //that's it.
You can do something like this:
int ***allocateLinearMemory(int x, int y, int z)
{
int *p = (int*) malloc(x * y * z * sizeof(int));
int ***q = (int***) malloc(x * sizeof(int**));
for (int i = 0; i < x; i++)
{
q[i] = (int**) malloc(y * sizeof(int*));
for (int j = 0; j < y; j++)
{
int idx = x*j + x*y*i;
q[i][j] = &p[idx];
}
}
return q;
}
void deallocateLinearMemory(int x, int ***q)
{
free(q[0][0]);
for(int i = 0; i < x; i++)
{
free(q[i]);
}
free(q);
}
I use it and works fine.

Resources