2010-04-04 25 views
164

Actualmente estoy aprendiendo C leyendo un buen libro para principiantes titulado "Enséñate a ti mismo en 21 días" (ya aprendí Java y C#, así que me muevo a un ritmo mucho más rápido) . Estaba leyendo el capítulo sobre punteros y el operador -> (flecha) apareció sin explicación. Creo que se usa para llamar a miembros y funciones (como el equivalente del operador. (Punto), pero para punteros en lugar de miembros). Pero no estoy del todo seguro. ¿Podría obtener una explicación y una muestra de código?Operador de flecha (->) en C

+32

Solo una nota al margen - libros titulados como "enséñate a ti mismo XXX en XXX días/semanas/horas" generalmente no son buenos. Obtenga una copia de K & R. – qrdl

+8

qrdl es correcto: los libros "Aprender X en días Y" generalmente son basura. Además de K & R, también recomendaría el "C Primer Plus" de Prata, que va más allá de K & R. –

+56

Consigue un mejor libro. http://norvig.com/21-days.html – joshperry

Respuesta

307

foo->bar es equivalente a (*foo).bar, es decir, se pone el miembro de llama bar de la struct que foo puntos a.

+26

Vale la pena señalar que si el operador de desreferencia se hubiera hecho postfix, como en Pascal, el operador '->' no se habría necesitado en absoluto, ya que habría sido equivalente a la 'foo * .bar' mucho más legible. También se habría evitado todo el desorden de las funciones de definición de tipos con todos los paréntesis adicionales. – EJP

+0

@kritzikratzi No hay sobrecarga del operador en C. – sepp2k

+0

@kritzikratzi ¡Podría eliminar ese comentario ahora! – Tim

90

Sí, eso es todo.

Es solo la versión de punto cuando desea acceder a los elementos de una estructura/clase que es un puntero en lugar de una referencia.

struct foo 
{ 
    int x; 
    float y; 
}; 

struct foo var; 
struct foo* pvar; 

var.x = 5; 
(&var)->y = 14.3; 
pvar->y = 22.4; 
(*pvar).x = 6; 

Eso es todo!

+16

Solo para señalarlo (sin juego de palabras), olvidaste el; en el corchete final de la estructura, debería ser}; –

+2

increíble, lo estaba editando mientras escribías el comentario ... precog! – Jack

+1

Como pvar no está inicializado, ¿cómo lo inicializaría si quisiera que pvar apunte a una nueva estructura, que no es 'pvar = & var'? – CMCDragonkai

24

a->b es sólo la abreviatura de (*a).b en todos los sentidos (lo mismo para las funciones: a->b() es la abreviatura de (*a).b()).

+0

¿hay documentación que indique que también funciona de esa manera para los métodos? – AsheKetchum

13

foo->bar es solo la abreviatura de (*foo).bar. Eso es todo al respecto.

1

Dot es un operador de referencia y se utiliza para conectar la variable de estructura para un registro particular de estructura. Ej:

struct student 
    { 
     int s.no; 
     Char name []; 
     int age; 
    } s1,s2; 

main() 
    { 
     s1.name; 
     s2.name; 
    } 

De tal manera que se puede utilizar un operador de punto para acceder a la estructura variable de

+5

¿Qué valor agrega esto? El ejemplo es un poco pobre en comparación con las otras respuestas que realmente lo comparan contra '->'. También esta pregunta ha sido respondida por 4.5 años ya. – EWit

1

tuviera que hacer un pequeño cambio en el programa de Jack para conseguir que se ejecute. Después de declarar el puntero struct pvar, señálelo a la dirección de var. He encontrado esta solución en la página 242 de la Programación de Stephen Kochan en C.

#include <stdio.h> 

int main() 
{ 
    struct foo 
    { 
    int x; 
    float y; 
    }; 

    struct foo var; 
    struct foo* pvar; 
    pvar = &var; 

    var.x = 5; 
    (&var)->y = 14.3; 
    printf("%i - %.02f\n", var.x, (&var)->y); 
    pvar->x = 6; 
    pvar->y = 22.4; 
    printf("%i - %.02f\n", pvar->x, pvar->y); 
    return 0; 
} 

Ejecutar este en vim con el siguiente comando:

:!gcc -o var var.c && ./var 

seria:

5 - 14.30 
6 - 22.40 
+2

punta de vim: use '%' para representar el nombre de archivo actual. Como tal: '! Gcc% &&./A.out' – jibberia

1
#include<stdio.h> 

int main() 
{ 
    struct foo 
    { 
     int x; 
     float y; 
    } var1; 
    struct foo var; 
    struct foo* pvar; 

    pvar = &var1; 
    /* if pvar = &var; it directly 
     takes values stored in var, and if give 
     new > values like pvar->x = 6; pvar->y = 22.4; 
     it modifies the values of var 
     object..so better to give new reference. */ 
    var.x = 5; 
    (&var)->y = 14.3; 
    printf("%i - %.02f\n", var.x, (&var)->y); 

    pvar->x = 6; 
    pvar->y = 22.4; 
    printf("%i - %.02f\n", pvar->x, pvar->y); 

    return 0; 
} 
1

El operador -> hace que el código sea más legible que el operador * en algunas situaciones.

Tales como: (citado de la EDK II project)

typedef 
EFI_STATUS 
(EFIAPI *EFI_BLOCK_READ)(
    IN EFI_BLOCK_IO_PROTOCOL   *This, 
    IN UINT32       MediaId, 
    IN EFI_LBA      Lba, 
    IN UINTN       BufferSize, 
    OUT VOID       *Buffer 
); 


struct _EFI_BLOCK_IO_PROTOCOL { 
    /// 
    /// The revision to which the block IO interface adheres. All future 
    /// revisions must be backwards compatible. If a future version is not 
    /// back wards compatible, it is not the same GUID. 
    /// 
    UINT64    Revision; 
    /// 
    /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device. 
    /// 
    EFI_BLOCK_IO_MEDIA *Media; 

    EFI_BLOCK_RESET  Reset; 
    EFI_BLOCK_READ  ReadBlocks; 
    EFI_BLOCK_WRITE  WriteBlocks; 
    EFI_BLOCK_FLUSH  FlushBlocks; 

}; 

El struct _EFI_BLOCK_IO_PROTOCOL contiene 4 miembros puntero de función.

Supongamos que tiene una variable struct _EFI_BLOCK_IO_PROTOCOL * pStruct, y desea utilizar el antiguo operador * para llamarlo puntero de función miembro.Usted va a terminar con un código como éste:

(*pStruct).ReadBlocks(...arguments...)

Pero con el operador ->, se puede escribir así:

pStruct->ReadBlocks(...arguments...).

¿Qué se ve mejor?

4
struct Node { 
    int i; 
    int j; 
}; 
struct Node a, *p = &a; 

Aquí el acceso a los valores de ij y podemos utilizar la variable a y el puntero p de la siguiente manera: a.i, (*p).i y p->i son todos iguales.

Aquí . es un "selector directo" y -> es un "selector indirecto".

0

Simplemente agregaría a las respuestas el "¿por qué?".

. es un operador de acceso de miembro estándar que tiene una precedencia mayor que * operador de puntero. Cuando intenta acceder a las partes internas de una estructura y lo escribió como *foo.bar, entonces el compilador pensaría querer un elemento 'bar' de 'foo' (que es una dirección en la memoria) y obviamente esa mera dirección no lo hace tener algún miembro

lo tanto es necesario pedir al compilador que primero eliminar la referencia de un poco con (*foo) y luego acceder al elemento de miembro: (*foo).bar, que es un poco torpe para escribir lo que las buenas personas han llegado con una versión abreviada: foo->bar que es una especie de miembro acceso por operador de puntero.

Cuestiones relacionadas