3

In order to have better understanding of pointers, I'd like to have this cleared up. Different data types require different pointers, like char* or int*. Are all these pointers considered to be different data types or are they just the same data type?

Kaiyaha
  • 448
  • 3
  • 9
  • 1
    What exactly is `different types of the same data type`? – Sourav Ghosh Jul 24 '20 at 15:16
  • @SouravGhosh since warnings mark different pointers differently (char* int* etc.), I might've thought it's something like different types of the same data, but of course I'm not quite sure what I'm talking about, otherwise I woudn't have asked – Kaiyaha Jul 24 '20 at 15:20
  • To summarize the several excellent answers as briefly as possible: "pointer" is not a data type, but rather a *category* of data types. Each combination of type qualifiers and pointed-to data type characterizes a different pointer type. – John Bollinger Jul 24 '20 at 16:12
  • I've stood corrected, now the question doesn't say about different types of the same data type, just simply the same data type – Kaiyaha Jul 24 '20 at 20:46
  • @JohnBollinger Well, if 'pointer' is not a data type and a category of that instead, what is a particular single pointer itself then? And what are the elements of that category? – Kaiyaha Jul 24 '20 at 20:51

4 Answers4

4

Are different pointers considered to be different data types?

Yes.

Different data types require different pointers, like char* or int*. Are all these pointers considered to be different data types or are they just different types of the same data type?

All are pointers, but their type is different when they point to objects of different type.

Note that beside the difference of the type of the pointer; their size in memory can also be different:

Also there is nothing like "different types of the same data type". Either the type is different or it is the same.

  • Yes, that's what confused me: the name is the same (a pointer), but types are different. Other data types don't seem to have this issue – Kaiyaha Jul 24 '20 at 15:23
  • 1
    @Kaiyaha A pointer is always associated with the type of the object they point to. So if the type of the object they point to is different, they (the pointers) are different. – RobertS supports Monica Cellio Jul 24 '20 at 15:25
3

Unless two types are the “same type,” they are different types:

  • int and long are different types even if they use exactly the same numbers of bits for the same things. We know this because C 2018 6.3.1.1 tells us they have different ranks (a hierarchy in rules about promotions and conversions).
  • struct foo { int x; } and struct bar { int x; } are different types even though they use exactly the same numbers of bits for the same things.
  • typedef defines a new name for an existing type; the new name is not a different type, just a different name for the same type.
  • char * and const char * are different types, as are int * and long *, again even if int and long are the same size.

Beyond that, C has a notion of “compatible” types. Roughly speaking, two types are compatible if one can be used in place of the other in certain situations. For example, an int [3] (array of three int) is compatible with an int [] (array of unspecified number of int) because an array of three int can supply a requirement for an array of an unspecified number of int. Filling in the size just completes the int [].

C 2018 6.7.6.1 tells us:

For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.

From this, we can see that not only are two different pointers types are different types but that some pointer types are not compatible with other pointer types. The rules about compatibility are somewhat involved, since they need to reconcile various flexible or incomplete parts of types, such as functions without complete parameter lists.

C 2018 6.3.2.3 tells us about conversions between pointer types, including:

  • A pointer to an object type may be converted to void * and back.
  • A pointer to a non-qualified type may be converted to a pointer to a qualified types (such as char * to const char *).
  • A pointer to an object type may be converted to a pointer to another object type if it has the required alignment.
  • A pointer to a function type may be converted to a pointer to another function type.

Again, the fact that only certain conversions are defined indicates to us that different types of pointers are different, and possibly in fundamental ways that could prevent a C implementation from converting between them.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

When a char * is created, it points to an area of memory that will accommodate char sized granularity for its variables. A int * will point to an area of memory that will accommodate int sized granularity. So, although sizeof(int *) == sizeof(char *) (caveat) They have uniquely different properties.

For example, this becomes apparent when considering what happens when memory is created for each:

char *buf = malloc(10);//reserves 10 memory locations, sizeof(char) 
                       //(always 1 byte) wide

int *val = malloc(sizeof(*val)*10);// reserves 10 memory locations sizeof(int)
                                   // (typically 4 bytes wide for 32bit target) 

Note that in requesting memory allocation the count of bytes used in the malloc expression should always be a factor of the sizeof the type.

This illustrates, again, that although the size of the pointer variables will be the same (either 4 or 8 bytes, depending on either 32bit or 64bit addressing), the memory required to accommodate 10 elements of each type will be significantly different.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • 1
    Hit post too soon? :) – Sourav Ghosh Jul 24 '20 at 15:15
  • @SouravGhosh - Yes :) – ryyker Jul 24 '20 at 15:16
  • 1
    @ryyker Well, you've just given be better understanding of malloc() as well! I used to think the argument of this function is a memory size itself, not the amount of the sizes. Thanks! – Kaiyaha Jul 24 '20 at 15:26
  • @Kaiyaha - take another look. The original allocation was incomplete. Sorry for confusion on that point. [malloc()](https://www.tutorialspoint.com/c_standard_library/c_function_malloc.htm) argument is in bytes. Setting the argument to only `10` for the `int *` was a mistake. The point was supposed to be to illustrate the _need to accomdate_ the right size for different variable `types`. – ryyker Jul 24 '20 at 15:34
  • @ryyker So, if I need an array of say 3 integers, the malloc() argument must be like 3 sizes of integers? (like 3*sizeof(int) or 3 * 4)? – Kaiyaha Jul 24 '20 at 15:37
  • @Kaiyaha - The `sizeof` an `int`, although commonly `4` bytes may be defined differently depending on target size, (32 or 64 bit) or on other environment definitions. It is always preferrable to use the `sizeof` operator to get the size of the type. – ryyker Jul 24 '20 at 15:39
  • Note that `sizeof(int *) == sizeof(char *)` is not mandated and *can* be wrong. – RobertS supports Monica Cellio Jul 24 '20 at 15:40
  • @ryyker I know, I specified that to make it clearer for myself. But yes, it's more reasonable to specify it using a type or a var of that type – Kaiyaha Jul 24 '20 at 15:42
  • @Kaiyaha Note that the more sneaky and safer method is `int *ptr = malloc(sizeof(*ptr) * 3);`. – RobertS supports Monica Cellio Jul 24 '20 at 15:43
  • @RobertSsupportsMonicaCellio I'm afraid I cannot assess the advantage of this piece of code yet :) – Kaiyaha Jul 24 '20 at 15:45
  • @Kaiyaha You dereference the pointer itself which always ensures that the type to point to is correct if you change the type of the object `ptr` is pointing to and with that `ptr` itself. - Imagine you would change `ptr` but not the call to `malloc()` then you likely will have very much trouble with the memory. – RobertS supports Monica Cellio Jul 24 '20 at 15:46
  • @RobertSsupportsMonicaCellio If I got that, you mean if I want to redefine the data type, I have less code to retype, right? Like what constants are used for – Kaiyaha Jul 24 '20 at 15:48
  • 1
    @RobertSsupportsMonicaCellio - Thanks, you are right! and I added a `caveat` to address that. – ryyker Jul 24 '20 at 15:50
  • 1
    @Kaiyaha It is not only that you have less to retype. If you forget to adjust the `malloc()` call you are in serious trouble as the allocated memory does not match the one you think it is allocated for. Read or Write operations at this memory invoke undefined behavior, when the allocated memory is too less. To prevent this, you allocate memory for the object `ptr` points to and you are always on the safe side. – RobertS supports Monica Cellio Jul 24 '20 at 15:52
  • 1
    @Kaiyaha - for example, given int *var = malloc(some value of bytes); either `numberOfElements*sizeof(int)` or `numberOfElements*sizeof(*var)` can be passed. The second is idiomatic, and preferrable mostly for making code maintenance a little easier. i.e. should somebody change the `type` in future edits, the `malloc function call would not have to be touched, i.e. `*var` will always be `*var` regardless of what type it is. – ryyker Jul 24 '20 at 15:55
  • @ryyker Also if you set the `sizeof()` operation in front like `sizeof(*var) * numberofelements` inside of the `malloc()` argument, it ensures `size_t` arithmetic. – RobertS supports Monica Cellio Jul 24 '20 at 16:06
  • @RobertSsupportsMonicaCellio - I am not sure what you are saying, are you saying that `10*sizeof(x)` will give a different result than `sizeof(x)*10` ? Give me a link. – ryyker Jul 24 '20 at 16:10
  • 1
    @ryyker [Here](https://stackoverflow.com/a/41595104/12139179) I found a good answer from chux about that. – RobertS supports Monica Cellio Jul 24 '20 at 16:17
  • 1
    @RobertSsupportsMonicaCellio - Never knew that - Thanks. Edited to reflect. – ryyker Jul 24 '20 at 16:21
1

Yes, they are different data types, as they point to different types of data.

In other words, their usage and properties varies (example: same pointer arithmetic on different pointer type will yield different result) and they have different alignment requirements.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261