¿Por qué diferentes tipos de punteros para diferentes tipos de datos en c?

Si tenemos que mantener una dirección de cualquier tipo de datos, entonces necesitamos un puntero de ese tipo de datos. Pero un puntero es simplemente una dirección, y una dirección es siempre tipo int , entonces ¿por qué la dirección de retención de cualquier tipo de datos requiere el puntero de ese tipo?

Hay varias razones:

  • No todas las direcciones son iguales; En particular, en las architectures que no son de Von Neuman (por ejemplo, Harvard ), los punteros a la memoria del código (donde a menudo se almacenan constantes) y los punteros a la memoria de datos son diferentes.
  • Debe conocer el tipo subyacente para poder realizar sus accesos correctamente. Por ejemplo, leer o escribir un char es diferente de leer o escribir un double .
  • Necesitas información adicional para realizar aritmética de punteros.

Tenga en cuenta que hay un tipo de puntero que significa “simplemente un puntero” en C, llamado void* . Puede usar este puntero para transferir una dirección en la memoria, pero necesita convertirla en algo útil para realizar operaciones en la memoria apuntada por void* .

Los punteros no son solo int . Tienen implícitamente semántica.

Aquí hay un par de ejemplos:

  • p->member solo tiene sentido si sabes a qué tipo p apunta.

  • p = p+1; se comporta de manera diferente según el tamaño del objeto al que apunta (en el sentido de que ‘p’ en realidad se incrementa, cuando se ve como un entero sin signo, por el tamaño del tipo al que apunta).

Puede tener un puntero sin tipo en C muy fácilmente: simplemente use void * para todos los punteros. Esto sería bastante tonto aunque por dos razones que se me ocurren.

En primer lugar, al especificar los datos a los que se apunta en el tipo, el comstackdor le ahorra muchos errores tontos, tipográficos o de otro tipo. Si, por el contrario, priva al comstackdor de esta información, está obligado a pasar MUCHO tiempo depurando cosas que nunca deberían haber sido un problema.

Además, probablemente has usado “aritmética de punteros”. Por ejemplo, int *pInt = &someInt; pInt++; int *pInt = &someInt; pInt++; – que avanza el puntero al siguiente entero en la memoria; esto funciona independientemente del tipo y avanza a la dirección correcta, pero solo puede funcionar si el comstackdor sabe el tamaño de lo que se está apuntando.

El siguiente ejemplo puede ayudar a comprender las diferencias entre punteros de diferentes tipos:

 #include  int main() { // pointer to char char * cp = "Abcdefghijk"; // pinter 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; } 

la salida es

introduzca la descripción de la imagen aquí

es importante entender que la expresión de address+1 da un resultado diferente según el tipo de address , es decir, +1 significa sizeof(addressed data) , como sizeof(*address) .

Por lo tanto, si en su sistema (para su comstackdor) sizeof(int) y sizeof(char) son diferentes (por ejemplo, 4 y 1), los resultados de cp+1 y ip+1 también son diferentes. En mi sistema es:

 E05859(hex) - E05858(hex) = 14702684(dec) - 14702681(dec) = 1 byte for char E0585C(hex) - E05858(hex) = 14702684(dec) - 14702680(dec) = 4 bytes for int 

Nota: los valores de dirección específicos no son importantes en este caso, la única diferencia es importante.

Actualizar:

Por cierto, la aritmética de direcciones (punteros) no está limitada por +1 o ++ , por lo que se pueden hacer muchos ejemplos, como:

 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)); 

con salida

introduzca la descripción de la imagen aquí

Así que, para una mejor comprensión lee el tutorial.

Porque su suposición de que “la dirección es siempre tipo int” es incorrecta.

Es totalmente posible crear una architecture de computadora donde, por ejemplo, los punteros a los caracteres son más grandes que los punteros a las palabras, por alguna razón. C se encargará de esto.

Además, por supuesto, los punteros pueden ser anulados y, cuando lo hace, el comstackdor necesita saber el tipo de datos que espera encontrar en la dirección en cuestión. De lo contrario, no puede generar las instrucciones adecuadas para tratar con esos datos.

Considerar:

 char *x = malloc(sizeof *x); *x = 0; double *y = malloc(sizeof *y); *y = 0; 

Estos dos fragmentos escribirán cantidades de memoria totalmente diferentes (o explotarán si las asignaciones fallan, no importa eso por ahora), pero la constante literal real ( 0 que es de tipo int ) es la misma en ambos casos. La información sobre los tipos de punteros le permite al comstackdor generar el código adecuado.

Es principalmente para aquellos que leen el código después de usted para que puedan saber qué se almacena en esa dirección. Además, si realiza alguna aritmética de punteros en su código, el comstackdor debe saber cuánto se supone que debe avanzar si hace algo como pSomething ++, que viene dado por el tipo de puntero, ya que el tamaño de su tipo de datos es Conocido antes de la comstackción.

Porque el tipo de puntero le dice al comstackdor que a la vez en cuántos bytes puede realizar la operación.

Ejemplo: – en caso de char solo 1 byte
Y puede ser diferente en caso de int 2 byte.