2

Llevo unos días con el mismo error en vscode y no doy encontrado el error, uso C. Utilizando las funciones de un TAD lista en una función fuera del main, me salta siempre el mismo error de "referencia a 'función' sin definir".

Starting build...
/usr/bin/gcc-11 -fdiagnostics-color=always -g /home/nico/Escritorio/Programas/GUI/main.c -o /home/nico/Escritorio/Programas/GUI/main
/usr/bin/ld: /tmp/cc7zWXgL.o: en la función `añadirCuenta':
/home/nico/Escritorio/Programas/GUI/main.c:28: referencia a `primeroLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:31: referencia a `recuperarElementoLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:38: referencia a `siguienteLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:30: referencia a `finLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:42: referencia a `primeroLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:45: referencia a `recuperarElementoLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:52: referencia a `siguienteLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:44: referencia a `finLista' sin definir
/usr/bin/ld: /home/nico/Escritorio/Programas/GUI/main.c:56: referencia a `insertarElementoLista' sin definir
/usr/bin/ld: /tmp/cc7zWXgL.o: en la función `main':
/home/nico/Escritorio/Programas/GUI/main.c:146: referencia a `crearLista' sin definir
collect2: error: ld returned 1 exit status

Build finished with error(s).

He cambiado varias veces el archivo tasks.json que genera el propio vscode donde pone inicialmente: "${file}" por "${workspaceFolder}/*.c" y, viendo que no funcionaba lo cambié y puse todos los archivos .c; de la forma: "main.c", "lista.c", "cola.c", "estructura.c".


{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: gcc build active file",
            "command": "/usr/bin/gcc",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "main.c", "lista.c", "cola.c", "estructura.c",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "Task generated by Debugger."
        },
        {
            "type": "cppbuild",
            "label": "C/C++: gcc-11 build active file",
            "command": "/usr/bin/gcc-11",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": "build",
            "detail": "Task generated by Debugger."
        }
    ],
    "version": "2.0.0"
}

La función donde me salta el error es la siguiente:

int añadirCuenta(TLISTA *listacontra, TIPOELEMENTOLISTA cuenta){
    TPOSICION pos;
    TIPOELEMENTOLISTA e;

    pos = primeroLista(*listacontra);

    while((pos != finLista(*listacontra))){
        recuperarElementoLista(*listacontra, pos, &e);
        if(cuenta.contraseña == e.contraseña){
            while(cuenta.contraseña == e.contraseña){
                printf("Contraseña ya usada, escriba otra: \n");
                scanf(" %d", &cuenta.contraseña);
            }
        }else{
            siguienteLista(*listacontra, pos);
        }
    }

    pos = primeroLista(*listacontra);

    while((pos != finLista(*listacontra))){
        recuperarElementoLista(*listacontra, pos, &e);
        if(cuenta.nombre == e.nombre){
            while(cuenta.nombre == e.nombre){
                printf("Nombre ya usado, escriba otro: \n");
                scanf(" %s", cuenta.nombre);
            }
        }else{
            siguienteLista(*listacontra, pos);
        }
    }

    insertarElementoLista(listacontra, pos, cuenta);
}

TIPOELEMENTOLISTA es así:

typedef CUENTA TIPOELEMENTOLISTA;

CUENTA es así:

#ifndef IMPRESORA_H
#define IMPRESORA_H

/**
*
*@param nombre nombre de la cuenta
*@param contraseña contraseña de la cuenta
*/
typedef struct{
char nombre[20];
int contraseña;
} CUENTA;

#endif

La llamo desde el main así:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "lista.h"
#include "cola.h"
#include "estructura.h"


int main(int argc, char** argv[]){ //sin acabar
    char opcion;
    int contraseñacuenta, contraseñacuenta2;
    TLISTA listacontra = NULL;
    TIPOELEMENTOLISTA cuenta;
    
    crearLista(&listacontra);


    do{
        printf("\n---------------\n");
        printf("a) Iniciar sesión\n");
        printf("b) Registrarse\n");
        printf("c) Ayuda\n");
        printf("s) Salir\n");
        printf("\n---------------\n");
        
        scanf(" %c", &opcion);
    
        if(opcion == 'a'){
            printf("Escriba su nombre de usuario: \n");
            scanf(" %s", cuenta.nombre);
            printf("Escriba su contraseña: \n");
            scanf(" %d", &cuenta.contraseña);
            
            abrirCuenta(cuenta.nombre, cuenta.contraseña);

        }else if(opcion == 'b'){
            printf("Escriba su nombre de cuenta: \n");
            scanf(" %s", cuenta.nombre);
            while(contraseñacuenta != contraseñacuenta2){
                printf("Escriba su contraseña: \n");
                scanf(" %d", &contraseñacuenta);
                printf("Vuelva a escribir su contraseña: \n");
                scanf(" %d", &contraseñacuenta2);
                
                if(contraseñacuenta != contraseñacuenta2){
                    printf("Error, las contraseñas no coinciden\n");
                }else{
                    cuenta.contraseña = contraseñacuenta;
                }
            }

            añadirCuenta(&listacontra, cuenta); //la función es esta


        }else if(opcion == 'c'){
            printf("OPCIÓNC");
        }
    }while(opcion != 's');

    destruirLista(&listacontra);
}

Así es el archivo lista.c:

#include <stdio.h>
#include <stdlib.h>
#include "estructura.h"

/** Definicion del tipo de elemento almacenado en la lista **/

typedef CUENTA TIPOELEMENTOLISTA;
///////////////////////////////////////////////////

/** Estructura para un nodo de la lista **/
typedef struct nodoLista {
TIPOELEMENTOLISTA elemento;
struct nodoLista *sig;
} STNODOLISTA;
typedef STNODOLISTA *TPOSICION;

/** Estructura para la lista **/
typedef struct {
TPOSICION inicio;
int longitud;
TPOSICION fin;
} STLISTA;
typedef STLISTA *TLISTA;

/**
* Reserva memoria para una lista de datos con el tipo [TIPOELEMENTOLISTA].
*
* @param q puntero a la lista a crear.
*/
void crearLista(TLISTA *l) {
*l = (TLISTA) malloc(sizeof(STLISTA));
(*l)->inicio = (TPOSICION) malloc(sizeof(STNODOLISTA));
(*l)->inicio->sig = NULL;
(*l)->fin = (*l)->inicio;
(*l)->longitud = 0;
}

/**
* Destruye (libera la memoria reservada) la lista [l] y todos los elementos que almacena.
*
* @param l puntero a la lista a destruir.
*/
void destruirLista(TLISTA *l) {
(*l)->fin = (*l)->inicio;
while ((*l)->fin != NULL) {
(*l)->fin = (*l)->fin->sig;
free((*l)->inicio);
(*l)->inicio = (*l)->fin;
}
free(*l);
}

/**
* Comprueba si la lista [l] esta vacia.
*
* @param l lista a comprobar si esta vacia.
* @return 1 si la lista esta vacia, 0 en otro caso.
*/
int esListaVacia(TLISTA l) {
return (l->longitud == 0);
}

/**
* Recupera la primera posicion de la lista.
*
* @param l lista de la cual recuperar la primera posicion.
* @return la primera posicion tipo [TPOSICION] de la lista [l].
*/
TPOSICION primeroLista(TLISTA l) {
return l->inicio;
}

/**
* Recupera la posicion del fin de la lista.
*
* @param l lista de la cual recuperar su final.
* @return la posicion del fin tipo [TPOSICION] de la lista [l].
*/
TPOSICION finLista(TLISTA l) {
return l->fin;
}

/**
* Devuelve la posicion siguiente a [p] en la lista [l].
*
* @param l lista en la cual se va a buscar la siguiente posicion.
* @param p posicion referencia para devolver la siguiente.
* @return la posicion siguiente a [p].
*/
TPOSICION siguienteLista(TLISTA l, TPOSICION p) {
return p->sig;
}

/**
* Recupera el elemento almacenado en la posicion [p] pasada por argumento.
*
* @param l lista de la cual recuperar el elemento.
* @param p posicion de la cual recuperar el elemento.
* @param e puntero a la variable en la cual almacenar el elemento recuperado.
*/
void recuperarElementoLista(TLISTA l, TPOSICION p, TIPOELEMENTOLISTA *e){
*e = p->sig->elemento;
}

/**
* Consulta la longitud de la lista [l].
*
* @param l lista de la cual consultar la longitud.
* @return entero con el valor de la longitud de la lista.
*/
int longitudLista(TLISTA l) {
return l->longitud;
}

/**
* Inserta el elemento [e] en la posicion siguiente a la posicion [p] de la lista [l].
*
* @param l puntero a la lista en la cual se va a insertar el elemento.
* @param p posicion despues de la cual se insertara el elemento.
* @param e elemento a insertar.
*/
void insertarElementoLista(TLISTA *l, TPOSICION p, TIPOELEMENTOLISTA e){
TPOSICION q = p->sig;
p->sig = (STNODOLISTA *) malloc(sizeof(STNODOLISTA));
p->sig->elemento = e;
p->sig->sig = q;
if (q == NULL) {
(*l)->fin = p->sig;
}
(*l)->longitud++;
}

/**
* Suprime el elemento en posicion [p] de la lista [l].
*
* @param l puntero a la lista de la que se suprimira el elemento.
* @param p posicion del elemento a suprimir.
*/
void suprimirElementoLista(TLISTA *l, TPOSICION p){
TPOSICION q;

q = p->sig;
p->sig = q->sig;
if (p->sig == NULL) {
(*l)->fin = p;
}
free(q);
(*l)->longitud--;
}

/**
* Modifica el valor del elemento almacenado en la posicion [p] guardando el nuevo elemento [e].
*
* @param l puntero a la lista de la cual se va a modificar el elemento.
* @param p posicion del valor que se va a modificar.
* @param e nuevo valor a guardar en la posicion [p].
*/
void modificarElementoLista(TLISTA *l, TPOSICION p, TIPOELEMENTOLISTA e){
p->sig->elemento = e;
}


Y así es el archivo cabecera lista.h:

#ifndef LISTA_H
#define LISTA_H
#include "estructura.h"

/** Definicion del tipo de elemento almacenado en la lista **/
typedef CUENTA TIPOELEMENTOLISTA;

///////////////////////////////////////////////////

/** Estructura para una posicion de la lista **/
typedef void *TPOSICION;
/** Estructura para la lista **/
typedef void *TLISTA;

/**
* Reserva memoria para una lista de datos con el tipo [TIPOELEMENTOLISTA].
*
* @param q puntero a la lista a crear.
*/
void crearLista(TLISTA *l);

/**
* Destruye (libera la memoria reservada) la lista [l] y todos los elementos que almacena.
*
* @param l puntero a la lista a destruir.
*/
void destruirLista(TLISTA *l);

/**
* Comprueba si la lista [l] esta vacia.
*
* @param l lista a comprobar si esta vacia.
* @return 1 si la lista esta vacia, 0 en otro caso.
*/
int esListaVacia(TLISTA l);

/**
* Recupera la primera posicion de la lista.
*
* @param l lista de la cual recuperar la primera posicion.
* @return la primera posicion tipo [TPOSICION] de la lista [l].
*/
TPOSICION primeroLista(TLISTA l);

/**
* Recupera la posicion del fin de la lista.
*
* @param l lista de la cual recuperar su final.
* @return la posicion del fin tipo [TPOSICION] de la lista [l].
*/
TPOSICION finLista(TLISTA l);

/**
* Devuelve la posicion siguiente a [p] en la lista [l].
*
* @param l lista en la cual se va a buscar la siguiente posicion.
* @param p posicion referencia para devolver la siguiente.
* @return la posicion siguiente a [p].
*/
TPOSICION siguienteLista(TLISTA l, TPOSICION p);

/**
* Recupera el elemento almacenado en la posicion [p] pasada por argumento.
*
* @param l lista de la cual recuperar el elemento.
* @param p posicion de la cual recuperar el elemento.
* @param e puntero a la variable en la cual almacenar el elemento recuperado.
*/
void recuperarElementoLista(TLISTA l, TPOSICION p, TIPOELEMENTOLISTA *e);

/**
* Consulta la longitud de la lista [l].
*
* @param l lista de la cual consultar la longitud.
* @return entero con el valor de la longitud de la lista.
*/
int longitudLista(TLISTA l);

/**
* Inserta el elemento [e] en la posicion siguiente a la posicion [p] de la lista [l].
*
* @param l puntero a la lista en la cual se va a insertar el elemento.
* @param p posicion despues de la cual se insertara el elemento.
* @param e elemento a insertar.
*/
void insertarElementoLista(TLISTA *l, TPOSICION p, TIPOELEMENTOLISTA e);

/**
* Suprime el elemento en posicion [p] de la lista [l].
*
* @param l puntero a la lista de la que se suprimira el elemento.
* @param p posicion del elemento a suprimir.
*/
void suprimirElementoLista(TLISTA *l, TPOSICION p);

/**
* Modifica el valor del elemento almacenado en la posicion [p] guardando el nuevo elemento [e].
*
* @param l puntero a la lista de la cual se va a modificar el elemento.
* @param p posicion del valor que se va a modificar.
* @param e nuevo valor a guardar en la posicion [p].
*/
void modificarElementoLista(TLISTA *l, TPOSICION p, TIPOELEMENTOLISTA e);

#endif // LISTA_H

No sé que más hacer o donde más buscar, cualquier ayuda es bienvenida. Si hace falta conocer alguna función más o falta alguna parte del código avisar sin problema.

8
  • Detalle menor: ¿Visual Studio o Visual Studio Code? Por cierto, lee Cómo preguntar y haz el recorrido de bienvenida para conocer el funcionamiento del sitio.
    – padaleiana
    Commented el 14 jun. a las 17:39
  • No se si realmente lo haces o no en tu código completo pero ten en cuenta que es necesario que una declaración de la función sea visible para el compilador antes de que se intente llamarla. ¿Estás definiendolas (que no implmentandolas) en los módulos que las usan? Lo normal sería usar archivos de cabecera pero puedes prescindir de ellos, siempre y cuando cumplas con lo dicho.
    – FJSevilla
    Commented el 14 jun. a las 18:42
  • No es recomendable usar caracteres no ASCII para los identificadores. Sería más útil que compartas el contenido de los archivos main.c y lista.c.
    – Mateo
    Commented el 14 jun. a las 19:21
  • No nos estas mostrando en donde esta definida la funcion crearLista ni donde la estas intentando usar, por loq ue el codigo que compoartes no tiene relacion con el error. (no uses ñ en los identidicadores de variables o funciones)
    – clay
    Commented el 14 jun. a las 20:42
  • @FJSevilla uso archivos de cabecera pero no los había puesto en la publicación, el archivo lista.h tiene todas las funciones y están correctamente implementadas igual que en lista.c (las hizo un profesor de universidad, no yo 😅).
    – Nico
    Commented el 14 jun. a las 22:08

1 respuesta 1

2

Si miras la línea del compilador verás que solo está compilando el archivo main.c, por eso no encuentra los demás símbolos:

/usr/bin/gcc-11 -fdiagnostics-color=always -g /home/nico/Escritorio/Programas/GUI/main.c -o /home/nico/Escritorio/Programas/GUI/main

Evidentemente estás usando la segunda tarea de compilación en lugar de la primera, que es la correcta.

Por cierto, no es recomendable usar caracteres especiales como la ñ y vocales con tildes para los identificadores.

4
  • Cuando dices que estoy usando la segunda tarea de compilación, ¿Te refieres en la rueda de engranajes de visual studio code que pone "Add debug configuration"? Gracias por la recomendación👍
    – Nico
    Commented el 15 jun. a las 19:05
  • @Nico si no lo he malinterpretado creo que Mateo se refiere a tu segundo "task" en tasks.json, en el archivo que muestras hay efectivamente dos items en la lista "tasks", si lo tienes así, prueba eliminando la segunda.
    – FJSevilla
    Commented el 15 jun. a las 20:21
  • @FJSevilla exactamente. Está seleccionando la segunda tarea de compilación en lugar de la primera.
    – Mateo
    Commented el 15 jun. a las 21:46
  • Pues si que era eso, muchísimas gracias por la ayuda a los dos.
    – Nico
    Commented el 15 jun. a las 22:02

¿No es la respuesta que buscas? Examina otras preguntas con la etiqueta o formula tu propia pregunta.