(edit)
can someone help me to understand why the allocation of a dynamic array is based on two pointers ( this code works without any problem)
int main(int argc, char** argv) {
int i;
int n=3;
int* *t1;
*t1 = (int*) malloc(n*sizeof(int));
for (i = 0 ; i <n ; i++)
{
scanf("%d",(*t1+i));
}
for ( i=0; i<n; i++)
{
printf("%d",*(*t1+i));
}
while the only writing that i know is
int* t;
t = (int*) malloc(n*sizeof(int));
so what is the interest of using *t instead of t.
Thank you.
Your question is unclear because you haven't specified what it is you are attempting to achieve. Later in a comment, you indicate you need a simple 1D array, but that isn't included in your question. Let's cover both case plus the case of using a pointer-to-array and make sure you understand the basics.
To understand dynamic allocation, you must understand there are no arrays involved (the exception being allocating for a pointer-to-array of fixed size).
Otherwise, dynamic allocation encompasses allocation of a block of memory of a given size and assignment of the starting address for that new block of memory to a pointer. In C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc? (in C++ it is required)
Allocating Memory For Integers
When you want to allocate a block of memory for the storage of integers, you simply allocate a block big enough to hold the number of integers you want to store, and assign the starting address for the new block of memory to a pointer. Let's take it step-by-step:
int *t;
declares a pointer-to int to which the beginning address for an allocated block of memory can be assigned.
int n = 100;
t = malloc (n * sizeof *t);
malloc allocates a new block of memory of n * sizeof *t bytes which is sufficient in size to hold n integer values and the beginning address for that block is assigned to the pointer t. Using the dereferenced sizeof *t to set the type-size ensures your type-size is correct. (t being a pointer-to int, when you dereference t (e.g. *t), your type is plain-old int, so sizeof *t is equivalent to sizeof (int))
It may not seem like it matters now (and for trivial types it doesn't make a lot of difference), but as the type of objects you deal with grow in complexity and levels of pointer indirection, mistakenly setting an incorrect type-size becomes a common problem with dealing with allocated nested structures, etc.. That is why simply using the dereferenced pointer to set type-size is recommended.
Let's take a simple example that users a pointer int *t_1D; to emphasize it is single linear allocation that can be indexed as a simple 1D array:
#define NUMINT 50 /* number of integers for t_1D */
...
int main (void) {
int *t_1D = NULL; /* pointer to int */
t_1D = malloc (NUMINT * sizeof *t_1D); /* allocate storage for NUMINT int */
if (t_1D == NULL) { /* validate EVERY allocation, handle error */
perror ("malloc-t_1D");
return 1;
}
for (int i = 0; i < NUMINT; i++)
t_1D[i] = i + 1; /* assign a value to each integer */
puts ("\nvalues in t_1D (with \\n every 5th integer)\n");
for (int i = 0; i < NUMINT; i++) { /* loop over each value */
if (i && i % ARRSZ == 0) /* simple mod test to output newline */
putchar ('\n');
printf (" %3d", t_1D[i]); /* output value at address */
}
puts ("\n");
free (t_1D); /* don't forget to free what you allocate */
Above when you are done with that block of memory, you must free() the block to prevent a memory leak. Understand for trivial examples where you allocate in main() the memory is freed on program exit. However, it is important to develop good habits early as you will commonly be allocating in a function all and if the memory is not freed before your function returns (or later freed in the caller before it returns) you lose the pointer to the block and it cannot be free -- resulting in a memory leak.
Simulating a 2D Array with a Pointer-To-Pointer
If you use a pointer-to-pointer (e.g. int **t;) as your pointer, your allocation is a two-step process. First you allocate a block of memory to hold some number of pointers (which you generally think of as the number of rows for the object you are allocating).
Then in a second set of allocations, you will allocate a block of memory to hold the number of integers-per-row you wish to store per-row (generally thought of as the col (column) number of integers) and assign the starting address for each allocated block to one of your allocated pointers -- in sequence.
The result is a data structure where you allocate 1-block of memory to hold row number pointers and and row blocks of memory to hold col number of integers. Then you can access each of the memory locations just as you would access values in a 2D array.
However, note since there are multiple allocations required to create an object from a pointer-to-pointer, there will be multiple calls to free required to free the memory allocated to the object.
Now let's look at how that can be used. Below, we will use int **t_2D; as the variable name to indicate we are storing an object that we can index as a 2D array:
#define ARRSZ 5 /* number of integers per-row for t_2D and t_PTA */
...
int **t_2D = NULL; /* pointer to pointer to int */
...
/* a pointer to pointer (allocate pointers, then ints for each pointer) */
t_2D = malloc (NUMINT/ARRSZ * sizeof *t_2D); /* allocate 10 pointers */
if (!t_2D) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++)
/* allocate/validate storage for 5 int assign start address to each ptr */
if (!(t_2D[i] = malloc (ARRSZ * sizeof *t_2D[i]))) { /* on failure */
while (i--) /* free previously allocated block for int */
free (t_2D[i]);
free (t_2D); /* free pointers */
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_2D[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_2D output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_2D[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
free (t_2D[i]); /* free integers */
free (t_2D); /* free pointers */
Note the loop at the end that loops over each pointer freeing the storage for integers before calling free to free the block of memory holding the pointers themselves.
A Pointer-To-Array -- Single Allocation, Single-Free, 2D Indexing
There is one other common allocation that you will run into that warrants explanation. You can use a pointer-to-array of fixed length (e.g. int (*t_PTA)[CONST];) and then allocate storage for some number of the fixed arrays in a single call and be able to address the object as a 2D array just as was done above with t_2D. Since there is only a single-allocation required, there is only a single-free needed to free the memory associated with the object.
(note: do not confuse a poitner-to-array (e.g. int (*p)[CONST]) with an array-of-pointers (e.g. int *p[CONST]), they are two distinct types)
To allocate, use and free an object create from a pointer-to-array, you can do the following:
/* a pointer to array -- single allocation, single-free, 2D indexing */
int (*t_PTA)[ARRSZ] = NULL; /* pointer to array of int[ARRSZ] */
t_PTA = malloc (NUMINT/ARRSZ * sizeof *t_PTA); /* storage for 50 integers */
if (!t_PTA) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_PTA[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_PTA output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_PTA[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
free (t_PTA);
(note: the convenience of the single free (t_PTA); used to free all memory associated with the object.)
Now let's put it altogether in a workable example:
#include <stdio.h>
#include <stdlib.h>
#define ARRSZ 5 /* number of integers per-row for t_2D and t_PTA */
#define NUMINT 50 /* number of integers for t_1D */
int main (void) {
int *t_1D = NULL, /* pointer to int */
**t_2D = NULL, /* pointer to pointer to int */
(*t_PTA)[ARRSZ] = NULL; /* pointer to array of int[ARRSZ] */
/* handling simple storage for integers */
t_1D = malloc (NUMINT * sizeof *t_1D); /* allocate storage for NUMINT int */
if (t_1D == NULL) { /* validate EVERY allocation, handle error */
perror ("malloc-t_1D");
return 1;
}
for (int i = 0; i < NUMINT; i++)
t_1D[i] = i + 1; /* assign a value to each integer */
puts ("\nvalues in t_1D (with \\n every 5th integer)\n");
for (int i = 0; i < NUMINT; i++) { /* loop over each value */
if (i && i % ARRSZ == 0) /* simple mod test to output newline */
putchar ('\n');
printf (" %3d", t_1D[i]); /* output value at address */
}
puts ("\n");
free (t_1D); /* don't forget to free what you allocate */
/* a pointer to pointer (allocate pointers, then ints for each pointer) */
t_2D = malloc (NUMINT/ARRSZ * sizeof *t_2D); /* allocate 10 pointers */
if (!t_2D) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++)
/* allocate/validate storage for 5 int assign start address to each ptr */
if (!(t_2D[i] = malloc (ARRSZ * sizeof *t_2D[i]))) { /* on failure */
while (i--) /* free previously allocated block for int */
free (t_2D[i]);
free (t_2D); /* free pointers */
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_2D[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_2D output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_2D[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
free (t_2D[i]); /* free integers */
free (t_2D); /* free pointers */
/* a pointer to array -- single allocation, single-free, 2D indexing */
t_PTA = malloc (NUMINT/ARRSZ * sizeof *t_PTA); /* storage for 50 integers */
if (!t_PTA) { /* validate EVERY allocation */
perror ("malloc-t_2D");
return 1;
}
for (int i = 0; i < NUMINT/ARRSZ; i++) /* loop over pointers */
for (int j = 0; j < ARRSZ; j++) /* loop over integer storage */
t_PTA[i][j] = (i * ARRSZ) + j + 1; /* assign value for each int */
puts ("values in t_PTA output by row x col:\n");
for (int i = 0; i < NUMINT/ARRSZ; i++) {
for (int j = 0; j < ARRSZ; j++)
printf (" %3d", t_PTA[i][j]); /* output each integer */
putchar ('\n');
}
putchar ('\n');
free (t_PTA);
}
Where you compile and run to receive the following:
Example Use/Output
$ ./bin/dynalloc_1_2_pta
values in t_1D (with \n every 5th integer)
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_2D output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_PTA output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
Memory Use/Error Check
It is imperative that you use a memory error checking program to ensure 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.
$ valgrind ./bin/dynalloc_1_2_pta
==10642== Memcheck, a memory error detector
==10642== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10642== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==10642== Command: ./bin/dynalloc_1_2_pta
==10642==
values in t_1D (with \n every 5th integer)
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_2D output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
values in t_PTA output by row x col:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
26 27 28 29 30
31 32 33 34 35
36 37 38 39 40
41 42 43 44 45
46 47 48 49 50
==10642==
==10642== HEAP SUMMARY:
==10642== in use at exit: 0 bytes in 0 blocks
==10642== total heap usage: 14 allocs, 14 frees, 1,704 bytes allocated
==10642==
==10642== All heap blocks were freed -- no leaks are possible
==10642==
==10642== For counts of detected and suppressed errors, rerun with: -v
==10642== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
It is a lot to digest at one sitting, but take it piece-by-piece and dynamic allocation will start to make sense. Let me know if you have furher questions.
In the first case t is a pointer to int*. And the right way would be for allocation:
int **t;
t = (int**) malloc(n*sizeof(int*));
So in other word: it is an array of int*, which is the dynamically allocated version of int* t[n].
And this is different, than the second case, where t is a pointer to int type, basically t is an array of int in this case, which is like the dynamically allocated version of int t[n].
Please clarify. However, the first version is incorrect. If you want to allocate a array of pointers to arrays, you should be doing:
int **t;
t=(int**) malloc(n*sizeof(int*));
To allocate the array of pointers to each individual row, and then allocating the rows:
for (int i=0; i<n; ++i){
t[i] = (int*) malloc(n*sizeof(int));
}
*t won't be valid in your first snippet, since it can be accessed. You would have to allocate **t first.
An int** would be is used when you want to allocate a block of int* objects. In your example, that is not what you have done or indeed want.
In fact you have not allocated or assigned anything to t1, making the allocation to *t1 (i.e. t1[0]) invalid because t1 is itself unknown.
If for example you wanted an allocated array of pointers to multiple allocated int arrays, then int** would be the appropriate data type for the array of pointers to arrays of int:
// Allocate n arrays of m ints
int** t = malloc( sizeof(int*) * n ) ;
for( int i = 0; i < n; i++ )
{
t[i] = malloc( sizeof(int) * m ) ;
}
Then for example t[2][3] refers to the fourth element in the third block of of int.
It is not an issue of syntax; they are not different forms of the same thing; they are semantically different, and in the context of your example int** is inappropriate and semantically incorrect.
Related
I tried creating function that dynamically allocates memory for 2 dimensional array and put some integer values into the array. Overall, the function worked as expected but there were some error. So I did the same thing within main() and got the right result. My code is like below:
#include <stdlib.h>
#include <stdio.h>
void test(int d1, int d2, int ***p){
int value;
*p = (int **)(malloc(sizeof(int)*d1));
for (int i = 0; i < d1; i++){
(*p)[i] = (int *)(malloc(sizeof(int)*d2));
for (int j = 0; j < d2; j++){
(*p)[i][j] = i * 10 + j;
}
}
printf("\n");
}
int main(void){
int d1, d2;
int ** ptr;
printf("length of 1st dimension?\n");
scanf("%d", &d1);
printf("length of 2nd dimension?\n");
scanf("%d", &d2);
test(d1, d2, &ptr);
for (int i=0; i<d1; i++){
for (int j=0; j<d2; j++){
printf("%d ", ptr[i][j]);
}
printf("\n");
}
free(ptr);
ptr = (int **)(malloc(sizeof(int)*d1));
for (int i=0; i< d1; i++){
ptr[i] = (int *)(malloc(sizeof(int)*d2));
for (int j=0; j<d2; j++){
ptr[i][j] = i *10 +j;
}
}
printf("\n######################\n\n");
for (int i=0;i<d1;i++){
for (int j=0; j<d2;j++){
printf("%d ", ptr[i][j]);
}
printf("\n");
}
free(ptr);
return 0;
}`
When I passed 5 as a length of 1st and 2nd dimension, I got the result like below:
length of 1st dimension?
5
length of 2nd dimension?
5
532699424 32725 2 3 4
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
######################
0 1 2 3 4
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
I think, except that I passed pointer to pointer to pointer as an argument to the function, I did the same thing. However some values in the first row are different. And I got different value for the first row whenever I executed the function.
Could someone please let me know what I did wrong?
Thank you in advance.
The lines
*p = (int **)(malloc(sizeof(int)*d1));
ptr = (int **)(malloc(sizeof(int)*d1));
are wrong. The elements is int*, but only room for int is allocated per element.
This may cause trouble if int* is larger than int (for example, when int* is 8 bytes and int is 4 bytes).
The lines should be
*p = malloc(sizeof(int*)*d1);
ptr = malloc(sizeof(int*)*d1);
or (with risk of making mistake reduced by avoiding writing type manually)
*p = malloc(sizeof(*p)*d1);
ptr = malloc(sizeof(*ptr)*d1);
See also: c - Do I cast the result of malloc? - Stack Overflow
I want to free the double pointer, the problem is I was receiving as parameter another double pointer which actually makes a copy of the one I wanna free but that means it doesn't actually free the original, so how can I free the original in another function.
I've tried passing a double pointer as argument and a pointer pointing to this double pointer too but none of this worked.
int main(){
int ** matrix;
int rows = 5;
int cols = 6;
matrix = createMatrix(rows, cols);
printf("%d\n", matrix[2][3]);
freeMatrix(matrix, rows);
printf("%d\n", matrix[2][3]);
}
int** createMatrix(int row, int col){
int **m = (int **)malloc(row * sizeof(int*));
for(int x = 0; x < row; x++){
m[x] = (int *)malloc(col * sizeof(int));
}
return m;
}
void freeMatriz(int **m, int row){
for(int x = 0; x < row; x++){
free(m[x]);
}
free(m);
}
I was trying to print a position, lets say matrix[2][3] before and after the free; but both times its printing the number when after the print it shouldn't because that space in memory its supposed to be freed which apparently is not happening.
other than the typo in the
void freeMatriz(int **m, int row)
^
This is correctly freeing up the memory. The printf after freeing the matrix should actually result in an access violation. Which when testing with a MUCH larger 1024x2048 matrix this is what happens. My theories are as follows...
The memory has not yet been reclaimed and was still within program reach...
Some sort of delay in garbage collection or something.. lol
I'll leave it up to someone who might know why the second printf worked with such a small memory space being allocated to do so.. ;) would love to know the exact reason..
if you step through this with a debugger you will see the memory does get freed properly and if stepped through with a debugger the second printf results in an access violation... so it's gotta have something to do with the kernel.. :)
If you look at the Working Set and the Memory allocation in task manager, and put a system("pause") or getchar() (whatever type of break you want) before the free.. you can allocate a large matrix, check in in task manager... resume the program (with another break after the free). and you will see that the memory is being released. :)
Your two primary problems are:
You fail to validate the return of each allocation so malloc could have failed and you would have no way of knowing; and
After allocating storage for your integer values, you fail to initialize the memory, leaving the memory holding whatever garbage values happened to be present at that memory location (you can, and in the case of your integer allocations, use calloc to allocate and initialize at the same time, or use memset to do the same)
Your attempt to access matrix[2][3] before free() was simply accessing a uninitialized 4-bytes of memory containing whatever bits happened to be there. Your attempt to access matrix[2][3] after free() invokes Undefined Behavior. After free(), you can no longer validly access the memory that has been freed.
If you allocate, you must validate... It's not a matter of if malloc can fail returning NULL, it is a matter of when malloc fails returning NULL. To handle the failure case, you must always check the return of the allocation function (just as you do with every input function) you use. It is simple, if malloc returns NULL the allocation failed. So just check, e.g.
int **creatematrix (int row, int col)
{
int **m = malloc (row * sizeof *m);
if (!m) { /* if you allocate -- you must VALIDATE */
perror ("malloc-m");
return NULL;
}
for (int x = 0; x < row; x++) {
if (!(m[x] = malloc (col * sizeof *m[x]))) { /* ditto */
perror ("malloc-m[x]");
while (x--) /* on error free any allocated memory */
free (m[x]);
free (m); /* before returing NULL */
return NULL;
}
}
return m;
}
(note: before returning NULL you should free() any memory you have allocated up to that point to prevent a memory leak when you return NULL)
In your calling function (main() here), you need to validate the return of your creatematrix function to determine success/failure of the allocate -- before you make use of the memory, e.g.
int main (void) {
int **matrix,
rows = 5,
cols = 6;
if (!(matrix = creatematrix (rows, cols))) /* VALIDATE allocations */
exit (EXIT_FAILURE);
for (int i = 0; i < rows; i++) { /* loop initializing all values */
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j;
printf (" %3d", matrix[i][j]); /* output all values */
}
putchar ('\n');
}
freematrix (matrix, rows); /* free all allocated memory */
}
Now you can free() all memory (which except for the typo of 'z' instead of 'x' you were doing correctly). Putting it altogether you could do:
#include <stdio.h>
#include <stdlib.h>
int **creatematrix (int row, int col)
{
int **m = malloc (row * sizeof *m);
if (!m) { /* if you allocate -- you must VALIDATE */
perror ("malloc-m");
return NULL;
}
for (int x = 0; x < row; x++) {
if (!(m[x] = malloc (col * sizeof *m[x]))) { /* ditto */
perror ("malloc-m[x]");
while (x--) /* on error free any allocated memory */
free (m[x]);
free (m); /* before returing NULL */
return NULL;
}
}
return m;
}
void freematrix (int **m, int row)
{
for (int x = 0; x < row; x++)
free (m[x]);
free (m);
}
int main (void) {
int **matrix,
rows = 5,
cols = 6;
if (!(matrix = creatematrix (rows, cols))) /* VALIDATE allocations */
exit (EXIT_FAILURE);
for (int i = 0; i < rows; i++) { /* loop initializing all values */
for (int j = 0; j < cols; j++) {
matrix[i][j] = i * cols + j;
printf (" %3d", matrix[i][j]); /* output all values */
}
putchar ('\n');
}
freematrix (matrix, rows); /* free all allocated memory */
}
Example Use/Output
$ ./bin/freematrix
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
18 19 20 21 22 23
24 25 26 27 28 29
Memory Use/Error 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.
$ valgrind ./bin/freematrix
==17080== Memcheck, a memory error detector
==17080== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==17080== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==17080== Command: ./bin/freematrix
==17080==
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
18 19 20 21 22 23
24 25 26 27 28 29
==17080==
==17080== HEAP SUMMARY:
==17080== in use at exit: 0 bytes in 0 blocks
==17080== total heap usage: 6 allocs, 6 frees, 160 bytes allocated
==17080==
==17080== All heap blocks were freed -- no leaks are possible
==17080==
==17080== For counts of detected and suppressed errors, rerun with: -v
==17080== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
Why is the data preserved for the second call when I haven't used static?
Here is the code, the output and what I've expected the output should be.
#include <stdio.h>
void fun(int len)
{
int arr[10];
int i;
for (i = 0; i < len; i++)
arr[i] = (i+1) * 10;
for (i = 0; i < 10; i++)
printf("%d ", arr[i]);
printf("\n");
}
int main(void) {
fun(10);
fun(4);
return 0;
}
output:
10 20 30 40 50 60 70 80 90 100
10 20 30 40 50 60 70 80 90 100
expected output:
10 20 30 40 50 60 70 80 90 100
10 20 30 40 0 0 0 0 0 0
int arr[10]; declares an array of 10 int elements on the stack. Its elements are uninitialized. If you attempt to access them without initialization, as is the case with fun(4), you may see garbage values, you may happen to see old memory contents (as you did here), or you may crash the program with a segmentation fault if the memory page belongs to another program. You may even get your expected output! In fact, anything can happen because behavior is undefined by the specification.
To meet your expectations, initialize the array in any way you choose, such as one of the following:
int arr[10] = {};
int arr[10] = {0};
int arr[10];
memset(arr, 0, sizeof(int) * 10);
int arr[10];
for (int i = 0; i < 10; i++) {
arr[i] = 0;
}
etc.
Please initialize array.
Like this
void fun(int len)
{
int arr[10] = {0}; //changed
int i;
for (i = 0; i < len; i++)
arr[i] = (i+1) * 10;
for (i = 0; i < 10; i++)
printf("%d ", arr[i]);
printf("\n");
}
You are invoking undefined behavior by accessing uninitialized memory. The result could be literally anything, including your computer growing legs and running away.
In practice, what is probably happening is that your function calls occupy the same place on the stack since there are no other calls between or within them. The arr variable ends up on the same spot on the stack both times. The first initialization is more comprehensive than the second, so you don't see total garbage. This is to be expected, but certainly never relied upon.
array arr[] is allocated in stack which is uninitialized by default, the values are the ones used last time this area was allocated, in this it happens to allocate the same stack area between the 2 fun calls, and the stack area was initialized by the first call.
As an exercise, I am trying to build a 2 dimensional array of random integers. I want to assign the random numbers by iterating through the array using pointer arithmetic.
I think I'm having trouble with the following For loop, which I lifted from p268 of C Programming by King.
int *p;
for (p = &a[0][0]; p <= &a[NUM_ROWS-1] [NUM_COLUMNS - 1]; p++)
I'm trying to use a similar loop in a program of my own but the program doesn't seem to assign any values.
#include <stdio.h>
#include <stdlib.h>
int ** make_array(int in_size );
void read_array( int ** a, int n);
int main(void){
int size;
int **p;
size = 5;
p = make_array( size );
read_array( p, size );
return 0;
}
int ** make_array( int in_size ) {
int i, *p, **a;
srand ((unsigned)time(NULL));
a = malloc(in_size * sizeof(int*));
for (i = 0; i < in_size ; i++) {
a[i] = malloc( in_size * sizeof(int));
}
for (p = &a[0][0]; p <= &a[in_size -1 ][in_size - 1]; p++) {
*p = rand() % 10;
}
return a;
}
void read_array( int **a, int n ) {
int i, *p;
for (p = &a[0][0] ; p <= &a[n - 1][n - 1]; p++)
printf("%d ", *p );
}
Now I know I could loop through it pretty easily with nested for loops, this seemed like an elegant way to loop through an array. Any idea what I'm doing wrong?
int *p;
for (p = &a[0][0]; p <= &a[NUM_ROWS-1] [NUM_COLUMNS - 1]; p++)
is valid in two cases:
(1) when 'a' is defined as two dimensional array e.g. int a[NUM_ROWS][NUM_COLUMNS]. In this case, memory chunk is contiguous and hence, it is valid to use pointer variable to iterate through the 2D array elements.
(2) Modify your make_array() function as follows to allocate contiguous chunk of memory to use the above mentioned method.
int ** make_array( int in_size )
{
int i, *p, **a;
int *big_chunk;
srand ((unsigned)time(NULL));
a = (int **)malloc(in_size * sizeof(int*));
big_chunk = (int *)malloc(in_size * in_size * sizeof(int)); <-- change done here
for (i = 0; i < in_size ; i++)
{
a[i] = big_chunk + i * insize; <-- change done here
}
/* Other code */
}
In your original make_array() function, malloc() does not guarantee contiguous memory chunks in successive iteration of malloc() call. Hence, using pointer to iterate through the 2D array elements will not be correct. e.g. once 'p' reaches a[0][in_size-1] then p = &a[0][in_size] will be different than a[1] -> malloc address for 2nd row.
As you have learned, in C, there are no 2D arrays. There are only ways to simulate indexing for 2D arrays. These fall into two categories, (1) creating an array of pointers to arrays, and (2) creating a normal sequential array and using index arithmetic to reference elements in 2D manner. In each case the arithmetic can be thought of in terms of total number of elements in your array (or size of the array) and the number of columns you want to simulate (or the stride) of the array. Knowing the size and stride of the array, with careful indexing, you can use your C - 1D array as a 2D array. To help finish lifting any issues that remain concerning the two types and the use of pointers and indexes, consider the following:
Array of Pointers to type
First, when you are using an array of pointers to type (e.g. int **array) you allocate ROWS number of pointers to COLS sized arrays of type (essentially you have ROWS number of COLS sized arrays.) Then by dereference, you can index your elements as a 2D array (e.g. array[0][x] where 0 <= x < COLS reads all in the array pointed to by the first pointer, array[1][x], the second pointer, and so on...).
To allocate your array of pointers to type, you allocate ROWS number of pointers (where ROWS are equivalent to the size/stride):
int **array = NULL;
...
array = xcalloc (size/stride, sizeof *array);
(note: xcalloc is just a function using calloc with error checking to validate allocation)
After allocating your ROWS number of pointers, you allocate a separate column-array of COLS (or stride) number of elements for each original pointer.
for (i = 0; i < size/stride; i++)
array[i] = xcalloc (stride, sizeof **array);
After you allocate your array of pointers to type, you will use two loops to fill/manipulate your data in your array:
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i][j] = rand() % 1000;
You can access any individual member with simple array[i][j] syntax. Remember you simply consider size/stride as your ROWS and stride as your COLS, so if you are computing the value of ROWS and COLS you could write the above as:
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLS; j++)
array[i][j] = rand() % 1000;
Linear Array Treated as 2D Array
Since you are using a traditional sequential 1D array to hold you data in this case, Declaring and allocating the array is trivial:
int *array = NULL;
...
array = xcalloc (size, sizeof *array);
note: to access the elements of the array in a simulated 2D fashion, you must store the values in the array using the same logic you will use to access the values, which from the loop standpoint will be exactly the same as you did in the pointers to arrays case above. The only differece will be the computation of the index:
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i * stride + j] = rand() % 1000;
Here, a closer look at just how you are simulating array[i][j] access is needed. NOTE: the index for the array:
array[i * stride + j] = rand() % 1000;
When you have a linear 1D array of elements, the indexing that allows you to treat and access values in 2D fashion is given by array[i * stride + j] where i and j represent ROWS and COLS.
Putting all this into a couple of examples will show you just how all the pieces fit together:
Example - Array of Pointers to type
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void *xcalloc (size_t n, size_t s);
int main (int argc, char **argv) {
int **array = NULL;
int size = argc > 1 ? (int)strtol(argv[1], NULL, 10) : 36;
int stride = argc > 2 ? (int)strtol(argv[2], NULL, 10) : 6;
int i,j;
/* test valid size/stride */
if (size < stride || size % stride) {
fprintf (stderr, "error: invalid stride '%d' for %d element array.\n",
stride, size);
return 1;
}
srand (time(NULL)); /* initialize seed */
/* alloc array of pointers to array of integers in memory */
array = xcalloc (size/stride, sizeof *array);
/* allocate arrays of integers */
for (i = 0; i < size/stride; i++)
array[i] = xcalloc (stride, sizeof **array);
/* fill with random values */
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i][j] = rand() % 1000;
/* printing in simulated 2D format */
printf ("\n printing (%d x %d) array\n\n",
size/stride, stride);
for (i = 0; i < size/stride; i++) {
for (j = 0; j < stride; j++)
printf (" %4d", array[i][j]);
putchar ('\n');
}
/* print a particular element array[1][2] */
if (stride > 1)
printf ("\n array[1][1] in (%d x %d) array : %d\n\n",
size/stride, stride, array[1][1]);
/* free allocated memory */
for (i = 0; i < size/stride; i++)
free (array[i]);
free (array);
return 0;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
Example Use/Output
$ ./bin/array_stride_2d 12 2
printing (6 x 2) array
535 68
45 815
348 480
417 151
443 789
267 738
array[1][1] in (6 x 2) array : 815
$ ./bin/array_stride_2d 12 3
printing (4 x 3) array
841 195 147
870 18 892
624 516 820
250 769 532
array[1][1] in (4 x 3) array : 18
$ ./bin/array_stride_2d 12 4
printing (3 x 4) array
116 275 740 510
625 122 386 623
624 879 970 396
array[1][1] in (3 x 4) array : 122
$ ./bin/array_stride_2d 12 6
printing (2 x 6) array
543 631 562 504 307 940
932 75 225 662 181 990
array[1][1] in (2 x 6) array : 75
Example - Linear Array Treated as 2D Array
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void *xcalloc (size_t n, size_t s);
int main (int argc, char **argv) {
int *array = NULL;
int size = argc > 1 ? (int)strtol(argv[1], NULL, 10) : 36;
int stride = argc > 2 ? (int)strtol(argv[2], NULL, 10) : 6;
int i,j;
/* test valid size/stride */
if (size < stride || size % stride) {
fprintf (stderr, "error: invalid stride '%d' for %d element array.\n",
stride, size);
return 1;
}
srand (time(NULL)); /* initialize seed */
/* alloc array of size sequential in memory */
array = xcalloc (size, sizeof *array);
/* fill with random values */
for (i = 0; i < size/stride; i++)
for (j = 0; j < stride; j++)
array[i * stride + j] = rand() % 1000;
/* printing in simulated 2D format */
printf ("\n printing (%d x %d) array\n\n",
size/stride, stride);
for (i = 0; i < size/stride; i++) {
for (j = 0; j < stride; j++)
printf (" %4d", array[i * stride + j]);
putchar ('\n');
}
/* print a particular element array[1][2] */
if (stride > 1)
printf ("\n array[1][1] in (%d x %d) array : %d\n\n",
size/stride, stride, array[1 * stride + 1]);
free (array);
return 0;
}
/** xcalloc allocates memory using calloc and validates the return.
* xcalloc allocates memory and reports an error if the value is
* null, returning a memory address only if the value is nonzero
* freeing the caller of validating within the body of code.
*/
void *xcalloc (size_t n, size_t s)
{
register void *memptr = calloc (n, s);
if (memptr == 0)
{
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
return memptr;
}
Use/Output
$ ./bin/array_stride_1d 12 2
printing (6 x 2) array
220 155
755 51
427 270
691 597
982 995
4 444
array[1][1] in (6 x 2) array : 51
$ ./bin/array_stride_1d 12 3
printing (4 x 3) array
990 837 473
153 10 337
139 940 444
768 625 457
array[1][1] in (4 x 3) array : 10
$ ./bin/array_stride_1d 12 4
printing (3 x 4) array
617 943 444 396
38 357 103 441
646 416 40 586
array[1][1] in (3 x 4) array : 357
$ ./bin/array_stride_1d 12 6
printing (2 x 6) array
364 61 373 723 994 849
793 332 913 991 999 373
array[1][1] in (2 x 6) array : 332
Memory Error Check
$ valgrind ./bin/array_stride_1d 12 6
==21560== Memcheck, a memory error detector
==21560== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==21560== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==21560== Command: ./bin/array_stride_1d 12 6
==21560==
printing (2 x 6) array
359 841 728 356 563 487
626 58 823 270 860 896
array[1][1] in (2 x 6) array : 58
==21560==
==21560== HEAP SUMMARY:
==21560== in use at exit: 0 bytes in 0 blocks
==21560== total heap usage: 1 allocs, 1 frees, 48 bytes allocated
==21560==
==21560== All heap blocks were freed -- no leaks are possible
==21560==
==21560== For counts of detected and suppressed errors, rerun with: -v
==21560== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Hopefully this has been helpful for your learning that there are basically two schemes for treating arrays as 2D arrays in C. You can even be more creative and create dimensional arrays well beyond 2D, just note the index computation quickly become a bit more involved. Even at the 2D level, you can get quite a bit more out of these methods, like row and column vectors, upper/lower matrices, matrix arithmetic, etc. Let me know if you have any questions.
Assuming that a memory address occupies 4 bytes and a char occupies 1 byte:
char** t;
t = malloc(5 * sizeof(char*));
int i;
for (i = 0; i < 5; i++)
t[i] = malloc(sizeof(char) * (i+1));
A minimum of around 35 bytes -- but a typical implementation of malloc will have some minimum allocation size it supports, so in reality, you can expect it to use more memory than that (though exactly how much more will vary).
In a typical case, the minimum allocation will be something like 16 or even 32 bytes, in which case most of the sizes you specified above don't really make any difference -- the last 5 allocations will all be of whatever the minimum happens to be. In a typical case, sizes larger than that will be rounded up to the next power of 2 as well.
That would give 32 bytes for your first allocation, and either 16 or 32 (i.e., the minimum supported size) for each of your other five, for a total of either 112 or 192 bytes.
35 bytes (Look below for breakup)
char** t;
t = malloc(5 * sizeof(char*)); // 5 * 4 = 20 bytes
int i;
for (i = 0; i < 5; i++)
t[i] = malloc(sizeof(char) * (i+1)); //1 + 2 + 3 + 4 + 5 = 15 bytes
Let the computer compute for you:
char** t;
t = (char**) malloc(5 * sizeof(char*));
int i;
for (i = 0; i < 5; i++)
t[i] = (char*) malloc(sizeof(char) * (i+1));
unsigned int sz = 5 * sizeof(char*);
for (i = 0; i < 5; i++)
sz += sizeof(char) * (i+1);
printf("%d\n", sz);
35 on a 32 bits machine.
20 for that
t = malloc(5 * sizeof(char*));
15 for that: 5+4+3+2+1
int i;
for (i = 0; i < 5; i++)
t[i] = malloc(sizeof(char) * (i+1));
Get how many bytes are allocated ON YOUR SYSTEM with, for example
#define malloc(s) mm(s)
void *mm(size_t s) {
printf("allocating %d ...\n", (int)s);
return (malloc)(s);
}
/* your code */
Of course, you can sum the sizes instead of printing them.
The malloc() allocates space rounded up to 16 bytes (at least in win32), so you'll use 32 bytes in the first alloc and 16*5 in the loop.
There is also overhead of malloc (both, time and memory), because malloc() puts a special header, _CrtMemBlockHeader before the memory area it returns (that's why you have to give exactly the same pointer to the free() and are able to use functions like _msize().
So, the memory amount actually used would be 32 + 80 = 112 bytes.
Considering also the overhead for header: + 5 * sizeof(__CrtMemBlockHeader)
the final amount can be as high as 300 bytes, that is ~8 times larger than the expected 35.