First let us clear up a little bit of terminology:
So we will have a pointer point to another pointer
This is incorrect. When you assign a pointer to another pointer, the second pointer does not point to the first pointer, it points to the same thing as the first pointer. Pointing to a pointer implies two levels of dereference needed - in this case - to get to the char
i.e. char a = **pr;
So, let's look at the code.
pr = (char*)malloc( 50 * sizeof(char) );
The prototype of malloc is
void *malloc(size_t size);
malloc
allocates size
bytes of memory and returns a pointer to that block of memory (or NULL
if it can't allocated a block of memory). malloc
has no idea of what kind of thing you want it to point to, so it chooses to return a void *
which means a pointer to something unknown. The (char*)
on the front of your call to malloc
is a type cast. It changes the type of the expression to its right to the type enclosed in parentheses which is char *
in this instance (you can put in or leave out the space between the char
and the *
without any effect).
The pointer, which now has type char *
is then assigned to pr
which also has type char *
.
The only thing is that C will do the cast automatically, as long as it is from void *
and to another pointer type. So what you wrote is exactly equivalent to
pr = malloc( 50 * sizeof(char) );
It's generally considered better style to do it this way than put the explicit cast in. It's easier to read and less cluttered.
There also used to be the danger that, if you forgot to #include <stdlib.h>
the compiler would assume malloc
returns an int
If you left the cast out, the compiler would flag the attempted cast from int
to char *
as an error, but if you put it in, the error would be suppressed. This issue no longer exists because C11 forbids using a function that hasn't been declared.
There is another problem which is sort of the reverse of the one described above. If you have
char* pr;
// Lots of code
pr = malloc( 50 * sizeof(char) );
pr[49] = 0;
and you decide that pr
really needs to point to int
you might end up with
int* pr;
// Lots of code
pr = malloc( 50 * sizeof(char) );
for (int i = 0 ; i < 50 ; ++i)
{
pr[i] = 0; // buffer overflow!
}
Which would compile but is undefined behaviour because the allocated block is not big enough to hold 50 int
s. You could solve that by reverting to the explicit cast (int* pr = (char*)malloc(...)
is an error), but the better way is to do a sizeof on the dereferenced pointer
int* pr;
// Lots of code
pr = malloc( 50 * sizeof *pr );
for (int i = 0 ; i < 50 ; ++i)
{
pr[i] = 0; // OK if malloc returns non NULL, otherwise undefined behaviour, probably a SIGSEV
}
calloc
is like malloc
except instead of supplying the absolute count of bytes, you supply a count of the things pointed to and the size of the things pointed to separately. calloc
also zeros the bytes in the allocated block.
int *pr = calloc(50, sizeof *pr);
is effectively the same as the previous bits of code, except it is not undefined behaviour if the memory can't be allocated.
NB: A lot of people are saying you absolutely shouldn't put the explicit cast in, but there really are arguments both ways. Also this.