C Grid using pointers and Malloc - c

I am Trying to work through some class examples and have gotten stuck on the following:
The array grid should
have length width with each entry representing a column of
cells. Columns that have some occupied cells should be a
malloc'ed character array of length height.
with the given header:
void grid(char **grid, int width, int height)
grid is defined in another file as:
char **grid;
As I have said I have gotten stuck on using malloc, I currently have:
int x;
*grid = malloc(width * sizeof(char));
for(x = 0; x < width; x++){
grid[x] = malloc(height * sizeof(char));
}
Can any one take a look at give me some pointers on the correct way to accomplish "Columns that have some occupied cells should be a
malloc'ed character array of length height.", As I dont understand how the line:
grid[x] = malloc(height *
sizeof(char));
is equivalent to an array of char's
Thanks

char** grid; is a pointer to pointer.
grid = malloc( width* sizeof( char* ) ) ; // Statement 1
for( int i=0; i<height; ++i )
{
grid[i] = malloc( height ) ; // Statement 2
}
Understand char** -> char* -> char. So first need to reserve for holding addresses amounting to width. By Statement 1, it is achieved. Now each of these index should point to a memory location holding height characters and is achieved by Statement 2.
Diagramatic representation sounds more clear than description. Hope that helps !

In C, an array is a pointer to the first element of the array. So an array is just a memory block, with the array variable pointing onto the first element in this memory block.
malloc() reserves a new memory block of the specified size. To know the size of a type (i.e. number of bytes needed to store one variable of that type), one uses the sizeof operator. Hence a character needs sizeof(char) bytes, and hence height characters need height * sizeof(char).
So with the malloc() call you allocate a memory block to store all the elements of the array, and malloc() returns a pointer onto the first of them.
With C's definition for an array variable (a pointer onto the first element), you can assign the results of malloc(...) to your array variable.

Use this:
grid = malloc(width * sizeof(char *));
You want to allocate space for width pointers to char - And then you correctly allocate the individual pointers to height chars in the loop.
Using a typedef makes this more visible:
typedef char * charpointer;
charpointer * grid = malloc(width * sizeof(charpointer));

First you allocate space for array of [width] char pointers. So instead of *grid = malloc(width * sizeof(char)); which allocates space for [width] chars, you should use *grid = malloc(width * sizeof(* char)); (the difference is that char is one byte, and char pointer is int (usually 32 bit, but architecture dependent)
In your loop, each time you allocate (an array of) [hight] chars and store the pointer to it in one of the pointers that you allocated in (1). so grid[x], actually points to an allocated buffer of chars (which is your array)
hope I made it clear.

Related

How do i read from a text file and allocate memory space using malloc for a 2d string array for each word in the text file

i am new to coding and am having a problem with the following.
I am required to read from a text file, each row will contain:
command arg1 arg2 arg3...
command arg1 arg2
command
command arg1 arg2 ... arg9
etc
What i am trying to do is read this entire file into a 2D string array called array using malloc. This way if i were to do:
array[0][0] i would access command arg1 arg2 arg3
array[1][0] i would access command arg1 arg2
and so on.
I also know there is a max of 100 rows and 256 characters per line. Below is how i attempted to declare my malloc however when trying to allocate strings to the 2d array, it only allocated single characters.
I dont quite understand how to do this, detailed explanation would be greatly appreciated
int row = 100;
int col = 256;
int **array;
array = (int**)malloc(row*sizeof(array));
if(!array){
perror("Error occured allocating memory");
exit(-1);
}
for(int i = 0; i<row;i++){
array[i] = (int*)malloc(col*sizeof(array));
}
If I got it right, you need to set up a two dimensional array of char * instead of int.
That is, you address the correct row by dereferencing once (array[the_ith_row]), and then address the correct element(command, arg1, arg2, ...) by another dereference (array[the_ith_row][the_jth_col]).
Notice: strings like "arg1" and "command" are treated as "array of chars" therefore you need to store a char * in order to access them. int could only store one char(with some extra space consumption), therefore won't work here.
So, the correct one should look like:
#include <string.h>
int row = 100;
int col = 256;
char ***array;
array = (char ***)malloc(row * sizeof(char **));
if (!array) {
perror("Error occured allocating memory");
exit(-1);
}
for (int i = 0; i < row; i++) {
array[i] = (char **)malloc(col * sizeof(char *));
}
// Do some example assignments
for (int j = 0; j < col; j++) {
array[i][j] = strcpy((char *)malloc(100), "test_string");
}
//therefore printf("%s", array[0][0]); will print test_string"
UPDATE: I missed some * here..
You are allocating using sizeof(array) which is not the correct unit of allocation that you want.
It looks like what you want are two different kinds of memory allocations or objects.
The first is an array of pointers to character strings since the file data is a series of character strings.
The second kind of memory allocation is for the memory to hold the actual character string.
The first kind of memory allocation, to an array of pointers to character strings would be:
char **pArray = malloc (100 * sizeof(char *)); // allocate the array of character string pointers
The second kind of memory allocation, to a character string which is an array of characters would be:
char *pString = malloc ((256 + 1) * sizeof(char)); // allocate a character array for up to 256 characters
The 256 + 1 is needed in order to allocate space for 256 characters plus one more for the end of string character.
So to allocate the entire needed space, you would do the following:
int iIndex;
int nMax = 100;
char **pArray = malloc (nMax, sizeof(char *)); // allocate array of rows
for (iIndex = 0; iIndex < nMax; iIndex++) {
pArray[iIndex] = malloc ((256 + 1) * sizeof (char)); // allocate a row
}
// now use the pArray to read in the lines of text from the file.
// for the first line, pArray[0], second pArray[1], etc.
Using realloc()
A question posed is using the realloc() function to adjust the size of the allocated memory.
For the second kind of memory, memory for the actual character string, the main thing is to use realloc() as normal to expand or shrink the amount of memory. However if memory is reduced, you need to consider if the text string was truncated and a new end of string terminator is provided to ensure the text string is properly terminated with and end of string indicator.
// modify size of a text string memory area for text string in pArray[i]
// memory area. use a temporary and test that realloc() worked before
// changing the pointer value in pArray[] element.
char *p = realloc (pArray[i], (nSize + 1) * sizeof (char));
if (p != NULL) {
pArray[i] = p; // valid realloc() so replace our pointer.
pArray[i][nSize] = 0; // ensure zero terminator for string
}
If you ensure that when the memory area for pArray] is set to NULL after allocating the array, you can just use the realloc() function as above without first using malloc() since if the pointer in the argument to realloc() is NULL then realloc() will just do a malloc() for the memory.
For the first kind of memory, you will need to consider freeing any memory whose pointers may be destroyed when the allocated array is shortened. This means that you will need to do a bit more management and keeping management data about the allocated memory area. If you can guarantee that you will only be increasing the size of the array and never shortening it then you don't need to do any management and you can just use the same approach as provided for the second kind of memory above.
However if the memory allocated for the first kind of memory will need to be smaller as well as larger, you need to have some idea as to the size of the memory area allocated. Probably the easiest would be to have a simple struct that would provide both a pointer to the array allocated as well as the max count of items the array can hold.
typedef struct {
size_t nCount;
char **pArray;
} ArrayObj;
Warning: the following code has not been tested or even compiled. Also note that this only works for if the memory allocation will be increased.
Then you would wrap the realloc() function within a management function. This version of the function only handles if realloc() is always to expand the array. If making it smaller you will need to handle that case in this function.
ArrayObj ArrayObjRealloc (ArrayObj obj, size_t nNewCount)
{
// make the management a bit easier by just adding one to the count
// to determine how much memory to allocate.
char **pNew = realloc (obj.pArray, (nNewCount + 1) * sizeof (char *));
if (pNew != NULL) {
size_t ix;
// realloc() worked and provided a valid pointer to the new area.
// update the management information we are going to return.
// set the new space to NULL to have it in an initial and known state.
// initializing the new space to NULL will allow for knowing which array
// elements have a valid pointer and which don't.
obj.pArray = pNew;
for (ix = nNewCount; ix >= obj.nCount; ix--) {
obj.pArray[ix] = NULL;
}
obj.nCount = nNewCount;
}
return obj;
}
and use this function something like
AnyObj obj = {0, NULL};
// allocate for the first time
obj = ArrayObjRealloc (obj, 100);
// do stuff with the array allocated
strcpy (obj.pArray[i], "some text");
// make the array larger
obj = ArrayObjRealloc (obj, 150);

Use array annotation with pointers

I have currently trouble understanding the following scenario:
I have a multidimensional array of Strings and I want to address it by using pointers only but I always get a Segmentation Fault when using the array annotation on the pointer. This is just an example code I want to use the 3D array in a pthread so I want to pass it in via a structure as a pointer but it just doesn't work and I would like to know why? I thought pointers and arrays are functionally equivalent? Here is the sample code:
#include <stdio.h>
void func(unsigned char ***ptr);
int main() {
// Image of dimension 10 times 10
unsigned char image[10][10][3];
unsigned char ***ptr = image;
memcpy(image[0][0], "\120\200\12", 3);
// This works as expected
printf("Test: %s", image[0][0]);
func(image);
return 0;
}
void func(unsigned char ***ptr) {
// But here I get a Segmentation Fault but why??
printf("Ptr: %s", ptr[0][0]);
}
Thanks in advance for your help :)
I think maybe strdup confuses the issue. Pointers and arrays are not always equivalent. Let me try to demonstrate. I always avoid actual multi-dimension arrays, so I may make a mistake here, but:
int main()
{
char d3Array[10][10][4]; //creates a 400-byte contiguous memory area
char ***d3Pointer; //a pointer to a pointer to a pointer to a char.
int i,j;
d3Pointer = malloc(sizeof(char**) * 10);
for (i = 0; i < 10; ++i)
{
d3Pointer[i] = malloc(sizeof(char*) * 10);
for (j = 0; j < 4; ++j)
{
d3Pointer[i][j] = malloc(sizeof(char) * 4);
}
}
//this
d3Pointer[2][3][1] = 'a';
//is equivalent to this
char **d2Pointer = d3Pointer[2];
char *d1Pointer = d2Pointer[3];
d1Pointer[1] = 'a';
d3Array[2][3][1] = 'a';
//is equivalent to
((char *)d3Array)[(2 * 10 * 4) + (3 * 4) + (1)] = 'a';
}
Generally, I use the layered approach. If I want contiguous memory, I handle the math myself..like so:
char *psuedo3dArray = malloc(sizeof(char) * 10 * 10 * 4);
psuedo3dArray[(2 * 10 * 4) + (3 * 4) + (1)] = 'a';
Better yet, I use a collection library like uthash.
Note that properly encapsulating your data makes the actual code incredibly easy to read:
typedef unsigned char byte_t;
typedef struct
{
byte_t r;
byte_t g;
byte_t b;
}pixel_t;
typedef struct
{
int width;
int height;
pixel_t * pixelArray;
}screen_t;
pixel_t *getxyPixel(screen_t *pScreen, int x, int y)
{
return pScreen->pixelArray + (y*pScreen->width) + x;
}
int main()
{
screen_t myScreen;
myScreen.width = 1024;
myScreen.height = 768;
myScreen.pixelArray = (pixel_t*)malloc(sizeof(pixel_t) * myScreen.height * myScreen.width);
getxyPixel(&myScreen, 150, 120)->r = 255;
}
In C, you should allocate space for your 2D array one row at a time. Your definition of test declares a 10 by 10 array of char pointers, so you don't need to call malloc for it. But to store a string you need to allocate space for the string. Your call to strcpy would crash. Use strdup instead. One way to write your code is as follows.
char ***test = NULL;
char *ptr = NULL;
test = malloc(10 * sizeof(char **));
for (int i = 0; i < 10; i++) {
test[i] = malloc(10 * sizeof(char *));
}
test[0][0] = strdup("abc");
ptr = test[0][0];
printf("%s\n", ptr);
test[4][5] = strdup("efg");
ptr = test[4][5];
printf("%s\n", ptr);
Alternatively, if you want to keep your 10 by 10 definition, you could code it like this:
char *test[10][10];
char *ptr = NULL;
test[0][0] = strdup("abc");
ptr = test[0][0];
printf("%s\n", ptr);
test[4][5] = strdup("efg");
ptr = test[4][5];
printf("%s\n", ptr);
Your problem is, that a char[10][10][3] is something very different from a char***: The first is an array of arrays of arrays, the later is a pointer to a pointer to a pointer. The confusions arises because both can be dereferenced with the same syntax. So, here is a bit of an explanation:
The syntax a[b] is nothing but a shorthand for *(a + b): First you perform pointer arithmetic, then you dereference the resulting pointer.
But, how come you can use a[b] when a is an array instead of a pointer? Well, because...
Arrays decay into pointers to their first element: If you have an array declared like int array[10], saying array + 3 results in array decaying to a pointer of type int*.
But, how does that help to evaluate a[b]? Well, because...
Pointer arithmetic takes the size of the target into account: The expression array + 3 triggers a calculation along the lines of (size_t)array + 3*sizeof(*array). In our case, the pointer that results from the array-pointer-decay points to an int, which has a size, say 4 bytes. So, the pointer is incremented by 3*4 bytes. The result is a pointer that points to the fourths int in the array, the first three elements are skipped by the pointer arithmetic.
Note, that this works for arrays of any element type. Arrays can contain bytes, or integers, or floats, or structs, or other arrays. The pointer arithmetic is the same.
But, how does that help us with multidimensional arrays? Well, because...
Multidimensional arrays are just 1D arrays that happen to contain arrays as elements: When you declare an array with char image[256][512]; you are declaring a 1D array of 256 elements. These 256 elements are all arrays of 512 characters, each. Since the sizeof(char) == 1, the size of an element of the outer array is 512*sizeof(char) = 512, and, since we have 256 such arrays, the total size of image is 256*512. Now, I can declare a 3D array with char animation[24][256][512];...
So, going back to your example that uses
char image[10][10][3]
what happens when you say image[1][2][1] is this: The expression is equivalent to this one:
*(*(*(image + 1) + 2) + 3)
image being of type char[10][10][3] decays into a pointer to its first element, which is of type char(*)[10][3] The size of that element is 10*3*1 = 30 bytes.
image + 1: Pointer arithmetic is performed to add 1 to the resulting pointer, which increments it by 30 bytes.
*(image + 1): The pointer is dereferenced, we are now talking directly about the element, which is of type char[10][3].
This array again decays into a pointer to its first element, which is of type char(*)[3]. The size of the element is 3*1 = 3. This pointer points at the same byte in memory as the pointer that resulted from step 2. The only difference is, that it has a different type!
*(image + 1) + 2: Pointer arithmetic is performed to add 2 to the resulting pointer, which increments it by 2*3 = 6 bytes. Together with the increment in step 2, we now have an offset of 36 bytes, total.
*(*(image + 1) + 2): The pointer is dereferenced, we are now talking directly about the element, which is of type char[3].
This array again decays into a pointer to its first element, which is of type char*. The size of the element is now just a single byte. Again, this pointer has the same value as the pointer resulting from step 5, but a different type.
*(*(image + 1) + 2) + 1: Pointer arithmetic again, adding 1*1 = 1 bytes to the total offset, which increases to 37 bytes.
*(*(*(image + 1) + 2) + 1): The pointer is dereferenced the last time, we are now talking about the char at an offset of 37 bytes into the image.
So, what's the difference to a char***? When you dereference a char***, you do not get any array-pointer-decay. When you try to evaluate the expression pointers[1][2][1] with a variable declared as
char*** pointers;
the expression is again equivalent to:
*(*(*(pointers + 1) + 2) + 3)
pointers is a pointer, so no decay happens. Its type is char***, and it points to a value of type char**, which likely has a size of 8 bytes (assuming a 64 bit system).
pointers + 1: Pointer arithmetic is performed to add 1 to the resulting pointer, which increments it by 1*8 = 8 bytes.
*(pointers + 1): The pointer is dereferenced, we are now talking about the pointer value that is found in memory at an offset of 8 bytes of where pointers points.
Further steps depending on what actually happened to be stored at pointers[1]. These steps do not involve any array-pointer-decay, and thus load pointers from memory instead.
You see, the difference between a char[10][10][3] and a char*** is profound. In the first case, the array-pointer-decay transforms the process into a pure offset computation into a multidimensional array. In the later case, we repeatedly load pointers from memory when accessing elements, all we ever have are 1D arrays of pointers. And it's all down to the types of pointers!

How to allocate contiguous 2D array of strings in C

I am new in whole C programming thing (comming from Java), and honestly its really confusing. Ok to the problem I am trying to allocate contigous chunk of data for my 2D array of strings (Guessing its something like 3D array??). All I have is this i believe contiguous allocation for Array of strings?
Can someone help me out with 2D array please?
And yes I know size before running the program, its defined so ROWS for rows, COLS for columns and NAME for length of string.
char **people = malloc(COLS * sizeof(char *));
people[0] = malloc(COLS * NAME);
for(int i = 1; i < COLS; i++)
people[i] = people[0] + i * NAME;
If you actually know the size of the array before running the program, you don't need to dinamically allocate the memory with malloc, you could create a 2D static array. In your case, as it is a 2D array of strings, it could be declared as char * array[ROWS][COLS], and then you could asign a string to a specific element this way: array[nrow][ncol]="Your String".
C, unlike Java, actually has a concept of multidimensional arrays; so unless there's a specific reason you want a char * * *, you might prefer to write:
char (*people)[COLS][NAME] = malloc(ROWS * sizeof(*people));
which sets people to be a pointer to the first of ROWS dynamically-allocated two-dimensional character arrays.
Due to pointer "decay", where an expression of array type will double as a pointer to the first element of the array, you can use people very much as if it were a char * * *; for example, people[3][4] will point to the string in row 3, column 4. The only restriction is that you can't write something like people[3][4] = ... to suddenly change what string to point to. But it sounds like you don't want to do that, anyway?
Note: the above is assuming that you are intentionally using dynamic memory allocation. However, I do recommend you consider Sizigia's suggestion to use static memory, which is the same sort of storage as is used for global variables. If you write something like
static char people[ROWS][COLS][NAME];
then the memory will be allocated just once, at the start of the program, and reused by all calls to the function that declares it.
You can define a char * using typedef so it's better for you to understand the code. Then all you have to do is to dynamically allocate a 2D array of your defined type (in the example below, I defined it as a "string"):
typedef char * string;
string ** people;
people = malloc(ROWS * sizeof(string));
for(int i = 0; i < ROWS; i++){
people[i] = malloc(COLUMNS * sizeof(char));
}
You can access it using the normal array sintax, people[i][j].

How can i use dynamic 2d array in c

I tried to make a dynamic 5x5 int array
int **data=malloc(5*5);
But I get segmentation fault on trying to access it.
You need to allocate memory for the 2d-array you want to make (which I think you understand). But first, you will have to allocate the space for pointers where you will store the rows of the 2D-array.
int **data=(int**)malloc(sizeof(*data)*5); //Here 5 is the number of rows
Now you can allocate space for each row.
for(int r=0;r<5;r++){
data[r]=(int*)malloc(sizeof(**data)*5);//here 5 is the width of the array
}
If you want contiguous block of memory for the whole array, you can allocate a single dimension array of size 25, and access it like data[r*5+c].
PS: Instead of sizeof(*data) and sizeof(**data), you can use sizeof(int*) and sizeof(int) to avoid confusion with *
PS: If you are not using C++, removing the casts from return value of malloc is better (see comments).
If you want a single contiguous memory block to hold 5x5=25 integers :
int *data = malloc(5*5*sizeof(*data));
If you want a 2d array with size 5x5
int **data = malloc(5*sizeof(*data));
for (int i=0; i<5; ++i)
data[i] = malloc(5*sizeof(**data));
There are two possibilities. The first one is indeed to allocate a two-dimensional array:
int ( *data )[5] = malloc( 5 * 5 * sizeof( int ) );
In this case one contiguous extent is allocated for the array.
The second one is to allocate at first a one-dimensional array of pointers and then allocate one-dimensional arrays pointed to by the already allocated pointers.
For example
int **data = malloc( 5 * sizeof( int * ) );
for ( size_t i = 0; i < 5; i++ )
{
data[i] = malloc( 5 * sizeof( int ) );
}
In this case there are allocated in fact 6 extents of memory: one for the array of the pointers and other 5 for arrays of integers.
To free the allocated memory in the first example it is enough to write
free( data );
and in the second example you need to write the following
for ( size_t i = 0; i < 5; i++ ) free( data[i] );
free( data );
If you want to treat the array as a 2D array (a[i][j]) and you want all the array elements to be contiguous in memory, do the following:
int (*data)[5] = malloc( sizeof *data * 5 );
If you also want to be table to determine the size of the array at run time and your compiler supports variable-length arrays1:
size_t rows, cols;
...
int (*data)[rows] = malloc( sizeof *data * cols );2
If your compiler does not support VLAs and you still want to determine the array size at runtime, you would do:
size_t rows, cols;
...
int **data = malloc( sizeof *data * rows );
if ( data )
{
for ( size_t i = 0; i < rows; i++ )
{
data[i] = malloc( sizeof *data[i] * cols );
}
}
The downside of this approach is that the rows of the array are not guaranteed to be contiguous in memory (they most likely won't be). Elements within a single row will be contiguous, but rows will not be contiguous with each other.
If you want to determine the array size at runtime and have all the array elements be contiguous in memory but your compiler does not support variable-length arrays, you would need to allocate a 1D array and manually compute your indices (a[i * rows + j]):
int *data = malloc( sizeof *data * rows * cols );
1. VLAs were introduced with C99, but then made optional in C2011. A post-C99 compiler that does not define the macro __STDC_NO_VLA__ should support VLAs.
2. Caution - there is some question whether sizeof *data is well-defined in this example; the sizeof expression is normally evaluated at compile time, but when the operand is a VLA the expression is evaluated at run time. data doesn't point to anything yet, and attempting to dereference an invalid pointer leads to undefined behavior. All I can say is that I've used this idiom a lot and never had an issue, but that may be due more to bad luck than design.
Here is the answer:
int ** squaredMatrix;
int szMatrix=10;
squaredMatrix= (int**)malloc(szMatrix*sizeof(int*));
for making 2d arrays you should view them as one array which every block is an array again .
for example in above picture , blue blocks make an array which each blue block is pointing to an array ( every 4 green blocks in a row are an array and blue blocks in a column are the main array)

Dynamic memory allocation code explanation

Being a beginner C/C++ programmer, I am having to spend several hours, trying to decipher the code below: Could someone walk me (step me through the code below for dynamic memory allocation) line by line.
char **alloc_2d_char(const int rows, const int cols)
{
char *data = (char *)malloc(rows*cols*sizeof(char));
char **array= (char **)malloc(rows*sizeof(char*));
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
return array;
}
Pointer to Pointers is explained separately than from Pointers to Arrays. I have been able to get parts of the information from various sources, but none that stitches the lines cohesively.
The code is using a single contiguous block of memory to hold a 2-D array.
char *data = (char *)malloc(rows*cols*sizeof(char));
Ok -- this line is allocating space for the entire 2-D array. The 2-D array is rows rows by cols columns. So the total number of elements is rows * cols. Then you have to multiply that by the amount of space each element takes up, which is sizeof(char) since this is a 2-D array of char. Thus the total amount of memory to be allocated is rows * cols * sizeof(char) which is indeed the argument to malloc.
The malloc call returns a pointer to the allocated memory. Since this memory will be used to hold char, you cast the return value to char *.
char **array= (char **)malloc(rows*sizeof(char*));
array is being declared as type "pointer to pointer to char" because that's what it's going to do. It'll point to memory that will hold pointers to char. It will be one pointer for each row. So you have to allocate rows * sizeof(char *) memory: the number of pointers times the size of a pointer of the right type. And since this was allocated to point to pointers to char, we cast the return value to char **.
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
This is the magic :). This sets each pointer in array to point to within the block of actual data allocated earlier. Consider a concrete example where rows is 2 and cols is 3. Then you have the block of 6 characters in memory:
[0][1][2][3][4][5]
And data[n] (for n from 0 to 5) is the n-th element and &data[n] is the *address of the n-th element.
So what that loop does in this case is do:
array[0] = &data[0];
array[1] = &data[3];
So array[0] points to the sub-block starting at [0] and array[1] points to the sub-block starting at [3]. Then when you add the second subscript you're indexing from the start of that pointer. So array[0][2] means "get the pointer stored in array[0]. Find what it points to, then move ahead 2 elements from there.:
array[0] points to [0][1][2] (well, actually points to [0]). Then you move two elements ahead and get [2].
Or if you start with array[1][1], array[1] points to [3][4][5] (and actually points at [3]. Move one element ahead and get [4].
The first malloc is getting memory for the 2D character array. The second malloc is getting memory for rows index.
The for loop is setting the pointer to each row.
Finally the row index is returned.
You can think of the 2-D array that it is creating as an array of single-dimensional arrays. Each row entry points to an array of char that represents the column data for that row.
The following is the original code with comments added to attempt to describe each step:
char **alloc_2d_char(const int rows, const int cols)
{
// This allocates the chunk of memory that stores that actual data.
// It is a one single-dimensional array that has rows*cols characters.
char *data = (char *)malloc(rows*cols*sizeof(char));
// This allocates an array of pointers that will then be assigned to the
// individual rows (carved out of the previous allocation).
char **array= (char **)malloc(rows*sizeof(char*));
// This assigns each row to the appropriate position in the data array.
// The &(data[cols*i]) bit of it is the address of a portion in the
// memory pointed to by data. The cols*i is the offset to the portion that
// represents row i.
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
// After doing this, then you can assign a value such as:
// array[r][c] = 'x';
// That statement would store 'x' into data[r*c + c]
return array;
}
Is not hard to decipher...
char *data = (char *)malloc(rows*cols*sizeof(char));
simple memory allocation
char **array= (char **)malloc(rows*sizeof(char*));
memory allocation of #row char pointers
array[i] = &(data[cols*i]);
every array[i] is a pointer, a pointer to data[cols*i]
Each * in a declaration refers to one level of pointer indirection. so int ** means a pointer to a pointer to an int. So your function:
char **alloc_2d_char(const int rows, const int cols)
{
returns a pointer to a pointer to a char.
char *data = (char *)malloc(rows*cols*sizeof(char));
This declares a pointer to a char. The pointer is called data. The initialization calls malloc, which allocates a number of bytes equal to the value of the argument. This means there are rows*cols*sizeof(char) bytes, which will be equal to rows*cols, since a char is 1 byte. The malloc function returns the pointer to the new memory, which means that data now points to a chunk of memory that's rows*cols big. The (char *) before the call to malloc just casts the new memory to the same type as the pointer data.
char **array= (char **)malloc(rows*sizeof(char*));
array is a pointer to a pointer to a char. It is also being assigned using malloc. The amount of memory being allocated this time is rows*sizeof(char), which is equal to rows. This means that array is a pointer to a pointer to a chunk of memory big enough to hold 1 row.
for (int i=0; i<rows; i++)
array[i] = &(data[cols*i]);
The rest of your code initializes each element of array to hold the address of the corresponding row of the big chunk of memory. Your data pointer will point to a chunk of memory that looks like this:
col: 0 1 2 3 ... cols-1
row: 0 *
1 *
2 *
3 *
.
.
.
rows-1 *
And your array pointer will point to a chunk of memory with a list of pointers, each of which points to one of the asterisks in the memory chunk above.
return array;
}
This just returns your array pointer to a pointer, which matches the return type of the alloc_2d_char function: char **. This means that the caller of the function will essentially obtain an array of pointers, and each of these pointers points to one of the rows of the 2D array.

Resources