Why are there different types of pointers for different data types in C?
Pointers are not just int
. They implicitly have semantics.
Here are a couple of examples:
p->member
only makes sense if you know what typep
points to.p = p+1;
behaves differently depending on the size of the object you point to (in the sense that 'p' in in fact incremented, when seen as an unsigned integer, by the size of the type it points to).
You can have a typeless pointer in C very easily -- you just use void *
for all pointers. This would be rather foolish though for two reasons I can think of.
First, by specifying the data that is pointed to in the type, the compiler saves you from many silly mistakes, typo or otherwise. If instead you deprive the compiler of this information you are bound to spend a LOT of time debugging things that should never have been an issue.
In addition, you've probably used "pointer arithmetic". For example, int *pInt = &someInt; pInt++;
-- that advances the pointer to the next integer in memory; this works regardless of the type, and advances to the proper address, but it can only work if the compiler knows the size of what is being pointed to.
There are several reasons:
- Not all addresses are created equal; in particular, in non Von Neuman (e.g. Harvard) architectures pointers to code memory (where you often store constants) and a pointers to data memory are different.
- You need to know the underlying type in order to perform your accesses correctly. For example, reading or writing a
char
is different from reading or writing adouble
. - You need additional information to perform pointer arithmetic.
Note that there is a pointer type that means "simply a pointer" in C, called void*
. You can use this pointer to transfer an address in memory, but you need to cast it to something useful in order to perform operations in the memory pointed to by void*
.
The following example can help to understand the differences between pointers of different types:
#include <stdio.h>
int main()
{
// Pointer to char
char * cp = "Abcdefghijk";
// Pointer to int
int * ip = (int *)cp; // To the same address
// Try address arithmetic
printf("Test of char*:\n");
printf("address %p contains data %c\n", cp, *cp);
printf("address %p contains data %c\n", (cp+1), *(cp+1));
printf("Test of int*:\n");
printf("address %p contains data %c\n", ip, *ip);
printf("address %p contains data %c\n", (ip + 1), *(ip + 1));
return 0;
}
The output is:
It is important to understand that address+1
expression gives different result depending on address
type, i.e. +1
means sizeof(addressed data)
, like sizeof(*address)
.
So, if in your system (for your compiler) sizeof(int)
and sizeof(char)
are different (e.g., 4 and 1), results of cp+1
and ip+1
is also different. In my system it is:
E05859(hex) - E05858(hex) = 14702684(dec) - 14702681(dec) = 1 byte for char
E0585C(hex) - E05858(hex) = 14702684(dec) - 14702680(dec) = 4 bytes for int
Note: specific address values are not important in this case. The only difference is the variable type the pointers hold, which clearly is important.
Update:
By the way, address (pointer) arithmetic is not limited by +1
or ++
, so many examples can be made, like:
int arr[] = { 1, 2, 3, 4, 5, 6 };
int *p1 = &arr[1];
int *p4 = &arr[4];
printf("Distance between %d and %d is %d\n", *p1, *p4, p4 - p1);
printf("But addresses are %p and %p have absolute difference in %d\n", p1, p4, int(p4) - int(p1));
With output:
So, for better understanding, read the tutorial.