1
#include <stdio.h>

struct nodo
{
    int dato;
    struct nodo *siguiente;
};

typedef struct nodo NODO;
typedef NODO *NODOSIG;

void f1(NODOSIG *lista);
void f2(NODOSIG **lista, NODOSIG *nuevo);

int main()
{
    NODOSIG LISTA = NULL;

    f1(&LISTA);

    return 0;
}

void f1(NODOSIG *lista)
{
    NODOSIG NUEVO;
    int x;
    NUEVO = malloc(sizeof(NODO));

    if(NUEVO != NULL){
        printf("\n\tIngrese un numero: ");
        scanf("%d", &x);
        NUEVO->dato = x;
        NUEVO->siguiente = NULL;

        f2(&lista, &NUEVO);
    }
}

void f2(NODOSIG **lista, NODOSIG *nuevo)
{
    lista->siguiente = *lista;
    *lista = nuevo;
}

Buenas, tengo este pedazo de código en el cual busco en la función 1 crear un nodo y en la función 2 (anidada a 1) encadenarlo por el principio, sé que se puede hacer todo en una función pero quiero hacerlo así porque dependiendo de el dato es sí, se va a encadenar al principio o al final (existencia de una función 3), el problema es que como en el título dice marca error en la siguiente linea de la función 2:

nuevo->siguiente = *lista;
ordago
  • 4,509
  • 12
  • 26
THE_F4ST
  • 53
  • 4
  • El problema es la redefinición de tipos que luego te hace confundirte. Si `NODOSIG` ya es un puntero a un `NODO`, en el prototipo de `f2` tienes `NODOSIG ** lista`, lo que termina siendo `NODO *** lista`. Realmente confuso. De ahí que no te deje hacer `lista->siguiente = nuevo`, porque lista no es un puntero a `NODO`, sino un puntero a un puntero a un puntero a `NODO`. Casi nada!!!! Todo esto, obviando el final de tu pregunta, que haces referencia a algo que no está en el código. Entiendo que el error de compilación te da donde te he dicho. – SuperG280 Feb 18 '20 at 08:09
  • Perdón, tenía un error en el código, ya lo corregí, ahora si aparece esa linea de error. – THE_F4ST Feb 18 '20 at 15:04

1 Answers1

2

Tu código es propenso a errores por el uso desaconsejado de alias de tipos. El primer alias:

typedef struct nodo NODO;

Hace que el tipo struct nodo reciba el alias de NODO. El segundo alias:

typedef NODO *NODOSIG;

Hace que el tipo NODO * (que es struct nodo *, puntero a la estructura nodo) reciba el alias de NODOSIG. Este tipo de nomenclatura se considera mala práctica porque ocultas un puntero (*) en un nombre de tipo que no incorpora el puntero. Por eso, en el cuerpo de f2:

void f2(NODOSIG **lista, NODOSIG *nuevo)
{
    lista->siguiente = *lista;
    *lista = nuevo;
}

Cuando recibes un puntero a puntero a NODOSIG, dado que NODOSIG es NODO * que a su vez es struct nodo * entonces estás recibiendo un puntero a un puntero a un puntero a la estructura nodo, por lo tanto la función f2 anterior y la siguiente son exactamente la misma:

void f2(struct nodo ***lista, struct nodo **nuevo)
//                  ^^^                   ^^
//                    \                     \__ puntero a puntero a estructura nodo
//                     \
//                      \__ puntero a puntero a puntero a estructura nodo
{
    lista->siguiente = *lista;
    *lista = nuevo;
}

Dado que el operador flecha (->) es un azúcar sintáctico para (*objeto).miembro, al escribir lista->siguiente estamos ejecutando la siguiente orden:

(*lista).siguiente = *lista;

Dado que lista es un puntero a puntero a puntero a estructura nodo entonces *lista es un puntero a puntero a estructura nodo y como tal, carece de miembros ya que sigue estando a dos indirecciones de tenerlos:

                                                  NODOSIG **
                                                    /
                                   NODOSIG * <-----/
                                     /  
     NODO             NODOSIG <-----/
+-------------+         /
| struct nodo | <------/
+-------------+
|    dato     |
|  siguiente  |
+-------------+

Mi consejo es que dejes de usar alias de tipos… y si los usas, no lo hagas ocultando punteros.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82
  • ya logré que funcionara pero no utilicé lo que me comentaste, redefiní mi f2 de la siguiente forma `void f2(NODOSIG **lista, NODOSIG nuevo) `y utilicé como dices un doble operador de indirección a lista, y ya funciona todo bien, solo me falta entender el por que funciona ; . ; – THE_F4ST Feb 18 '20 at 16:11
  • 1
    Me alegro que encontrases solución, pero mi consejo sigue siendo que dejes de usar alias de tipos… y si los usas, no lo hagas ocultando punteros ya que se considera mala práctica porque ocultas un puntero (`*`) en un nombre de tipo que no incorpora el puntero, fomentando que aparezcan errores como el que has tenido. – PaperBirdMaster Feb 18 '20 at 16:13