Uso del operador de flecha (->) en C

7 minutos de lectura

avatar de usuario
mohit deshpande

Estoy leyendo un libro llamado “Teach Yourself C in 21 Days” (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 -> (flecha) operador surgió sin explicación. Creo que se usa para llamar a miembros y funciones (como el equivalente del . (punto), pero para punteros en lugar de miembros). Pero no estoy del todo seguro.

¿Podría obtener una explicación y un ejemplo de código?

  • Consigue un libro mejor. norvig.com/21-days.html

    – josephperry

    4 de abril de 2010 a las 16:35

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

    – J.Taylor

    29 de abril de 2011 a las 23:29

  • @Steve Esa pregunta trata sobre C++. Llamarlo me causó cierta confusión cuando comencé a leer sobre la sobrecarga del operador en esa otra respuesta, que no es relevante en C.

    – Juan

    13 mayo 2013 a las 19:42


  • @Belton La serie de la manera difícil es mala, el tipo dice cosas que ni siquiera eran relevantes cuando escribió el libro y no le importan las buenas prácticas.

    – Balint

    25 de junio de 2017 a las 19:51

  • ¡Él no dijo que era un gran libro! Es solo el libro que estaba leyendo por alguna razón. Tal vez está aprendiendo mucho de él, y planea leer uno mejor cuando haya terminado. Comentarios como estos son molestos

    – uh_big_mike_boi

    28 de junio de 2019 a las 14:14

foo->bar es equivalente a (*foo).bares decir, llama al miembro bar de la estructura que foo puntos a.

  • Vale la pena señalar que si el operador de desreferencia se hubiera hecho posfijo, como en Pascal, el -> operador no habría sido necesario en absoluto, ya que habría sido equivalente al mucho más legible foo*.bar. Todo el lío de las funciones typedef-ing con todos los paréntesis adicionales también se habría evitado.

    – usuario207421

    26 de enero de 2015 a las 6:04


  • Así sería foo*.bar y (*foo).bar ambos ser equivalentes a foo->bar? Qué pasa Foo myFoo = *foo; myFoo.bar?

    – Aarón Franke

    9 de enero de 2019 a las 8:21

  • no, solo dice SI los creadores de C habrían hecho el operador de desreferencia como operador POSTfix en lugar de PREfix, entonces habría sido más fácil. Pero ES un operador de prefijo en C.

    – reichhart

    16 de marzo de 2019 a las 9:59


  • @ user207421 ¿Podría dar una breve descripción o un enlace a las “funciones de definición de tipos con todos los paréntesis adicionales” que menciona? Gracias.

    – RoG

    27 de mayo de 2019 a las 6:24

  • @user207421 nah, causaría más padres… hasta ahora, hay prioridad de () y [] a la derecha arriba * a la izquierda. si están todos de un lado, habrás puesto a más padres. Lo mismo en expresiones, debido al conflicto con el operador de multiplicación. Pascal ^ podía ser una opción pero se reservaba para la operación de bits, aún más padres.

    – Swift – Pastel de viernes

    22 de octubre de 2019 a las 6:32


avatar de usuario
71GA

Bueno, tengo que añadir algo también. La estructura es un poco diferente a la matriz porque la matriz es un puntero y la estructura no lo es. ¡Así que ten cuidado!

Digamos que escribo este código inútil:

#include <stdio.h>

typedef struct{
        int km;
        int kph;
        int kg;
    } car;

int main(void){

    car audi = {12000, 230, 760};
    car *ptr = &audi;

}

Aquí puntero ptr apunta a la dirección (!) de la variable de estructura audi pero al lado de la estructura de dirección también tiene un trozo de datos (!)! El primer miembro de la trozo de datos tiene la misma dirección que la estructura en sí misma y puede obtener sus datos solo desreferenciando un puntero como este *ptr (sin llaves).

Pero si desea acceder a cualquier otro miembro que no sea el primero, debe agregar un designador como .km, .kph, .kg que no son más que compensaciones a la dirección base del trozo de datos

Pero debido a la precedencia no puedes escribir *ptr.kg como operador de acceso . se evalúa antes del operador de desreferencia * y obtendrías *(ptr.kg) ¡lo cual no es posible ya que el puntero no tiene miembros! Y el compilador lo sabe y, por lo tanto, emitirá un error, por ejemplo:

error: ‘ptr’ is a pointer; did you mean to use ‘->’?
  printf("%d\n", *ptr.km);

En su lugar usas esto (*ptr).kg y obligas al compilador a desreferenciar el puntero y permitir el acceso a la trozo de datos y 2do agrega un desplazamiento (designador) para elegir el miembro.

Mira esta imagen que hice:

ingrese la descripción de la imagen aquí

Pero si tuviera miembros anidados, esta sintaxis se volvería ilegible y, por lo tanto, -> Fue presentado. Creo que la legibilidad es la única razón justificable para usarlo así ptr->kg es mucho más fácil de escribir que (*ptr).kg.

Ahora permítanos escribir esto de manera diferente para que vea la conexión más claramente. (*ptr).kg(*&audi).kgaudi.kg. Aquí usé por primera vez el hecho de que ptr es un “Dirección de audi es decir &audi y hecho de que “referencia” & y “desreferencia” * los operadores se cancelan entre sí.

  • Tu respuesta es genial!.

    – Marca

    28 de febrero a las 18:59

avatar de usuario
Jacobo

Si eso es.

Es solo la versión de punto cuando desea acceder a 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;
pvar = malloc(sizeof(struct foo));

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

¡Eso es todo!

  • Dado que pvar no está inicializado, ¿cómo lo inicializaría si quisiera que pvar apuntara a una nueva estructura? pvar = &var?

    – CMC Dragonkai

    26 de septiembre de 2015 a las 14:27

  • La pregunta era específicamente sobre C, que no tiene clases ni variables de referencia.

    usuario2442944

    19 dic 2016 a las 19:34

  • hmm, ¿no deberías hacer un malloc antes de escribir en pvar struct foo* pvar; ?? pvar->y escribir en espacio no asignado!

    – Zibrí

    21 de marzo de 2018 a las 8:46

  • Inicialización de pvar: inicialice todos los miembros manualmente a algunos valores predeterminados que desee tener o use algo como calloc() si el relleno cero estaría bien para usted.

    – reichhart

    16 de marzo de 2019 a las 10:03

  • ¿No debería ser: pvar = malloc(sizeof(struct foo)) o malloc(sizeof(*pvar))??

    – Yuri Aps

    14 de julio de 2019 a las 2:01

Solo agregaría a las respuestas el “¿por qué?”.

. es un operador de acceso a miembros estándar que tiene una precedencia más alta que * operador puntero

Cuando intenta acceder a las partes internas de una estructura y lo escribió como *foo.bar entonces el compilador pensaría en querer un elemento ‘bar’ de ‘foo’ (que es una dirección en la memoria) y obviamente esa mera dirección no tiene ningún miembro.

Por lo tanto, debe pedirle al compilador que primero elimine la referencia con (*foo) y luego acceda al elemento miembro: (*foo).barque es un poco torpe de escribir, por lo que la buena gente ha creado una versión abreviada: foo->bar que es una especie de acceso a miembros por operador de puntero.

avatar de usuario
Jayghosh Wankar

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

Aquí el para acceder a los valores de i y j podemos usar la variable a y el puntero p como sigue: a.i, (*p).i y p->i son todos iguales.

Aquí . es un “selector directo” y -> es un “selector indirecto”.

avatar de usuario
Pedro Alejandro

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

avatar de usuario
Matti Virkkunen

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

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad