sirven que punteros puntero para operaciones los lenguaje declaracion con cadenas aritmetica c pointers initialization

que - punteros void lenguaje c



¿Es posible inicializar un puntero C a NULL? (9)

Había estado escribiendo cosas como

char *x=NULL;

asumiendo que

char *x=2;

crearía un puntero de caracteres para abordar 2.

Pero, en The GNU C Programming Tutorial dice que int *my_int_ptr = 2; almacena el valor entero 2 en cualquier dirección aleatoria que se encuentre en my_int_ptr cuando se asigna.

Esto parecería implicar que mi propio char *x=NULL está asignando cualquier valor de NULL a un char a alguna dirección aleatoria en la memoria.

Mientras

#include <stdlib.h> #include <stdio.h> int main() { char *x=NULL; if (x==NULL) printf("is NULL/n"); return EXIT_SUCCESS; }

de hecho, imprime

es nulo

cuando lo compilo y lo ejecuto, me preocupa que confíe en un comportamiento indefinido, o al menos un comportamiento poco especificado, y que deba escribir

char *x; x=NULL;

en lugar.


¿Es posible inicializar un puntero C a NULL?

TL; DR Sí, mucho.

El reclamo real hecho en la guía dice:

Por otro lado, si usa solo la asignación inicial única, int *my_int_ptr = 2; , el programa intentará llenar el contenido de la ubicación de memoria señalada por my_int_ptr con el valor 2. Dado que my_int_ptr está lleno de basura, puede ser cualquier dirección. [...]

Bueno, están equivocados, tienes razón.

Para la declaración, ( ignorando, por ahora, el hecho de que la conversión de puntero a entero es un comportamiento definido por la implementación )

int * my_int_ptr = 2;

my_int_ptr es una variable (de tipo puntero a int ), tiene una dirección propia (tipo: dirección de puntero a entero), está almacenando un valor de 2 en esa dirección.

Ahora, my_int_ptr , al ser un tipo de puntero, podemos decir que apunta al valor de "tipo" en la ubicación de memoria señalada por el valor contenido en my_int_ptr . Entonces, esencialmente está asignando el valor de la variable del puntero, no el valor de la ubicación de memoria señalada por el puntero.

Entonces, para concluir

char *x=NULL;

inicializa la variable de puntero x a NULL , no el valor en la dirección de memoria señalada por el puntero .

Esto es lo mismo que

char *x; x = NULL;

Expansión:

Ahora, siendo estrictamente conforme, una declaración como

int * my_int_ptr = 2;

es ilegal, ya que implica violación de restricciones. Para ser claro,

  • my_int_ptr es una variable de puntero, escriba int *
  • una constante entera, 2 tiene el tipo int , por definición.

y no son tipos "compatibles", por lo que esta inicialización no es válida porque viola las reglas de asignación simple, mencionadas en el capítulo §6.5.16.1 / P1, descritas en la respuesta de Lundin .

En caso de que alguien esté interesado en cómo se vincula la inicialización con las restricciones de asignación simple, cite C11 , capítulo §6.7.9, P11

El inicializador para un escalar debe ser una sola expresión, opcionalmente encerrada entre llaves. El valor inicial del objeto es el de la expresión (después de la conversión); se aplican las mismas restricciones de tipo y conversiones que para la asignación simple, tomando el tipo del escalar como la versión no calificada de su tipo declarado.


El tutorial está mal. En ISO C, int *my_int_ptr = 2; es un error En GNU C, significa lo mismo que int *my_int_ptr = (int *)2; . Esto convierte el entero 2 en una dirección de memoria, de alguna manera según lo determine el compilador.

No intenta almacenar nada en la ubicación a la que se dirige esa dirección (si corresponde). Si pasó a escribir *my_int_ptr = 5; , intentaría almacenar el número 5 en la ubicación a la que se dirige esa dirección.


Esto es correcto.

int main() { char * x = NULL; if (x==NULL) printf("is NULL/n"); return EXIT_SUCCESS; }

Esta función es correcta para lo que hace. Asigna la dirección de 0 al puntero de caracteres x. Es decir, apunta el puntero x a la dirección de memoria 0.

Alternativa:

int main() { char* x = 0; if ( !x ) printf(" x points to NULL/n"); return EXIT_SUCCESS; }

Mi suposición sobre lo que querías es:

int main() { char* x = NULL; x = alloc( sizeof( char )); *x = ''2''; if ( *x == ''2'' ) printf(" x points to an address/location that contains a ''2'' /n"); return EXIT_SUCCESS; } x is the street address of a house. *x examines the contents of that house.


Me gustaría agregar algo ortogonal a las excelentes respuestas. En realidad, inicializar a NULL está lejos de ser una mala práctica y puede ser útil si ese puntero se puede usar o no para almacenar un bloque de memoria asignado dinámicamente.

int * p = NULL; ... if (...) { p = (int*) malloc(...); ... } ... free(p);

Dado que según el estándar ISO-IEC 9899, free es un nop cuando el argumento es NULL , el código anterior (o algo más significativo en la misma línea) es legítimo.


Mucha confusión sobre los punteros en C proviene de una muy mala elección que se hizo originalmente con respecto al estilo de codificación, corroborada por una muy mala elección en la sintaxis del lenguaje.

int *x = NULL; es correcto C, pero es muy engañoso, incluso diría absurdo, y ha dificultado la comprensión del lenguaje para muchos novatos. Hace pensar que más adelante podríamos hacer *x = NULL; lo cual por supuesto es imposible. Verá, el tipo de la variable no es int , y el nombre de la variable no es *x , ni el * en la declaración desempeña ningún papel funcional en colaboración con el = . Es puramente declarativo. Entonces, lo que tiene mucho más sentido es esto:

int* x = NULL; que también es correcta C, aunque no se adhiere al estilo de codificación original de K&R. Deja perfectamente claro que el tipo es int* , y la variable de puntero es x , por lo que se hace evidente incluso para los no iniciados que el valor NULL se almacena en x , que es un puntero a int .

Además, facilita la derivación de una regla: cuando la estrella está lejos del nombre de la variable, entonces es una declaración, mientras que la estrella que se adjunta al nombre es una referencia de puntero.

Entonces, ahora se vuelve mucho más comprensible que más abajo podamos hacer x = NULL; o *x = 2; en otras palabras, hace que sea más fácil para un novato ver cómo variable = expression conduce a pointer-type variable = pointer-expression y dereferenced-pointer-variable = expression . (Para los iniciados, por ''expresión'' me refiero a ''rvalue''.)

La elección desafortunada en la sintaxis del lenguaje es que al declarar variables locales se puede decir int i, *p; que declara un entero y un puntero a un entero, por lo que uno cree que el * es una parte útil del nombre. Pero no lo es, y esta sintaxis es solo un caso especial peculiar, agregado por conveniencia, y en mi opinión, nunca debería haber existido, porque invalida la regla que propuse anteriormente. Hasta donde sé, en ninguna otra parte del lenguaje esta sintaxis es significativa, pero incluso si lo es, apunta a una discrepancia en la forma en que se definen los tipos de puntero en C. En cualquier otro lugar, en declaraciones de una sola variable, en listas de parámetros, en miembros de estructura, etc., puede declarar sus punteros como type* pointer-variable lugar de type *pointer-variable ; Es perfectamente legal y tiene más sentido.


Para aclarar por qué el tutorial está mal, int *my_int_ptr = 2; es una "violación de restricción", es un código que no está permitido compilar y el compilador debe darle un diagnóstico al encontrarlo.

Según 6.5.16.1 Asignación simple:

Restricciones

Uno de los siguientes debe contener:

  • el operando izquierdo tiene un tipo aritmético atómico, calificado o no calificado, y el derecho tiene un tipo aritmético;
  • el operando izquierdo tiene una versión atómica, calificada o no calificada de una estructura o tipo de unión compatible con el tipo de la derecha;
  • el operando izquierdo tiene un tipo de puntero atómico, calificado o no calificado, y (considerando el tipo que tendría el operando izquierdo después de la conversión de valor) ambos operandos son punteros a versiones calificadas o no calificadas de tipos compatibles, y el tipo señalado por la izquierda tiene todo los calificadores del tipo señalado por la derecha;
  • el operando izquierdo tiene un tipo de puntero atómico, calificado o no calificado, y (considerando el tipo que tendría el operando izquierdo después de la conversión del valor l) un operando es un puntero a un tipo de objeto, y el otro es un puntero a una versión calificada o no calificada de nulo, y el tipo señalado por la izquierda tiene todos los calificadores del tipo señalado por la derecha;
  • el operando izquierdo es un puntero atómico, calificado o no calificado, y el derecho es una constante de puntero nulo; o
  • el operando izquierdo tiene un tipo _Bool atómico, calificado o no calificado, y el derecho es un puntero.

En este caso, el operando izquierdo es un puntero no calificado. En ninguna parte menciona que el operando correcto puede ser un entero (tipo aritmético). Entonces el código viola el estándar C.

Se sabe que GCC se comporta mal a menos que explícitamente le digas que sea un compilador de C estándar. Si compila el código como -std=c11 -pedantic-errors , dará un diagnóstico correcto como debe hacerlo.


Solo recuerda:

En C, el valor del lado izquierdo siempre se evalúa en una ubicación de memoria , mientras que el lado derecho siempre se evalúa en un valor (ya sea int o dirección o clase Foo).


este es un puntero nulo

int * nullPtr = (void*) 0;


int *my_int_ptr = 2

almacena el valor entero 2 en cualquier dirección aleatoria que se encuentre en my_int_ptr cuando se asigna.

Esto está completamente mal. Si esto realmente está escrito, obtenga un mejor libro o tutorial.

int *my_int_ptr = 2 define un puntero entero que apunta a la dirección 2. Lo más probable es que se bloquee si intenta acceder a la dirección 2 .

*my_int_ptr = 2 , es decir, sin el int en la línea, almacena el valor dos en la dirección aleatoria a la que my_int_ptr . Dicho esto, puede asignar NULL a un puntero cuando está definido. char *x=NULL; es perfectamente válido C.

Editar: Al escribir esto, no sabía que la conversión de entero a puntero es un comportamiento definido por la implementación. Consulte las buenas respuestas de @MM y @SouravGhosh para obtener más detalles.