I do not know for sure, but I would be willing to bet that the answer is because the inventors of C ran out (or nearly ran out) of characters.
The original intention was that the language should use symbols for operators, and also that the language must be expressable within the so-called "lower" ASCII table, which consists of ASCII values 0 through 127.
The first 31 values are unprintable control characters, so we are left with this:
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
`abcdefghijklmnopqrstuvwxyz{|}~
Remove the space, and all characters needed for identifiers, (which are all letters, all numbers, and the underscore,) and and we are left with this:
!"#$%&'()*+,-./:;<=>?@[\]^
{|}~
Remove parentheses, braces, and brackets, as well as the backtick (`), which is not sufficiently dissimilar from the single quote, and we are left with this:
!"#$%&'*+,-./:;<=>?@\^|~
Remove punctuation which is critical for the syntax of the language, ("#',.:;?) and we are left with this:
!$%&*+-/<=>@\^|~
Remove the ampersand (&), which stands for "taking the address of" something, and which must therefore be distinctly different from anything that has to do with pointers, as well as comparisons, (<=>), exclamation (!), plus (+), and minus (-), which are valid operations to perform on pointers, and we are left with this:
$%*/@\^|~
I am not sure why the dollar sign and the at-sign were not considered; perhaps they were thought of as being a bit too bulky to make frequent use of in code. So, take them out, and we are left with these:
%*/\^|~
As you can see, all of the above characters are used as operators for various arithmetic and logical operations in C, which means that they had to reuse one of them as the character for declaring and dereferencing pointers.
They chose the asterisk (*), which is a decent choice because it somewhat bears the notion of a "point", and because multiplication is not one of the operations which are valid to perform on pointers.
They could have also chosen the caret (^), (which stands for exclusive-OR,) but I do not think that it is such a huge deal, and clearly, their options were very limited.
X*p
,X * p
,X* p
andX *p
all mean exactly the same thing. Hence the interesting mistakes likechar* p, q
where you expectq
to bechar*
but it really is just plain oldchar
.int ans = **a * 5
then you can always say,int x = **a; int ans = x * 5;