42

I just read that we need to give the type of pointers while declaring them in C (or C++) i.e.:

int *point ;

As far as I know, pointers store the address of variables, and address occupies same amount of memory whatever may be the type. So, why do we need to declare its type?

Alex Riley
  • 169,130
  • 45
  • 262
  • 238
CodeBlaster
  • 525
  • 5
  • 12
  • 5
    C does have 'void *' which is a pointer to anything. – woolstar Dec 05 '13 at 18:38
  • 26
    First, your understanding is simply dead wrong; there is no requirement that every address be the same size. Second, try naming **all** the basic operations one can perform on a pointer. It's not a long list, so it shouldn't take you long. In how many of them do you need to know the type of the pointed-to variable? – Eric Lippert Dec 05 '13 at 22:32

10 Answers10

70

Type-safety. If you don't know what p is supposed to point to, then there'd be nothing to prevent category errors like

*p = "Nonsense";
int i = *p;

Static type checking is a very powerful tool for preventing all kinds of errors like that.

C and C++ also support pointer arithmetic, which only works if the size of the target type is known.

address occupies same amount of memory whatever my be the type

That's true for today's popular platforms. But there have been platforms for which that wasn't the case. For example, a pointer to a multi-byte word could be smaller than a pointer to a single byte, since it doesn't need to represent the byte's offset within the word.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Assuming the target character set is ASCII or Unicode, and `p` is of a type which is assignment compatible with a `char*`, the above code will perfectly legitimately set `i` equal to 78. The result of dereferencing a pointer is an lvalue of the same type as the pointer. – supercat Dec 05 '13 at 21:44
  • @supercat: Indeed, with certain assumptions, that code might be valid. Type checking can help to check those assumptions, and make sure the code is valid. – Mike Seymour Dec 06 '13 at 02:22
  • @supercat: Although of course (in the real C and C++ languages, and perhaps the weakly-typed hypothetical language we're considering for the sake of the question) that won't write the character `'N'` to the byte pointed to by `p` in any case. The string literal will convert to a pointer, and whatever's at `*p` will be assigned from that pointer value. – Mike Seymour Dec 06 '13 at 02:32
  • Oops, I hadn't noticed the `*` before the first `p`. If `p` is a `**char`, the first statement would be valid but the second not. If it's only singly-indirected, the first statement would be invalid (unless the preceding token was a type such that the statement became something like `char *p = "Nonsense";`). – supercat Dec 06 '13 at 16:01
35

Because:

  1. addresses to different types don't need to have the same size. The standard explicitly specifies so (C 2011 standard (online draft), 6.2.5/28).
  2. type-safety: this allows the compiler to detect when you provide an incompatible pointer to a function, or in an assignment. This in turn prevents ugly situations where you mess up the argument order to a function.
  3. the compiler needs to know the type when the pointer is dereferenced.
  4. to do pointer arithmetic the size of the object pointed to needs to be known and thus its type.

The last two points don't apply to void pointers, which is why they cannot by dereferenced and no pointer arithmetic may be done on them. The standard specifies that a void pointer must be big enough to hold any kind of pointer (except function pointers, which are a different story altogether) and that assignment to and from void pointers may be made without casts (at least in C, in C++ casts are always needed).

Kninnug
  • 7,992
  • 1
  • 30
  • 42
13

One reason is in pointer arithmetic. You cannot do p+1 unless you know the size of the element to which p points -- that is the size of the type to which p is a pointer. If you'd try p+1 on a void *p you're likely to get a bad answer (it is the same as if done on a char * but maybe you didn't want that; it is caught by -pedantic as a warning and by -pedantic-errors as an error).

Another reason is type safety. If a function receives as argument an int * you cannot pass a pointer to char (a string) there. You'd get a warning (an error with -Werror / -pedantic-errors). Consider this (dummy) code:

void test(int *x)
{
}

int main()
{
    char *x = "xyz";
    test(x);
    return 0;
}

Compiling (using gcc (GCC) 4.8.2 20131017 (Red Hat 4.8.2-1)) gives:

1.c: In function ‘main’:
1.c:8:2: warning: passing argument 1 of ‘test’ from incompatible pointer type [enabled by default]
  test(x);
  ^
1.c:1:6: note: expected ‘int *’ but argument is of type ‘char *’
 void test(int *x)
      ^
Mihai Maruseac
  • 20,967
  • 7
  • 57
  • 109
  • It should, but it is an warning (`pointer to incompatible type`) – Mihai Maruseac Dec 05 '13 at 18:30
  • [Clang error](http://coliru.stacked-crooked.com/a/1a4ec482a2fbd754), [GCC error](http://coliru.stacked-crooked.com/a/bab609134414d220). Granted it's 4.8.1, but why would it change? – chris Dec 05 '13 at 18:35
  • Oh, except that's a good thing because I'm fairly sure it's an error by the standard. In my experiences, pedantic warnings have been about better standard conformance. – chris Dec 05 '13 at 18:37
  • It should and it is a good thing. But beginners don't use it, so they'll only get a warning. – Mihai Maruseac Dec 05 '13 at 18:38
  • 1
    All good except that arithmetic on void pointers behaves the same as char pointers. Not an error at all. – Guido Dec 05 '13 at 18:54
  • 2
    @Guido [this answer](http://stackoverflow.com/a/3524270/249237) says pointer arithmetic on `void *` is **not** the same as `char *` and illegal (in both C and C++). – Kninnug Dec 05 '13 at 19:22
  • @Kninnug: I believe that GCC allows treating void* as char* as an extension. – Zan Lynx Dec 05 '13 at 20:07
  • @Kninnug: Which is useful for doing stuff with the return values from OS functions like mmap, although it isn't a big deal to cast to char*. – Zan Lynx Dec 05 '13 at 20:09
  • @ZanLynx The answer I linked addresses that as well. Relying on that isn't wise as it's not portable and if you want to treat it as a `char *` make it into a `char *`, that also makes the intent clearer. – Kninnug Dec 05 '13 at 20:15
11

So, why do we need to declare its type?

You want to know the type of the pointer so you can do static type checking.

We also need to know the type in order for pointer arithmetic to work, for example when we index into an array(which is equivalent to pointer arithmetic) of different size types the pointer will be adjusted by a type dependent amount. If we look at the draft C99 standard section 6.5.6 Additive operators says (emphasis mine):

For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to an object type [...]

So the pointer needs to be an object type, which means not incomplete or void.

You also said:

address occupies same amount of memory whatever may be the type. So, why do we need to declare its type?

This is not always true in C++ the size of pointers to member functions can change depending on the class type, one of the good articles that covers this is Pointers to member functions are very strange animals.

Furthermore we can see that both the C99 draft standard section section 6.2.5 Types paragraph 27 which says:

[...] Pointers to other types need not have the same representation or alignment requirements.

and the draft C++ standard section 3.9.2 Compound types paragraph 3 says:

[...] The value representation of pointer types is implementation-defined. Pointers to cv-qualified and cv-unqualified versions (3.9.3) of layout-compatible types shall have the same value representation and alignment requirements (3.11). [...]

do not require pointers to have the same representation except in specific cases.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
8

You need to specify the type as the standard demands so. Moreover, so that there are no issues when you try to perform pointer arithmetic like addition or subtraction.

Juzz Coding
  • 321
  • 1
  • 11
5

The type of pointer comes to play while dereferencing and pointer arithmetic. For example

int x=10;     //Lets suppose the address of x=100
int *ptr=&x;   //ptr has value 100
printf("The value of x is %d", *ptr);
ptr++;  // ptr has value 104(if int is 4bytes)

In the above example the pointer type is int so the compiler will start looking for the values stored in the next 4 bytes(if int is 4bytes) starting from memory address 100. So the type of pointer tell the compilers that how many bytes its should look for while dereferencing. If the pointer type was not there how would the compiler would have known that how many bytes to look while dereferencing. And when we did ptr++ the type of pointer tells by how much the ptr should be incremented. Here ptr is incremented by 4.

char c='a';   //Lets suppose the address of c = 200
char* ptr=&c;   //ptr has value 200
ptr++;   //ptr has value 201(char assumed to be 1 byte) 

The pointer type tells that ptr is incremented by 1 byte.

APan
  • 364
  • 1
  • 10
5

While processors often have different instructions for "load a byte from an address", "load a 16-bit halfword from an address", and "load a 32-bit word from an address", and likewise for "store" operations, C uses the same syntax to load a byte from an address as to load any other size value. Given the statement:

int n = *p;

the compiler may generate code which loads a byte, halfword, or word from the address in p and store it into n; if p is a *float, it may generate a more complicated code sequence to load a floating-point value in c, truncate it, convert to int, and store the converted value into n. Without knowing the type of p, the compiler can't know which operation would be appropriate.

Likewise, the statement p++ may increase the address in p by one, two, four, or some other number. The amount by which the address is increased will upon the declared type of p. If the compiler doesn't know the type of p, it won't know how to adjust the address.

It is possible to declare a pointer without specifying the type of the thing to which it points. The type of such a pointer is void*. One must convert a void* to a real pointer type before doing anything useful with it, however; the primary usefulness of void* lies in the fact that if a pointer is converted to void*, it may be passed around as a void* by code which knows nothing about the pointer's actual type. If the pointer is eventually given to code which does know its type, and that code casts the pointer back to that type, the result will be the same as the pointer that had been converted to void*.

Code which will have to handle pointers to things it knows nothing about can often usefully employ void* for such purposes, but code which does know about the things to which pointers point should generally declare pointers of the proper type.

supercat
  • 77,689
  • 9
  • 166
  • 211
3

So that it can perform arithmetic and other operations. Consider these two examples:

int* p; /* let the address of the memory location p pointing to be 1000*/
p++;
printf("%u",p); /* prints 1004 since it is an integer pointer*/


char *p; /* let the address of the memory location p pointing to be 1000*/
p++;
printf("%u",p); /* prints 1001 since it is an char pointer*/

I hope this helps you !

Kaustav Ray
  • 744
  • 6
  • 20
0

We actually don't need (see below) to declare the type, but we should. The pointer stores information about the objects location, while the type defines how much space it takes in memory.

The size of the object stored at the pointed memory is needed in various cases - array creation, assigment, copying the memory, and finally - creating the object using new.

However you can still define a void pointer, if you want to hide (for any reason) the type:

void* dontKnowWhatTypeIsHere;

A void pointer is considered an universal one. It can point to any object, and when we want to use it with a type, we'll just do reinterpret_cast.

Paweł Stawarz
  • 3,952
  • 2
  • 17
  • 26
-5

Lots of aforesaid statement but apan is purely right. Now your question why we define type of pointers? First definition of pointer A pointer which can hold the address of another variable. The above definition is partial. The exact definition is pointer is a variable which can hold the address of a variable and if we de-reference(fetch the value) it, it will returns the value of the present on that address. If a pointer is fails to returns a value on dereferencing then it is not a pointer. You can try that even in gcc compiler a simple variable can also hold the address of another variable but at dereference it will give you error. Now the size Irrespective of data types the size of pointer is always equal to the size of integer on that specific compiler. So the size of pointer in gcc compiler is 4bytes(size of integer) and in turboc its size is 2bytes(size of integer). Now question is why equal to size of integer. What will be the address of any variable it may be int, char, float etc the address is always a whole integer number and where the whole integer number is stores in int. That's why the size of pointer is equal to the size of int because it also stores the address which is always a pure integer data. Then what is the difference between an int and char of any other data types pointer. At the time of retrieval your compiler will fetch the number of bytes according to your data types other wise you will get error or not an error but for you some unpredictable result but not for me. Same rule apply for increment and decrement the pointer it always increment and decrement according to pointer data types. The size of pointer doesn't depend on the data type and hence the reason that your link list come into picture because if you try to declare the structure inside same variable then you will get compile time error because your compiler doesn't the size of structure before its complete declaration but self referential pointer of same structure are allowed why? The only answer because the size of pointer doesn't depend the size of data type. If you any query then please ask me. Thanks asif aftab

asifaftab87
  • 1,315
  • 24
  • 28
  • *"Now the size Irrespective of data types the size of pointer is always equal to the size of integer on that specific compiler."* **NO**. While in many cases this may be so it is neither specified by the standard nor always true. Think of 64-bit platforms where an `int` may be 4 bytes but pointers are 8 bytes. Or embedded/old platforms where a non-linear addressing-scheme is used. – Kninnug Dec 05 '13 at 20:53
  • "*exact definition is pointer is a variable which can hold the address of a variable*" No, a pointer is a *value*, not a *variable*. – Eric Lippert Dec 05 '13 at 21:22
  • Kninnug is absolutely correct; there is no requirement for any two pointers of different types to be of the same size, and no requirement for them to be of the same size as int. On segmented architectures there can also be a difference in size between "near" and "far" pointers. – Eric Lippert Dec 05 '13 at 21:24
  • "*That's why the size of pointer is equal to the size of int because it also stores the address which is always a pure integer data*" No, absolutely not! There is no requirement whatsoever that a pointer be implemented as an integer! Perhaps you do not remember what it was like writing code for x86 machines back in the 16 bit days, where there could be 16 bit integers but 32 bit pointers consisting of 16 bit offset and 16 bit segment, giving you only 20 bits of effective addressing. – Eric Lippert Dec 05 '13 at 21:27
  • Thanks Eric for your rectification of my answer. – asifaftab87 Dec 06 '13 at 04:13
  • My above answer is only on the basis 32bits gcc compiler and not for very in depth feature of embedded system. Here my discussion is very helpful for beginner because the difficult thing to understand in C is pointer and whatever the comments as response of my post they all are very very experience guy. Now just see the question the boy is confuse about pointer property means he is novice and we can't behaves so badly with a beginner. I worked as a trainer for one and half year and I know how to explain how things are working not how an OS is working. We always start with small step. Sorry for – asifaftab87 Dec 06 '13 at 19:26
  • Sorry to all who comments on my post. I am agree with your concepts. Thanks for your comments again – asifaftab87 Dec 06 '13 at 19:28