mezcla - estrella de oswald colorimetria capilar
¿Cómo entender la estrella puntero*en C? (10)
Declarar &a
significa que apunta a *i
. Después de todo, es un puntero a *int
. Un entero es señalar *i
. Pero si se considera j = *k
es el puntero al puntero esto, significa que &k
será el valor de k
tendrá un puntero a *int
.
Estoy luchando con el signo del puntero *, me resulta muy confuso cómo se usa tanto en declaraciones como en expresiones.
Por ejemplo:
int *i; // i is a pointer to an int
Pero, ¿cuál es la lógica detrás de la sintaxis? ¿Qué significa el * justo antes de lo que quiero decir? Tomemos el siguiente ejemplo. Por favor corrígeme donde estoy equivocado:
char **s;
char *(*s); // added parentheses to highlight precedence
Y aquí es donde pierdo la pista. El * s entre las parantheses significa: s es un puntero? ¿Pero un indicador de qué? ¿Y qué significa el * fuera del paréntesis: un puntero a lo que está apuntando?
Entonces, el significado de esto es: ¿El puntero apuntando a lo que está apuntando es un puntero a un char?
Estoy perdido ¿El signo * se interpreta de manera diferente en declaraciones y expresiones? Si es así, ¿cómo se interpreta de manera diferente? ¿Dónde estoy equivocado?
La * en declaración significa que la variable es un puntero a alguna otra variable / constante. lo que significa que puede contener la dirección de la variable del tipo. por ejemplo: char *c;
significa que c puede mantener la dirección en algunos caracteres, mientras que int *b
significa que b puede contener la dirección de algunos int, el tipo de referencia es importante, ya que en punteros aritméticos, el pointer + 1
realidad es pointer + (1 * sizeof(*pointer))
.
La expresión * in significa "el valor almacenado en la dirección", por lo que si c
es un puntero a alguna char, entonces *c
es la char específica.
char *(*s);
lo que significa que s es un puntero a un puntero a char, por lo que s no contiene la dirección de un char, sino la dirección de la variable que contiene la dirección de un char.
La regla de declaración en c es que la declaras de la manera en que la usas.
char *p
significa que necesitas *p
para obtener el char,
char **p
significa que necesitas **p
para obtener el char.
Las declaraciones en C están centradas en la expresión, lo que significa que la forma de la declaración debe coincidir con la forma de la expresión en el código ejecutable.
Por ejemplo, supongamos que tenemos un puntero a un entero llamado p
. Queremos acceder al valor entero apuntado por p
, por lo que desreferenciamos el puntero, así:
x = *p;
El tipo de la expresión *p
es int
; por lo tanto, la declaración de p
toma la forma
int *p;
En esta declaración, int
es el especificador de tipo , y *p
es el declarador . El declarador introduce el nombre del objeto que se declara ( p
), junto con información de tipo adicional no proporcionada por el especificador de tipo. En este caso, la información de tipo adicional es que p
es un tipo de puntero. La declaración se puede leer como " p
es de tipo puntero a int
" o " p
es un puntero para escribir int
". Prefiero usar la segunda forma, otros prefieren la primera.
Es un accidente de sintaxis C y C ++ que puede escribir esa declaración como int *p;
o int* p;
. En ambos casos, se analiza como int (*p);
- en otras palabras, el *
siempre está asociado con el nombre de la variable, no el especificador de tipo.
Ahora supongamos que tenemos una serie de punteros a int
, y queremos acceder al valor apuntado por el elemento i-ésimo de la matriz. Subcribimos en la matriz y desreferenciamos el resultado, así:
x = *ap[i]; // parsed as *(ap[i]), since subscript has higher precedence
// than dereference.
De nuevo, el tipo de la expresión *ap[i]
es int
, por lo que la declaración de ap
es
int *ap[N];
donde el declarador *ap[N]
significa que ap
es una matriz de punteros a int
.
Y para aclarar el punto, ahora supongamos que tenemos un puntero a un puntero a int
y queremos acceder a ese valor. Nuevamente, deferenciamos el puntero, luego desreferenciamos ese resultado para obtener el valor entero:
x = **pp; // *pp deferences pp, then **pp dereferences the result of *pp
Dado que el tipo de la expresión **pp
es int
, la declaración es
int **pp;
El declarador **pp
indica que pp
es un puntero a otro puntero a un int
.
La doble indirección aparece mucho, generalmente cuando quiere modificar el valor de un puntero que está pasando a una función, como:
void openAndInit(FILE **p)
{
*p = fopen("AFile.txt", "r");
// do other stuff
}
int main(void)
{
FILE *f = NULL;
...
openAndInit(&f);
...
}
En este caso, queremos que la función actualice el valor de f
; para hacer eso, debemos pasar un puntero a f
. Como f
ya es un tipo de puntero ( FILE *
), eso significa que estamos pasando un puntero a un FILE *
, de ahí la declaración de p
como FILE **p
. Recuerde que la expresión *p
en openAndInit
refiere al mismo objeto que la expresión f
en main
.
Tanto en declaraciones como en expresiones, tanto []
como ()
tienen una precedencia mayor que unario *
. Por ejemplo, *ap[i]
se interpreta como *(ap[i])
; la expresión ap[i]
es un tipo de puntero y la *
desreferencia que apunta. Por lo tanto, ap
es una matriz de punteros . Si desea declarar un puntero a una matriz , debe agrupar explícitamente el *
con el nombre de la matriz, así:
int (*pa)[N]; // pa is a pointer to an N-element array of int
y cuando desee acceder a un valor en la matriz, debe respetar pa
antes de aplicar el subíndice:
x = (*pa)[i];
Del mismo modo con las funciones:
int *f(); // f is a function that returns a pointer to int
...
x = *f(); // we must dereference the result of f() to get the int value
int (*f)(); // f is a pointer to a function that returns an int
...
x = (*f)(); // we must dereference f and execute the result to get the int value
Mi método favorito para analizar declaraciones complicadas es la regla de la espiral en el sentido de las agujas del reloj .
Básicamente, comienzas desde el identificador y sigues una espiral en el sentido de las agujas del reloj. Vea el enlace para saber exactamente cómo se usa.
Dos cosas que el artículo no menciona:
1- Debe separar el especificador de tipo (int, char, etc.) del declarador, analizar el declarador y luego agregar el especificador de tipo.
2- Si encuentras corchetes que denotan una matriz, asegúrate de leer también los siguientes corchetes (si hay alguno).
Tómelo de esta manera:
int *i
significa que el valor al que señala i es un número entero.
char **p
significa que p es un puntero que a su vez es un puntero a un char.
Usted tiene la respuesta en sus preguntas.
De hecho, se usa una estrella doble para indicar el puntero al puntero.
aquí hay un poco de información
variable pointer
declaring &a p
reading/ a *p
processing
int * i
significa que es un puntero a int (leer hacia atrás, leer * como puntero). char **p
y char *(*p)
ambos significan un puntero a un puntero a char.
Aquí hay algunos otros ejemplos
int* a[3]
// a es una matriz de 3 punteros a int
int (*a)[3]
// a es un puntero a una matriz de 3 entradas
int i; //i is an int.
int *i; //i is a pointer to an int
int **i;//i is a pointer to a pointer to an int.
¿El signo * se interpreta de manera diferente en declaraciones y expresiones?
Sí. Ellos son completamente diferentes. en una declaración * se usa para declarar punteros. En una expresión unario * se usa para desreferenciar un puntero (o como el operador de multiplicación binario)
Algunos ejemplos:
int i = 10; //i is an int, it has allocated storage to store an int.
int *k; // k is an uninitialized pointer to an int.
//It does not store an int, but a pointer to one.
k = &i; // make k point to i. We take the address of i and store it in k
int j = *k; //here we dereference the k pointer to get at the int value it points
//to. As it points to i, *k will get the value 10 and store it in j