0

In C language,we can define different kinds of pointer such as:

  • int *p
  • char *p all of them have the same size 4 bytes or 8 bytes. All of them can be used as a parameter for the printf("%s",p),so how the complier distinguish between them?
storen
  • 1,025
  • 10
  • 22
  • Similar question seen yesterday, pretty sure there's a duplicate somewhere in SO. – Raptor Nov 21 '14 at 02:03
  • Also there's `int *p[10]` – mclaassen Nov 21 '14 at 02:05
  • `cdecl` on the inter-tubes: http://cdecl.org/ – Deduplicator Nov 21 '14 at 02:09
  • Passing any but the second one (which is of type `char*` - pointer to `char`) to `printf("%s", p);` invokes UB. Luckily, any decent implementation will complain. – Deduplicator Nov 21 '14 at 02:11
  • possible duplicate of [What is the difference between char \*s\[\] and char (\*s)\[\]?](http://stackoverflow.com/questions/27030694/what-is-the-difference-between-char-s-and-char-s) – 2501 Nov 21 '14 at 02:43
  • "all of them have the same size 4 bytes or 8 bytes" No, the sizes aren't the same, esp. in systems with word addressing and Harvard architecure. Even if all the pointer sizes are the same on that architecture, it doesn't necessarily be 4 or 8 bytes – phuclv Dec 07 '14 at 04:01

4 Answers4

2

You are right. All the pointers have the same size and they hold the same data type (a memory address). So, your question is legit.

The compiler needs to know about the data type the pointer points to in order to be able to find out how to deal with it. For example, an array is basically a pointer to an (preferably) allocated memory region. So, a[1] is a shorthand for *(a+1). But where does the next element of the array start? The compiler has no way to know this, unless your pointer has a type. For example, if you tell him that a points to int (4 bytes) and, for example, a = 0x100, he will know that a+1 is 0x104, because that is the address of the next element.

Also, knowing the type of the data the pointer points to is essential for knowing how to dereference the pointer (interpreting the data).

Paul92
  • 8,827
  • 1
  • 23
  • 37
2

It's all about static type checking and pointer arithmetics. Perhaps it's best illustrated by looking at a concrete example.

Consider this:

#include <stdio.h>

int main( int argc, char *argv[] )
{
   char x[10];

   char *p0       = &x[0];  /* ok */
   int  *p1       = &x[0];  /* <- type checking, warning #1 */
   char (*p2)[10] = &x;     /* ok */
   int  (*p3)[10] = &x;     /* <- type checking, warning #2 */

   (void)printf( "sizeof(char): %ld\n", sizeof( char ));
   (void)printf( "sizeof(int):  %ld\n", sizeof( int ));

   (void)printf( "p0: %p, p0+1: %p\n", (void*)p0, (void*)( p0+1 ));
   (void)printf( "p1: %p, p1+1: %p\n", (void*)p1, (void*)( p1+1 ));
   (void)printf( "p2: %p, p2+1: %p\n", (void*)p2, (void*)( p2+1 ));
   (void)printf( "p3: %p, p3+1: %p\n", (void*)p3, (void*)( p3+1 ));

   return 0;
}

Important: compile with -Wall (gcc -Wall -o test test.c)

The program will compile, but you'll get two warnings about incompatible pointer types, and rightly so.

% gcc -Wall -o test test.c
test.c: In function ‘main’:
test.c:9:21: warning: initialization from incompatible pointer type [enabled by default]
    int  *p1       = &x[0];  /* <- type checking, warning #1 */
                     ^
test.c:11:21: warning: initialization from incompatible pointer type [enabled by default]
    int  (*p3)[10] = &x;     /* <- type checking, warning #2 */
                     ^

Now run the program:

% ./test 
sizeof(char): 1
sizeof(int):  4
p0: 0x7fff9f6dc5c0, p0+1: 0x7fff9f6dc5c1  # + 1 char
p1: 0x7fff9f6dc5c0, p1+1: 0x7fff9f6dc5c4  # + 1 int (4 bytes here)
p2: 0x7fff9f6dc5c0, p2+1: 0x7fff9f6dc5ca  # + 10 chars
p3: 0x7fff9f6dc5c0, p3+1: 0x7fff9f6dc5e8  # + 10 ints (40 bytes here)

Here you can observe the impact on pointer arithmetics: although all 4 pointers were initialized to the same value, the same operation yields completely different results.

xbug
  • 1,394
  • 1
  • 11
  • 18
  • You could make this a much better answer by deleting about 75% of the lines of code you posted. And one compiler's output is more than enough. No need to provide two. – Carey Gregory Nov 21 '14 at 06:06
  • The balance between sweeping answers and tangled ones is not easy to find. I'm striving to provide the best answers I can, and to improve my signal-to-noise ratio overtime. I just removed the redundant compiler output, feel free to edit out the remaining material. – xbug Nov 21 '14 at 11:44
1

Think of it like the different in living spaces. Each residence has 1 address, but the residences are different sizes.

/*
 _________________________________________
/___________Studio Apartments_____________\
|  _   _   _   _   _   _   _   _   _   _  |
|_|0|_|1|_|2|_|3|_|4|_|5|_|6|_|7|_|8|_|9|_|

 _________________________________________
/____________2 Bed Apartments_____________\
|  _       _       _       _       _      |
|_|0|_____|1|_____|2|_____|3|_____|4|_____|

Note: different endianness may look like:
 _________________________________________
/____________2 Bed Apartments_____________\
|      _       _       _       _       _  |
|_____|0|_____|1|_____|2|_____|3|_____|4|_|
*/

typedef studio char; //tell the compiler what a "studio" is like
typedef apt2br short; //tell it what a 2 bedroom apartment is like

/*Now let's build our apartments at the first available address.*/
studio mystudios[10] = /*the letter people live here :)*/
  {'A','B','E','C','I','D','O','F','U','G'};

/*We just told our contractor to build somewhere - record locations for later.*/
studio *LetterStudios=&mystudios;

/* Let's say we want to print out all of our letter people residents
 * and no one has built an apartment complex next to them, so the data
 * following our last letter person is () a '0'
 */

printf("%s\n", (char *)LetterStudios);

/* if nothing is built we may get "ABECIDOFUG", but since we did not add our
 * own '\0' terminator then we get whatever happens to be next.  This is a
 * buffer overrun ... we may get "ABECIDOFUG<lots of garbage>" or worse
 */

Lets look at the 2 byte case:

/* So let's give ourselves some boundaries and loop through it, but this
 * case has 1 byte elements, so lets look at a 2 byte array
 */

apt2br myapts[5] = /*people with magic number names live here :)*/
  {0xFEFE, 0xB0B, 0xDADE, 0xABE, 0xBABE};
apt2br *MagicApartments=&myapts;

/* to get the number of units in an apartment complex we can always divide the
 * size of the whole complex by the size of a single unit
 */
for(int i=0;i<sizeof(myapts)/sizeof(myapts[0]);i++){
  printf("%X\n",myapts[i]);
}
/* Note: the sizeof() is on the array, not the pointer to it, all pointers are
 * going to be either 4 (32 bit) or 8 (64 bit), which would have printed only
 * 2 or 4 elements because the size of the "apartment" at the address is 2
 */

 /* you can still use the pointer though */
 int apartments = sizeof(myapts)/sizeof(myapts[0]);
 while (apartments--)
   printf("%X\n",*MagicApartments++);
 /* This just gives the inspector a number of apartments to inspect and points
  * him to the first apartment to inspect.  Each time he prints off the data
  * pointed to, moves his pointer to the next apartment and decrements the number
  * of apartments to inspect till he gets to 0.
  * Note however that now his MagicApartments pointer is past the last apartment
  * If he were to inspect again (without resetting MagicApartments=&myapts;) ,
  * he would end up inspecting the apartment next door... another buffer overrun
  */
technosaurus
  • 7,676
  • 1
  • 30
  • 52
-2

I think pointer just stored the address of variable. So All pointers have same size (4 bytes or 8 bytes) because the address bus is 32bits or 64bits. You can declare pointers like this

void * p = null;  
int* p2 = (int*)p;
float* p3 = (float*)p;

p, p2, p3 point to the same address. The data type we used when declare a pointer tells the compile how to process the data in this address.

For example, *p2 would be processed as a 4bytes integer and *p3 as a 8bytes float.

Onel Sarmiento
  • 1,608
  • 3
  • 20
  • 46