c++ - sirven - ¿Declarar tipo de punteros?
que es un puntero en c++ (10)
Entonces, ¿por qué tenemos que declarar su tipo?
Desea saber el tipo de puntero para poder hacer una comprobación de tipo estática .
También necesitamos conocer el tipo para que la aritmética del puntero funcione, por ejemplo, cuando indexamos en una matriz ( que es equivalente a la aritmética del puntero ) de diferentes tipos de tamaño, el puntero se ajustará por una cantidad dependiente del tipo. Si miramos el borrador de la sección estándar C99 6.5.6
operadores de aditivos dicen (el énfasis es mío ):
Además, ambos operandos tendrán un tipo aritmético, o un operando será un puntero a un tipo de objeto [...]
Por lo tanto, el puntero debe ser un tipo de objeto , lo que significa que no está incompleto o vacío.
También dijiste:
la dirección ocupa la misma cantidad de memoria cualquiera que sea el tipo. Entonces, ¿por qué tenemos que declarar su tipo?
Esto no siempre es cierto en C ++. El tamaño de los punteros a las funciones de los miembros puede cambiar dependiendo del tipo de clase, uno de los buenos artículos que lo cubre es que los punteros a las funciones de los miembros son animales muy extraños .
Además, podemos ver que tanto el borrador de la sección estándar de C99 sección 6.2.5
Tipos párrafo 27 que dice:
[...] Los punteros a otros tipos no necesitan tener los mismos requisitos de representación o alineación.
y el borrador de la sección estándar de C ++ 3.9.2
Tipos compuestos, párrafo 3 dice:
[...] La representación del valor de los tipos de puntero está definida por la implementación. Los punteros a las versiones cv-calificado y cv no calificado (3.9.3) de los tipos compatibles con el diseño deben tener los mismos requisitos de representación y alineación de valores (3.11). [...]
no requieren punteros para tener la misma representación excepto en casos específicos.
Acabo de leer que necesitamos dar el tipo de punteros mientras los declaramos en C (o C ++), es decir:
int *point ;
Hasta donde yo sé, los punteros almacenan la dirección de las variables, y la dirección ocupa la misma cantidad de memoria, cualquiera que sea el tipo. Entonces, ¿por qué tenemos que declarar su tipo?
Debe especificar el tipo como lo exige el estándar. Por otra parte, para que no haya problemas cuando intentes realizar la aritmética del puntero como suma o resta.
El tipo de puntero viene a jugar mientras se desreferencia y se usa la aritmética del puntero. Por ejemplo
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)
En el ejemplo anterior, el tipo de puntero es int para que el compilador comience a buscar los valores almacenados en los siguientes 4 bytes (si int es 4 bytes) comenzando desde la dirección de memoria 100. Entonces, el tipo de puntero le dice a los compiladores cuántos bytes debe buscar mientras desreferenciamos. Si el tipo de puntero no estaba allí, ¿cómo habría sabido el compilador cuántos octetos mirar mientras desreferenciaba? Y cuando hicimos ptr ++, el tipo de puntero indica cuánto debe aumentarse la ptr. Aquí ptr se incrementa en 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)
El tipo de puntero dice que ptr se incrementa en 1 byte.
En realidad, no necesitamos (ver a continuación) para declarar el tipo, pero deberíamos . El puntero almacena información sobre la ubicación de los objetos, mientras que el tipo define cuánto espacio ocupa en la memoria.
El tamaño del objeto almacenado en la memoria apuntada es necesario en varios casos: creación de matriz, asignación, copia de la memoria y finalmente creación del objeto utilizando new
.
Sin embargo, aún puede definir un puntero void
, si desea ocultar (por algún motivo) el tipo:
void* dontKnowWhatTypeIsHere;
Un puntero de vacío se considera universal. Puede señalar cualquier objeto, y cuando queremos usarlo con un tipo, haremos reinterpret_cast
.
Mientras que los procesadores a menudo tienen diferentes instrucciones para "cargar un byte de una dirección", "cargar una media palabra de 16 bits de una dirección" y "cargar una palabra de 32 bits de una dirección", y lo mismo para las operaciones de "almacenamiento", C usa la misma sintaxis para cargar un byte desde una dirección para cargar cualquier otro valor de tamaño. Dada la declaración:
int n = *p;
el compilador puede generar código que carga un byte, media palabra o palabra de la dirección en p y la almacena en n; si p es un * float, puede generar una secuencia de código más complicada para cargar un valor de coma flotante en c, truncarlo, convertirlo a int, y almacenar el valor convertido en n. Sin saber el tipo de p, el compilador no puede saber qué operación sería apropiada.
Del mismo modo, la declaración p++
puede aumentar la dirección en p
por uno, dos, cuatro o algún otro número. La cantidad por la cual se incrementa la dirección será sobre el tipo declarado de p. Si el compilador no conoce el tipo de p, no sabrá cómo ajustar la dirección.
Es posible declarar un puntero sin especificar el tipo de cosa a la que apunta. El tipo de dicho puntero es void*
. Sin embargo, uno debe convertir un void*
a un tipo de puntero real antes de hacer algo útil con él; la utilidad principal de void*
radica en el hecho de que si un puntero se convierte en void*
, se puede pasar como un void*
por código que no sabe nada sobre el tipo real del puntero. Si finalmente el puntero se da a un código que sí conoce su tipo, y ese código arroja el puntero a ese tipo, el resultado será el mismo que el puntero que se convirtió a void*
.
El código que tendrá que manejar punteros a cosas de las que no sabe a menudo puede emplear útilmente void*
para tales propósitos, pero el código que sí sabe sobre las cosas a las que apuntan los punteros generalmente debería declarar punteros del tipo correcto.
Muchos de los enunciados antes mencionados pero apan son puramente correctos. Ahora su pregunta ¿por qué definimos el tipo de punteros? Primera definición de puntero Un puntero que puede contener la dirección de otra variable. La definición anterior es parcial. La definición exacta es puntero es una variable que puede contener la dirección de una variable y si la desreferenciamos (trae el valor), devolverá el valor del presente en esa dirección. Si un puntero no puede devolver un valor en la desreferenciación, entonces no es un puntero. Puedes probar que incluso en el compilador gcc una variable simple también puede contener la dirección de otra variable, pero en la desreferencia te dará un error. Ahora el tamaño Independientemente de los tipos de datos, el tamaño del puntero siempre es igual al tamaño del entero en ese compilador específico. Entonces, el tamaño del puntero en el compilador gcc es 4bytes (tamaño del entero) y en turboc su tamaño es 2bytes (tamaño del entero). Ahora la pregunta es por qué es igual al tamaño del número entero. Cuál será la dirección de cualquier variable puede ser int, char, float, etc. la dirección siempre es un número entero entero y donde el número entero entero se almacena en int. Es por eso que el tamaño del puntero es igual al tamaño de int porque también almacena la dirección, que siempre es un número entero puro. Entonces, ¿cuál es la diferencia entre un int y char de cualquier otro puntero de tipos de datos? En el momento de la recuperación, su compilador obtendrá el número de bytes de acuerdo con sus tipos de datos; de lo contrario, obtendrá un error o no un error, pero obtendrá un resultado impredecible, pero no para mí. La misma regla se aplica para incrementar y disminuir el puntero, siempre aumenta y disminuye según los tipos de datos del puntero. El tamaño del puntero no depende del tipo de datos y, por lo tanto, de la razón por la cual su lista de enlaces entra en escena porque si intenta declarar la estructura dentro de la misma variable, obtendrá un error de tiempo de compilación porque su compilador no tiene el tamaño estructura antes de su declaración completa, pero se permiten punteros autorreferenciales de la misma estructura ¿por qué? La única respuesta porque el tamaño del puntero no depende del tamaño del tipo de datos. Si tiene alguna consulta, por favor pregúnteme. Gracias asif aftab
Para que pueda realizar aritmética y otras operaciones. Considera estos dos ejemplos:
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*/
Espero que esto te ayude !
Porque:
- las direcciones a diferentes tipos no necesitan tener el mismo tamaño . La norma explícitamente lo especifica ( norma C 2011 (borrador en línea), 6.2.5 / 28).
- type-safety: esto permite que el compilador detecte cuando proporciona un puntero incompatible a una función o en una tarea. Esto, a su vez, evita situaciones desagradables en las que desordene el orden de los argumentos para una función.
- el compilador necesita saber el tipo cuando el puntero es desreferenciado.
- para hacer una aritmética de puntero, es necesario conocer el tamaño del objeto señalado y, por lo tanto, su tipo.
Los dos últimos puntos no se aplican a los punteros void
, que es por lo que no se pueden desreferenciar y no se puede hacer aritmética con los punteros. El estándar especifica que un puntero void
debe ser lo suficientemente grande como para contener cualquier tipo de puntero (excepto los punteros de función, que son totalmente diferentes) y que la asignación void
desde los punteros void
se puede realizar sin moldes (al menos en C, en C ++ los moldes siempre son necesarios) .
Tipo de seguridad. Si no sabes a qué p
se supone que apunta, entonces no habría nada para evitar errores de categoría como
*p = "Nonsense";
int i = *p;
La comprobación estática de tipos es una herramienta muy poderosa para prevenir todo tipo de errores como ese.
C y C ++ también admiten la aritmética del puntero , que solo funciona si se conoce el tamaño del tipo de destino.
dirección ocupa la misma cantidad de memoria sea cual sea mi ser el tipo
Eso es cierto para las plataformas populares de hoy. Pero ha habido plataformas para las que ese no era el caso. Por ejemplo, un puntero a una palabra de varios bytes podría ser más pequeño que un puntero a un solo byte, ya que no necesita representar el desplazamiento del byte dentro de la palabra.
Una razón es en la aritmética del puntero. No puede hacer p+1
menos que sepa el tamaño del elemento al que apunta p
, que es el tamaño del tipo al que p
es un puntero. Si intenta p+1
en un void *p
, es probable que obtenga una mala respuesta (es lo mismo que si lo hiciera en un char *
pero tal vez no quería eso, es atrapado por -pedantic
como una advertencia y -pedantic-errors
como un error).
Otra razón es seguridad de tipo. Si una función recibe como argumento un int *
no puede pasar un puntero a char
(una cadena) allí. Tendría una advertencia (un error con -Werror
/ -pedantic-errors
). Considere este código (ficticio):
void test(int *x)
{
}
int main()
{
char *x = "xyz";
test(x);
return 0;
}
La compilación (usando gcc (GCC) 4.8.2 20131017 (Red Hat 4.8.2-1)
) da:
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)
^