EDIT: Sorry guys, I forgot to mention that this is coded in VS2013.
I have a globally declared struct:
typedef struct data //Struct for storing search & sort run-time statistics.
{
int **a_collision;
} data;
data data1;
I then allocate my memory:
data1.a_collision = (int**)malloc(sizeof(int)*2); //Declaring outer array size - value/key index.
for (int i = 0; i < HASH_TABLE_SIZE; i++)
data1.a_collision[i] = (int*)malloc(sizeof(int)*HASH_TABLE_SIZE); //Declaring inner array size.
I then initialize all the elements:
//Initializing 2D collision data array.
for (int i = 0; i < 2; i++)
for (int j = 0; j < HASH_TABLE_SIZE; j++)
data1.a_collision[i][j] = NULL;
And lastly, I wish to free the memory (which FAILS). I have unsuccessfully tried following some of the answers given on SO already.
free(data1.a_collision);
for (int i = 0; i < HASH_TABLE_SIZE; i++)
free(data1.a_collision[i]);
A heap corruption detected error is given at the first free statement. Any suggestions?
There are multiple mistakes in your code. logically wrong how to allocate memory for two dimension array as well as some typos.
From comment in your code "outer array size - value/key index" it looks like you wants to allocate memory for "2 * HASH_TABLE_SIZE" size 2D array, whereas from your code in for loop breaking condition "i < HASH_TABLE_SIZE;" it seems you wants to create an array of size "HASH_TABLE_SIZE * 2".
Allocate memory:
Lets I assume you wants to allocate memory for "2 * HASH_TABLE_SIZE", you can apply same concept for different dimensions.
The dimension "2 * HASH_TABLE_SIZE" means two rows and HASH_TABLE_SIZE columns. Correct allocation steps for this would be as follows:
step-1: First create an array of int pointers of lenght equals to number of rows.
data1.a_collision = malloc(2 * sizeof(int*));
// 2 rows ^ ^ you are missing `*`
this will create an array of int pointers (int*) of two size, In your code in outer-array allocation you have allocated memory for two int objects as 2 * sizeof(int) whereas you need memory to store addresses. total memory bytes you need to allocate should be 2 * sizeof(int*) (this is poor typo mistake).
You can picture above allocation as:
343 347
+----+----+
data1.a_collision---►| ? | ? |
+----+----+
? - means garbage value, malloc don't initialize allocate memory
It has allocated two memory cells each can store address of int
In picture I have assumed that size of int* is 4 bytes.
Additionally, you should notice I didn't typecast returned address from malloc function because it is implicitly typecast void* is generic and can be assigned to any other types of pointer type (in fact in C we should avoid typecasting you should read more from Do I cast the result of malloc?).
Now step -2: Allocate memory for each rows as an array of length number of columns you need in array that is = HASH_TABLE_SIZE. So you need loop for number of rows(not for HASH_TABLE_SIZE) to allocate array for each rows, as below:
for(int i = 0; i < 2; i++)
// ^^^^ notice
data1.a_collision[i] = malloc(HASH_TABLE_SIZE * sizeof(int));
// ^^^^^
Now in each rows you are going to store int for array of ints of length HASH_TABLE_SIZE you need memory bytes = HASH_TABLE_SIZE * sizeof(int). You can picture it as:
Diagram
data1.a_collision = 342
|
▼ 201 205 209 213
+--------+ +-----+-----+-----+-----+
343 | | | ? | ? | ? | ? | //for i = 0
| |-------| +-----+-----+-----+-----+
| 201 | +-----------▲
+--------+ 502 506 510 514
| | +-----+-----+-----+-----+
347 | | | ? | ? | ? | ? | //for i = 1
| 502 |-------| +-----+-----+-----+-----+
+--------+ +-----------▲
data1.a_collision[0] = 201
data1.a_collision[1] = 502
In picture I assuming HASH_TABLE_SIZE = 4 and size of int= 4 bytes, note address's valuea
Now these are correct allocation steps.
Deallocate memory:
Other then allocation your deallocation steps are wrong!
Remember once you have called free on some pointer you can't access that pointer ( pr memory via other pointer also), doing this calls undefined behavior—it is an illegal memory instruction that can be detected at runtime that may causes—a segmentation fault as well or Heap Corruption Detected.
Correct deallocation steps are reverse of allocation as below:
for(int i = 0; i < 2; i++)
free(data1.a_collision[i]); // free memory for each rows
free(data1.a_collision); //free for address of rows.
Further more this is one way to allocate memory for two dimension array something like you were trying to do. But there is better way to allocate memory for complete 2D array continuously for this you should read "Allocate memory 2d array in function C" (to this linked answer I have also given links how to allocate memory for 3D arrays).
Here is a start:
Your "outer array" has space for two integers, not two pointers to integer.
Is HASH_TABLE_SIZE equal to 2? Otherwise, your first for loop will write outside the array you just allocated.
There are several issues :
The first allocation is not correct, you should alloc an array of (int *) :
#define DIM_I 2
#define DIM_J HASH_TABLE_SIZE
data1.a_collision = (int**)malloc(sizeof(int*)*DIM_I);
The second one is not correct any more :
for (int i = 0; i < DIM_I; i++)
data1.a_collision[i] = (int*)malloc(sizeof(int)*DIM_J);
When you free memory, you have to free in LastInFirstOut order:
for (int i = 0; i < DIM_I; i++)
free(data1.a_collision[i]);
free(data1.a_collision);
Related
The below code is pointer to "array of pointers" code. I am not sure that this is correct.
tags[0][0] = malloc(sizeof(char)*5);
strcpy(tags[0][0],"hi");
tags[0][1] = malloc(sizeof(char)*5);
strcpy(tags[0][1],"h2");
Can anyone please tell are the above lines correct in following code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char *(*tags)[2] = malloc (2 * sizeof *tags);
tags[0][0] = malloc(sizeof(char)*5);
strcpy(tags[0][0],"hi");
tags[0][1] = malloc(sizeof(char)*5);
strcpy(tags[0][1],"h2");
tags[1][0] = "<head";
tags[1][1] = "</head>";
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++)
printf (" %s", tags[i][j]);
putchar ('\n');
}
free (tags);
}
Is there any difference between the above and array of pointers to pointers?
Yes, the code principle is absolutely correct. It's the correct way to do dynamic allocation of a 2D array.
This
char *(*tags)[2]
means that tags is a pointer to an array of 2 char pointers.
So when you do
char *(*tags)[2] = malloc (2 * sizeof *tags);
you allocate an array of two arrays of two char pointers. It's equivalent to:
char* tags[2][2];
when not using dynamic allocation.
So yes, the code is fine. That's exactly the way to do it. And you should always do like that when you want a dynamic 2D array.
However, your code lacks:
free(tags[0][0]);
free(tags[0][1]);
BTW: Storing both pointers to dynamic allocated memory and pointers to string literals in the same array is a bit "strange" and can be problematic as you need to track which pointers to free and which not to free.
This looks ok to me. I haven't seen pointers like this very much in practice, but I would describe tags as "A pointer to a 2-size array of character pointers". When you malloc (2 * sizeof *tags);, you create space for two of of these 2-size array of character pointers. This is what you have from each line:
char *(*tags)[2] = malloc (2 * sizeof *tags);
tags -----> [char*][char*] // index 0 of tags
[char*][char*] // index 1 of tags
// You now have 4 character pointers in contiguous memory that don't
// point to anything. tags points to index 0, tags+1 points to index 1.
// Each +1 on *(tags) advances the pointer 16 bytes on my machine (the size
// of two 8-byte pointers).
Next malloc:
tags[0][0] = malloc(sizeof(char)*5);
+-------> 5 bytes
|
tags ------> [char*][char*] // index 0
^
index 0 of tags[0], this now points to 5 bytes
After first strcpy
strcpy(tags[0][0],"hi");
+-------> {'h', 'i', '\0', <2 more> }
|
tags ------> [char*][char*] // index 0
Next malloc
tags[0][1] = malloc(sizeof(char)*5);
+-------> 5 bytes
|
tags ------> [char*][char*] // index 0
^
index 1 of tags[0], this now points to 5 bytes
Next strcpy
strcpy(tags[0][1],"h2");
+-------> {'h', '2', '\0', <2 more> }
|
tags ------> [char*][char*] // index 0
And finally, the string literal assignments
tags[1][0] = "<head";
tags[1][1] = "</head>";
tags -----> [char*][char*] // index 0 of tags
[char*][char*] // index 1 of tags
| |
| |------> points to string literal "</head>"
|--------------> points to string literal "<head"
If you really want to clean up properly, you should
free(tags[0][1]);
free(tags[0][0]);
// the order of the above doesn't really matter, I just get in the
// habit of cleaning up in the reverse order that I malloced in.
// But if you free(tags) first, you've created a memory leak, as
// there's now no existing pointers to tags[0][0] or [0][1].
free(tags);
Of course, all memory gets reclaimed by the OS as soon as the process exits anyway.
What you want to achieve is array of strings.
char ***tags = malloc(sizeof(char**) * numberofpointers);
for (int i = 0; i < numberofpointers; ++i)
{
tags[i] = malloc(sizeof(char*) * numberofstringsperpointer);
}
for (int i = 0; i < numberofpointers; ++i)
{
for (int j = 0; j < numberofstringsperpointer; ++j)
{
tags[i][j] = malloc(sizeof(char) * (numberofcharacterperstring + 1));
}
}
strcpy(tags[0][0], string)
I'm trying to edit an array (as a pointer) of structs by filling in the default values with new structs that I initialize. Doing so seems to cause some really bizarre problems. I'm learning how to use structs with pointers, so any help is appreciated.
Snippet from the main function (player just saves the startLoc without changing it)
Location** near;
startLoc = initLocation("Base", 5);
player = initPlayer(startLoc);
near = &(startLoc->near);
*near = initLocation("Zero", 0);
*(near + 1) = initLocation("Two", 0);
printf("Start near: %i\n", startLoc->nearCount);
Entire location.c
#include <stdlib.h>
typedef struct Location {
char isValid;
char* name;
struct Location* near;
int nearCount;
} Location;
Location* initLocation(char* name, int nearCount) {
Location* l = malloc(sizeof(Location));
l->name = name;
l->near = calloc(sizeof(Location) * nearCount, 1);
l->nearCount = nearCount;
l->isValid = 1;
return l;
}
Let's start with a basic discussion about a pointer and a pointer-to-pointer. A pointer is simply a variable that holds the address of something else as its value. When you declare a pointer to something, as you have done with your name or near members within your struct you declare a variable that will hold the address in memory where that type object is stored in memory (e.g. the pointer will point to where that object is stored)
When you declare a pointer-to-pointer to type (e.g. Location **near) you have a pointer that holds the address of another pointer as its value. That can be useful in two ways. (1) it can allow you to pass the address of a pointer as a parameter so that the function is able to operate on the original pointer at that address, or (2) it can allow that single pointer to point to a collection of pointers in memory, e.g.
pointer
| pointers allocated struct
near --> +----+ +-------------------+
| p1 | --> | struct Location 1 |
+----+ +-------------------+
| p2 | --> | struct Location 2 |
+----+ +-------------------+
| p3 | --> | struct Location 3 |
+----+ +-------------------+
| .. | | ... |
(a pointer-to-pointer to type struct Location)
In the second case, why choose a pointer-to-pointer as your type instead of just allocating for a collection of that type? Good question. There are two primary reasons, one would be if what you were allocating for can vary in size. For example:
char**
| pointers allocated strings
words --> +----+ +-----+
| p1 | --> | cat |
+----+ +-----+--------------------------------------+
| p2 | --> | Four score and seven years ago our fathers |
+----+ +-------------+------------------------------+
| p3 | --> | programming |
+----+ +-------------------+
| .. | | ... |
or (2) where you want an allocated collection of an even number of objects (such as changing char** above to int**) that can be addressed using 2D-array indexing (e.g. array[2][7])
Allocating for a collection of pointers and objects adds complexity because you are responsible for maintaining two allocated collections, the pointers, and the objects themselves. You must track and reallocate for both your collection of pointers (and the objects -- if needed) and then free() your collection of objects before freeing your allocated block of pointers.
This can be greatly simplified, if you just need some number of the same type object, such as N - struct Location. That gives you a single allocation, single reallocation and single free for those objects themselves (of course each object can in turn contain allocated objects as well). In your case for near it would be similar to:
pointer
|
near --> +-------------------+
| struct Location 1 |
+-------------------+
| struct Location 2 |
+-------------------+
| struct Location 3 |
+-------------------+
| ... |
(a pointer to type struct Location)
In your case you are dealing with needing nested allocated blocks of struct Location. In that sense, where required, you simply need N - struct Location which will all be of the same size and there isn't a compelling need for 2D array indexing. From that standpoint, looking at what you are trying to do (to the best possible guess), simply allocating for blocks of struct Location rather than handling separate blocks of pointers pointing to individually allocated struct Location would seem to make much more sense.
Implementing A Short-Example
While there is nothing wrong with an initLocation() to set up a single struct Location, you may find it makes more sense to simply write an addLocation() function to add a new struct Location to your collection each time it is called. If you initialize your pointer to the collection NULL back in the caller, you can simply use realloc() to handle your initial allocation and subsequent reallocations.
In the following example, we just create a new struct Location for each name in a list and allocate for 3-near objects. You are free to use addLocation() with the near struct Location in each object just as you have with your initial collection, but that implementation is left to you as it is simply doing the same thing on a nested basis.
Putting an addLocation() function together in a manner that looks like what you are attempting, you could do:
Location *addLocation (Location *l, size_t *nmemb, char *name, int nearCount)
{
/* realloc using temporary pointer adding 1 Location */
void *tmp = realloc (l, (*nmemb + 1) * sizeof *l); /* validate EVERY allocation */
if (!tmp) { /* on failure */
perror ("error: realloc-l");
return NULL; /* original data good, that's why you realloc to a tmp */
}
/* on successful allocation */
l = tmp; /* assign reallocated block to l */
l[*nmemb].isValid = 1; /* assign remaining values and */
l[*nmemb].name = name; /* allocate for near */
l[*nmemb].near = calloc(nearCount, sizeof(Location));
if (!l[*nmemb].near) {
perror ("calloc-l[*nmemb].near");
return NULL;
}
l[*nmemb].nearCount = nearCount; /* set nearCount */
(*nmemb)++; /* increment nmemb */
return l; /* return pointer to allocated block of Location */
}
You could then loop filling each with something similar to:
for (size_t i = 0; i < nmemb;) /* loop adding 1st nmemb names */
if (!(l = addLocation (l, &i, names[i], nearCount)))
break;
(note: i is being updated in addLocation so there is no need for i++ in your loop definition)
A complete example could be written as follows. I have added a print function and a function to delete all allocated memory as well. In the call to addLocation below, you will see names[i%nnames] used instead of names[i] and using the counter modulo the total number of names in my list just ensures that a name from the list is provided, no matter how big i gets.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
typedef struct Location {
char isValid;
char *name;
struct Location *near;
int nearCount;
} Location;
Location *addLocation (Location *l, size_t *nmemb, char *name, int nearCount)
{
/* realloc using temporary pointer adding 1 Location */
void *tmp = realloc (l, (*nmemb + 1) * sizeof *l); /* validate EVERY allocation */
if (!tmp) { /* on failure */
perror ("error: realloc-l");
return NULL; /* original data good, that's why you realloc to a tmp */
}
/* on successful allocation */
l = tmp; /* assign reallocated block to l */
l[*nmemb].isValid = 1; /* assign remaining values and */
l[*nmemb].name = name; /* allocate for near */
l[*nmemb].near = calloc(nearCount, sizeof(Location));
if (!l[*nmemb].near) {
perror ("calloc-l[*nmemb].near");
return NULL;
}
l[*nmemb].nearCount = nearCount; /* set nearCount */
(*nmemb)++; /* increment nmemb */
return l; /* return pointer to allocated block of Location */
}
void prn_locations (Location *l, size_t nmemb)
{
for (size_t i = 0; i < nmemb; i++)
if (l[i].isValid)
printf ("%-12s nearCount: %d\n", l[i].name, l[i].nearCount);
}
void del_all (Location *l, size_t nmemb)
{
for (size_t i = 0; i < nmemb; i++)
free (l[i].near); /* free each structs allocated near member */
free (l); /* free all struct */
}
int main (int argc, char **argv) {
char *endptr, /* use with strtoul conversion, names below */
*names[] = { "Mary", "Sarah", "Tom", "Jerry", "Clay", "Bruce" };
size_t nmemb = argc > 1 ? strtoul (argv[1], &endptr, 0) : 4,
nnames = sizeof names / sizeof *names;
int nearCount = 3; /* set nearCourt */
Location *l = NULL; /* pointer to allocated object */
if (errno || (nmemb == 0 && endptr == argv[1])) { /* validate converstion */
fputs ("error: nmemb conversion failed.\n", stderr);
return 1;
}
for (size_t i = 0; i < nmemb;) /* loop adding 1st nmemb names */
if (!(l = addLocation (l, &i, names[i%nnames], nearCount)))
break;
prn_locations (l, nmemb);
del_all (l, nmemb);
}
Example Use/Output
$ ./bin/locationalloc
Mary nearCount: 3
Sarah nearCount: 3
Tom nearCount: 3
Jerry nearCount: 3
Or, for example if you wanted to allocate for 10 of them, then:
$ ./bin/locationalloc 10
Mary nearCount: 3
Sarah nearCount: 3
Tom nearCount: 3
Jerry nearCount: 3
Clay nearCount: 3
Bruce nearCount: 3
Mary nearCount: 3
Sarah nearCount: 3
Tom nearCount: 3
Jerry nearCount: 3
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 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/locationalloc
==13644== Memcheck, a memory error detector
==13644== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==13644== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==13644== Command: ./bin/locationalloc
==13644==
Mary nearCount: 3
Sarah nearCount: 3
Tom nearCount: 3
Jerry nearCount: 3
==13644==
==13644== HEAP SUMMARY:
==13644== in use at exit: 0 bytes in 0 blocks
==13644== total heap usage: 9 allocs, 9 frees, 1,728 bytes allocated
==13644==
==13644== All heap blocks were freed -- no leaks are possible
==13644==
==13644== For counts of detected and suppressed errors, rerun with: -v
==13644== 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.
Let me know if this comports with your intent and whether you have any additional questions.
I use malloc to dynamically allocate memory, use memset to initialize the 2D array, and use free to free the memory. The code is:
int n1=2,n2=5;
int in1;
float **a;
a = (float **)malloc(n1*sizeof(float *));
for (in1=0;in1<n1;in1++)
a[in1] = (float *)malloc(n2*sizeof(float));
memset(a[0],0,n1*n2*sizeof(float));
free(*a);free(a);
First problem when I run the code is:
* Error in `./try1': free(): invalid next size (fast): 0x0000000000c06030 *
Second question is: since the prerequisite for using memset is having contiguous memory. That's why it doesn't work on 3D array (see Error in memset() a 3D array). But here a is a 2D pointer or array, the input of memset is a[0]. My understanding is:
+---------+---------+-----+--------------+
| a[0][0] | a[0][1] | ... | a[0][n2 - 1] |
+---------+---------+-----+--------------+
^
|
+------+------+-----+-----------+
| a[0] | a[1] | ... | a[n1 - 1] |
+------+------+-----+-----------+
|
v
+---------+---------+-----+--------------+
| a[1][0] | a[1][1] | ... | a[1][n2 - 1] |
+---------+---------+-----+--------------+
The above figure shows the contiguous memory. So memset(a[0],0,n1*n2*sizeof(float)); can successfully initialize **a. Am I right? If it's not contiguous, how can the initialization be successful? (it is from the tested open source code)
The above figure shows the contiguous memory.
No it doesn't. It shows two regions of contiguous memory: a[0][0] -> a[0][n2 - 1] and a[1][0] -> a[1][n2 - 1].
You could try to initialize and erase each of them:
int n1 = 2, n2 = 5;
int in1;
float **a;
a = (float **)malloc(n1*sizeof(float *));
for (in1 = 0; in1<n1; in1++)
{
a[in1] = (float *)malloc(n2*sizeof(float));
memset(a[in1], 0, n2*sizeof(float));
}
for (in1 = 0; in1<n1; in1++)
{
free(*(a+in1));
}
free(a);
Only in the case of a 'real' 2d array, like float a[2][5];, your assumption about contiguous memory is correct.
I was wondering, why does this work
// read n as matrix dimension, then:
int* M;
M = (int*)malloc(n * n * sizeof(int));
// cycle through each "cell" in the matrix and read a number with
scanf("%d", &M[i * n + j]);
and this doesn't?
// read n as matrix dimension, then:
int** M;
M = malloc(n * n * sizeof(int));
// cycle through each "cell" in the matrix and read a number with
scanf ("%d", &M[i][j]);
I just don't get it. In both cases they should be double pointers, am I right?
int ** is supposed to point to an int*. Here you have allocated some memory - to be precise sizeof(int)*rows*cols bytes and then you use M[i] etc. Here M[i] which is basically *(M+i) we will access i*sizeof(int*) offset from the one address returned by malloc but you allocated for rows*cols int's not int*-s - so you will eventually access memory that you shouldn't (typically on a system where sizeof(int*) > sizeof(int)) which will lead you to undefined behavior.
What is the solution then? Well allocate for int*-s.
int ** M = malloc(sizeof *M * rows);
if(!M){
perror("malloc");
exit(EXIT_FAILURE);
}
for(size_t i = 0; i < rows; i++){
M[i] = malloc(sizeof *M[i] * cols);
if(!M[i]){
perror("malloc");
exit(EXIT_FAILURE);
}
}
For your case rows = N and cols = N.
This will you give you a jagged array which you can access like you did. With malloc comes the responsibility of checking the return type of it and freeing the memory when you are done working with it. Do that.
On the first case you are accessing the allocated chunk of memory and you have realized the memory access using indices i and j to give yourself a flavor of accessing memory that you do in case of 2d array. So there is no point using double pointer here. It is legal what you did.
In both cases they should be double pointers
No they shouldn't be. The first one is different than the second one. They are not in anyway indicating the same thing.
Case 1 :-
int* M;
M = (int*)malloc(n * n * sizeof(int));
Here memory is allocated for M which is single pointer. Let's say you want to store 5 integers into that memory. So it looks like
-------------------------------
| 10 | 20 | 30 | 40 | 50 |
-------------------------------
M M[0] M[1] M[2] m[3] M[4] <--- Its a 1D array, only one row of 5 int
Case 2 :-
int **M;
M = malloc(n * n * sizeof(int));
M[0][0] M[0][1]
| | | | ....... | | <---- If below one is not done then how will you store the numbers into these
----------- ----- ---------
| | | |
M[0] M[1] M[2] .... M[4] <--- didn't allocated memory for these rows or 1D array
| | | |
-----------------------------------
|
M <---- allocated memory for this
It doesn't work because M is double pointer and you allocated memory only for M, you didn't allocated memory for M[row]. thats why below statement didn't work.
scanf ("%d", &M[i][j]);
So to make it work first Allocate the memory for M as you did
M = malloc(row*sizeof(*M)); /* row indicates no of rows */
and then allocate for each row
for(int index = 0 ;index < row;index++) {
M[index] = malloc(col * sizeof(*M[index])); /* col indicates number of columns */
}
And scan the matrix input
for(int index = 0 ;index < row;index++) {
for(int sub_index = 0 ;sub_index < col; sub_index++)
scanf("%d",&M[index][sub_index]);
}
and once work is done with matrix free the dynamically allocated memory using free() for each row to avoid memory leakage.
The other answers (suggesting one malloc for M and n mallocs for the rows) are correct, but not the most efficient way to allocate a matrix. You can, however, allocate the matrix with only one malloc call, while still allowing you to index it by row and column with M[i][j], as follows:
int (*M)[cols] = malloc(rows * sizeof *M);
This declares M as a pointer to array of int with length cols and requests malloc to allocate rows number of such arrays, meaning you get a single block of rows * cols ints (sizeof *M == sizeof(int) * cols).
When the malloc succeeds, you can use M as if it were declared as int M[rows][cols] so you can read into it with
scanf("%d", &M[i][j]);
It looks more complicated, but allocates M as one contiguous block of memory, which allows the processor to optimize access to it.
And as an added bonus you can also free it with just one call:
free(M);
This does require C99 support, or at least support for variable-length arrays, but the matrix itself is not a proper variable-length array. It is still allocated by malloc, but the declaration of M allows you to use it like one.
This is sample code my teacher showed us about "How to dynamically allocate an array in C?". But I don't fully understand this. Here is the code:
int k;
int** test;
printf("Enter a value for k: ");
scanf("%d", &k);
test = (int **)malloc(k * sizeof(int*));
for (i = 0; i < k; i++) {
test[i] = (int*)malloc(k * sizeof(int)); //Initialize all the values
}
I thought in C, to define an array you had to put the [] after the name, so what exactly is int** test; isn't it just a pointer to a pointer? And the malloc() line is also really confusing me.....
According to declaration int** test; , test is pointer to pointer, and the code pice allocating memory for a matrix of int values dynamically using malloc function.
Statement:
test = (int **)malloc(k * sizeof(int*));
// ^^------^^-------
// allocate for k int* values
Allocate continue memory for k pointers to int (int*). So suppose if k = 4 then you gets something like:
temp 343 347 351 355
+----+ +----+----+----+----+
|343 |---►| ? | ? | ? | ? |
+----+ +----+----+----+----+
I am assuming addresses are of four bytes and ? means garbage values.
temp variable assigned returned address by malloc, malloc allocates continues memory blocks of size = k * sizeof(int**) that is in my example = 16 bytes.
In the for loop you allocate memory for k int and assign returned address to temp[i] (location of previously allocated array).
test[i] = (int*)malloc(k * sizeof(int)); //Initialize all the values
// ^^-----^^----------
// allocate for k int values
Note: the expression temp[i] == *(temp + i). So in for loop in each iterations you allocate memory for an array of k int values that looks something like below:
First malloc For loop
--------------- ------------------
temp
+-----+
| 343 |--+
+-----+ |
▼ 201 205 209 213
+--------+ +-----+-----+-----+-----+
343 | |= *(temp + 0) | ? | ? | ? | ? | //for i = 0
|temp[0] |-------| +-----+-----+-----+-----+
| 201 | +-----------▲
+--------+ 502 506 510 514
| | +-----+-----+-----+-----+
347 |temp[1] |= *(temp + 1) | ? | ? | ? | ? | //for i = 1
| 502 |-------| +-----+-----+-----+-----+
+--------+ +-----------▲
| | 43 48 52 56
351 | 43 | +-----+-----+-----+-----+
|temp[2] |= *(temp + 2) | ? | ? | ? | ? | //for i = 2
| |-------| +-----+-----+-----+-----+
+--------+ +-----------▲
355 | |
| 9002 | 9002 9006 9010 9014
|temp[3] | +-----+-----+-----+-----+
| |= *(temp + 3) | ? | ? | ? | ? | //for i = 3
+--------+ | +-----+-----+-----+-----+
+-----------▲
Again ? means garbage values.
Additional points:
1) You are casting returned address by malloc but in C you should avoid it. Read Do I cast the result of malloc? just do as follows:
test = malloc(k* sizeof(int*));
for (i = 0; i < k; i++){
test[i] = malloc(k * sizeof(int));
}
2) If you are allocating memory dynamically, you need to free memory explicitly when your work done with that (after freeing dynamically allocated memory you can't access that memory). Steps to free memory for test will be as follows:
for (i = 0; i < k; i++){
free(test[i]);
}
free(test);
3) This is one way to allocate memory for 2D matrix as array of arrays if you wants to allocate completely continues memory for all arrays check this answer: Allocate memory 2d array in function C
4) If the description helps and you want to learn for 3D allocation Check this answer: Matrix of String or/ 3D char array
Remember that arrays decays to pointers, and can be used as pointers. And that pointers can be used as arrays. In fact, indexing an array can be seen as a form or pointer arithmetics. For example
int a[3] = { 1, 2, 3 }; /* Define and initialize an array */
printf("a[1] = %d\n", a[1]); /* Use array indexing */
printf("*(a + 1) = %d\n", *(a + 1)); /* Use pointer arithmetic */
Both outputs above will print the second (index 1) item in the array.
The same way is true about pointers, they can be used with pointer arithmetic, or used with array indexing.
From the above, you can think of a pointer-to-pointer-to.type as an array-of-arrays-of-type. But that's not the whole truth, as they are stored differently in memory. So you can not pass an array-of-arrays as argument to a function which expects a pointer-to-pointer. You can however, after you initialized it, use a pointer-to-pointer with array indexing like normal pointers.
malloc is used to dynamically allocate memory to the test variable think of the * as an array and ** as an array of arrays but rather than passing by value the pointers are used to reference the memory address of the variable. When malloc is called you are allocating memory to the test variable by getting the size of an integer and multiplying by the number of ints the user supplies, because this is not known before the user enters this.
Yes it is perfectly Ok. test is pointer to pointer and so test[i] which is equivalent to writing test + i will be a pointer. For better understanding please have a look on this c - FAQ.
Yes indeed, int** is a pointer to a pointer. We can also say it is an array of pointers.
test = (int **) malloc(k * sizeof(int*));
This will allocate an array of k pointers first. malloc dynamically allocates memory.
test[i] = (int*) malloc(k * sizeof(int));
This is not necessary as it is enough to
test[i] = (int*) malloc(sizeof(int*));
Here we allocate each of the array places to point to a valid memory. However for base types like int this kind of allocation makes no sense. It is usefull for larger types (structs).
Each pointer can be accessed like an array and vice versa for example following is equivalent.
int a;
test[i] = &a;
(test + i) = &a;
This could be array test in memory that is allocated beginning at offset 0x10000000:
+------------+------------+
| OFFSET | POINTER |
+------------+------------+
| 0x10000000 | 0x20000000 | test[0]
+------------+------------+
| 0x10000004 | 0x30000000 | test[1]
+------------+------------+
| ... | ...
Each element (in this example 0x2000000 and 0x30000000) are pointers to another allocated memory.
+------------+------------+
| OFFSET | VALUE |
+------------+------------+
| 0x20000000 | 0x00000001 | *(test[0]) = 1
+------------+------------+
| ...
+------------+------------+
| 0x30000000 | 0x00000002 | *(test[1]) = 2
+------------+------------+
| ...
Each of the values contains space for sizeof(int) only.
In this example, test[0][0] would be equivalent to *(test[0]), however test[0][1] would not be valid since it would access memory that was not allocted.
For every type T there exists a type “pointer to T”.
Variables can be declared as being pointers to values of various types, by means of the * type declarator. To declare a variable as a pointer, precede its name with an asterisk.
Hence "for every type T" also applies to pointer types there exists multi-indirect pointers like char** or int*** and so on. There exists also "pointer to array" types, but they are less common than "array of pointer" (http://en.wikipedia.org/wiki/C_data_types)
so int** test declares an array of pointers which points to "int arrays"
in the line test = (int **)malloc(k*sizeof(int*)); puts enough memory aside for k amount of (int*)'s
so there are k amount of pointers to, each pointing to...
test[i] = (int*)malloc(k * sizeof(int)); (each pointer points to an array with the size of k amounts of ints)
Summary...
int** test; is made up of k amount of pointers each pointing to k amount of ints.
int** is a pointer to a pointer of int. take a look at "right-left" rule