Of course you can ask about C - just because it is a fifty year old language and shows it's age badly doesn't mean you can't ask about it!
If you are learning it as your first language though, it's going to be of little help in getting you a job ... a more modern language like C# would probably be a better choice.
The first thing to know is that the name of an array is a pointer to the first element in the array - so you can use pointer syntax or array index syntax interchangeably:
#include <stdio.h>
int main()
{
printf("Hello World\n");
int myArray[] = {1, 2, 3, 4, 5};
int first = *myArray;
int second = myArray[1];
if (first == 1 && second == 2)
{
printf("Yes!\n");
}
else
{
printf("No!\n");
}
return 0;
}
Will print "Yes!" every time.
Why is
malloc
a pointer? Well, it isn't - it's a function that returns a pointer, and that's different.
What
malloc
does is take a parameter which the number of bytes you want, and it returns a pointer to the first byte of the newly allocated memory - it doesn't know or care what you are going to do with the memory, it just allocates it on an area of memory allocated to your program called the
heap
. And it has a companion function called
free
to release that memory when you are finished with it. (You need to call
free
or you app starts to "leak memory" - the heap fills up with "lumps of memory" you have allocated but don't need any more.)
And a block of memory can be used however you want: as a string of characters, an integer, or an array for example (heck, you can use it as all three in different parts of your app if you want!)
Malloc returns what is called a
void pointer
- it's a special type that you can't use directly but you can cast it to a pointer of any type:
int
,
int*
, or even
char*******
if you really need it to!
Once you have a pointer, you can use it (called dereferencing), copy it, cast it - anything you need to.
In your 2D arrays example,
matrix
is declared as an
int**
- a pointer to a pointer to an integer - and
malloc
is asked to allocate enough space for
rows
pointers:
int **matrix = (int **) malloc(rows * sizeof(int *));
Now, C is a very old language, so it is probably producing 32bit code, which means that a pointer is also 32 bits wide - 4 bytes. So malloc is asked for a block of memory that holds
rows * 4
bytes. Then next line is probably a bit confusing - it allocates a block of memory that is big enough to hold all the rows and columns of integers and assigns it to the first element in the array of pointers to integers.
Then the loop adds the pointers to each row in the array.
A better way to write that would have been:
int **matrix = (int **) malloc(rows * sizeof(int *));
int *arrayData = (int *) malloc(rows * columns * sizeof(int));
for (int i = 1; i < rows; i++)
{
matrix[i] = arrayData + i * columns;
}
Because
arrayData
is a pointer to a integer, when you add a number of it it automatically includes the size of an integer to the calculation so you don't have to worry about that.
matrix[0]
returns the first element in the array, and since
matrix
is a pointer to a pointer to an integer, it returns a pointer to an integer - the first integer in the first row.
That's why I said right at the beginning that "the name of an array is a pointer to the first element in the array" it is, and as a result
*matrix
and
matrix[0]
can be used interchangeably (but it's usually better to stick to one syntax rather than mixing them up). Equally,
*(matrix + 1)
and
matrix[1]
are equivelant and return the pointer to the second row in the array.
You need two mallocs to allocate the two memory blocks needed - one for the array of "start of rows" which is stored in
matrix
and one for the block of memory that will contain the row and column data itself.
In your final question,
arr
is not an array of
char
s - it's an array of pointers to
char
values.
arr[0]
returns a pointer to the first char in "geek", arr[1] returns a pointer to the first char in "Geeks", and so on.
So when you call
printf
and pass it
arr[i]
you aren't passing a
char
but a pointer to a
char
- so it prints the whole string, not a single character.
How does it know? The system allocates the memory for the three strings for you and copies the string literals into them when that code is executed. It then allocates enough space for the three pointers and sets them to point at the strings it just allocated, and finally sets
arr
to point at the first of those three pointers.
I know it's confusing, but think about it for a while, before you get a piece of paper and a pencil then pretend to be the system for a while: draw a block of memory and "allocate bits of it" you can draw an arrow to when you set a variable to point to it. You'll get the idea, but it may take a while and a fair amount of "rubbing out"!
This is why I said that C is a poor starter language: In more modern languages (like C# for example, though there are many) you don't have to worry about pointers, they all go on behind the scenes and you just deal with the variables and their content.