searching for an element inside a linked list c

So i have a header file with a linked list implementation with a structure, the problem is when i want to find if an element is already inside the linked list if i do all the steps in the main function it works, but if i do that in a seperate function it doesnt work and i dont know why.

Program:

#include <stdlib.h> 
#include <stdio.h>
#include <string.h>
#include "Listas_ligadas2.h"

/*
ident: val[0]
linha: val[1]
*/

void remove_esp(char str[]); // removes the first char of the scanned string beacuse its of being a ' '
int equipa_in(link_v head, char nome[]);// the function with the problem

void A(char equipa[],int val[],link_v headv);

//basically while c != x it applies the switch

int main()
{
    char c;char nome[1023];
    link_v head2 = NULL;
    int valores[2] = {0,1};
    while ((c = getchar())!= 'x') {
    switch (c) 
    {
        case 'A':
        {
            scanf("%1023[^:\n]",nome);
            remove_esp(nome);
            if (equipa_in(head2,nome) == 1)
            {
                printf("%d Equipa existente.\n",valores[1]);
                valores[1]++;
            }
            else
            {
                head2 = insertEnd_v(head2,nome,valores);
                valores[1]++;
            }
            break;
        }
    }
    }
   return 0;
}

int equipa_in(link_v head, char nome[])
{
    link_v t;
    for(t = head; t != NULL; t = t->next)
        if(strcmp(t->v.nome,nome) == 0)
            return 1;
    return 0;
}

void remove_esp (char str[])
{
    int i;

    if (str[0] == ' ')
    {
        for (i = 0; str[i] != '\0'; ++i)
            str[i] = str[i + 1];
    }
}

So if i do it like that it works fine, but if i do it like this:

#include <stdlib.h> 
#include <stdio.h>
#include <string.h>
#include "Listas_ligadas2.h"

/*
ident: val[0]
linha: val[1]
*/

void remove_esp(char str[]); // removes the first char of the scanned string beacuse its of being a ' '
int equipa_in(link_v head, char nome[]);// the function with the problem
void A(char nome[],int valores[],link_v head2);


//basically while c != x it applies the switch

int main()
{
    char c;char nome[1023];
    link_v head2 = NULL;
    int valores[2] = {0,1};
    while ((c = getchar())!= 'x') {
    switch (c) 
    {
        case 'A':
        {
            scanf("%1023[^:\n]",nome);
            remove_esp(nome);
            A(nome,valores,head2);
            break;
        }
    }
    }
   return 0;
}

int equipa_in(link_v head, char nome[])
{
    link_v t;
    for(t = head; t != NULL; t = t->next)
        if(strcmp(t->v.nome,nome) == 0)
            return 1;
    return 0;
}

void remove_esp (char str[])
{
    int i;

    if (str[0] == ' ')
    {
        for (i = 0; str[i] != '\0'; ++i)
            str[i] = str[i + 1];
    }
}

void A(char nome[],int valores[],link_v head2)
{
    if (equipa_in(head2,nome) == 1)
    {
        printf("%d Equipa existente.\n",valores[1]);
        valores[1]++;
    }
    else
    {
        head2 = insertEnd_v(head2,nome,valores);
        valores[1]++;
    }
}

it doesnt work and i dont understand why.

header file:

#ifndef _Listas_ligadas2_
#define _Listas_ligadas2_

#include<stdlib.h> 
#include<stdio.h>
#include <string.h>

typedef struct vit
{
    int id;
    char *nome;
    int vit;
} vit;

typedef struct node_v
{
    vit v;
    struct node_v *next;
} *link_v;


//this function removes a certin char at a given index
void removechar_v(char *orig, int index, char *newStr)
{
    if(!orig){};
    if(!newStr){};
    int i=0, j=0;

    while (*(orig+i) != '\0')
    {
        if (i != index)
        {
            *(newStr+j) = *(orig+i);
            j++;
            i++;
        }
        else i++;
    }
    *(newStr+j) = '\0';
}

link_v NEW_vit(char *nome,int val[])
{
    int i;
    link_v x = (link_v) malloc(sizeof(struct node_v));
    x->v.nome = (char*) malloc(sizeof(char)*(strlen(nome)+1));
    strcpy(x->v.nome,nome);
    x->v.vit = 0;
    x->v.id = val[0];
    x->next = NULL;
    val[0]++;
    return x;
}

link_v insertEnd_v(link_v head,char *nome,int val[])
{
    link_v x;
    if(head == NULL)
        return NEW_vit(nome,val);
    for(x = head; x->next != NULL; x = x->next)
    ;
    x->next = NEW_vit(nome,val);
    return head;
}

int length_v(link_v head)
{
    int count=0;
    link_v x;
    for(x=head ; x!=NULL; x=x->next)
        count++;
    return count;
}

//prints the elements in the list and copies its name to another string because
//for some reason if i want to print t->v.nome and the nome is abc it prints abcc

void print_lista_v(link_v head,int val[])
{
    link_v t;char *nnome;
    for(t = head; t != NULL; t = t->next){
        nnome = (char*) malloc(strlen(t->v.nome)*sizeof(char));
        strcpy(nnome,t->v.nome);
        removechar_v(nnome,strlen(t->v.nome)-1,nnome);
        printf("%d %d %s %d\n",val[1],t->v.id,nnome,t->v.vit);
    }
}

//after removing an element it puts the corresponding indexes of the list

void baixa_id_v(link_v head)
{
    link_v t;int i;
    i = 0;
    for(t = head; t != NULL; t = t->next){
        t->v.id = i++;
    }
}

void FREEnode_v(link_v t)
{
    free(t->v.nome);
    free(t);
}

link_v delete_el_v(link_v head,char *nome)
{
    link_v t, prev;
    for(t = head, prev = NULL; t != NULL;
        prev = t, t = t->next) {
        if(strcmp(t->v.nome,nome) == 0) {
            if(t == head)
                head = t->next;
            else
                prev->next = t->next;
            FREEnode_v(t);
            break;
        }
    }
    return head;
}

link_v lookup_v(link_v head, char *nome)
{
    link_v t;
    for(t = head; t != NULL; t = t->next)
        if(strcmp(t->v.nome,nome) == 0)
            return t;
    return NULL;
}

#endif

2 answers

  • answered 2020-05-22 13:06 Fraser Davies

    I have had a go at copying and then compiling/running your code. Apart from a few typos (the code has a few references to link_char which I changed to link_v, I also declared char nome_jg[1023] and link_v head) it works for me.

    I did have to write the following function:

    void remove_esp (char str[])
    {
        int i;
    
        if (str[0] == ' ')
        {
            for (i = 0; str[i] != '\0'; ++i)
                str[i] = str[i + 1];
        }
    }
    

    ...this seems to be what the comment required of the function.

    The issue might be with your implementation of remove_esp.

  • answered 2020-05-22 23:04 Andreas Wenzel

    As has already been pointed out in the comments section, the problem is that the function main is passing a pointer to the head of the linked list by value to the function A. This means that the function A will have its own copy of the pointer to the head of the linked list. So any modification to this pointer in the function A will not change the pointer in the function main.

    If you want the function main to receive an updated value of the pointer to the head of the linked list, then you must provide some way for the function main to receive this value. You have 3 options to accomplish this:

    1. Change the prototype of the function 'A' to return the value of the new pointer to the head of the linked list.
    2. Change the prototype of the function 'A' so that the pointer to the head of the linked list is passed by pointer instead of by value.
    3. Store the pointer to the head of the linked list in a global veriable that will be used by both functions main and A.

    Generally, I don't recommend option #3, as it is often bad programming style to use global variables. Option #1 is better, however using return values is not very flexible, because a function can only return one value. Therefore, the most flexible option would be option #2.

    In order to implement option #2, you would have to change the function prototype from:

    void A(char nome[],int valores[],link_v head2);

    to:

    void A(char nome[],int valores[],link_v *head2);

    However, this is confusing, because link_v is already a pointer; it is a typedef for a struct node_v *. Threfore, a link_v * is actually a struct node_v **, so it is a double pointer. To make it clear that it is a double pointer, I will not use the link_v typedef, but will use struct node_v ** instead. Also, to make clear that it is a double pointer, I will also change the name of the variable by prefixing a "pp_", like this:

    void A(char nome[],int valores[], struct node_v **pp_head2);

    Now, you can rewrite the line

    A(nome,valores,head2);

    in the function main to the following:

    A(nome,valores,&head2);

    You are now passing the variable head2 by pointer and no longer by value, so that no copy of the variable is made. That way, any changes to this variable by the function A will also change the value of this variable in the function main.

    However, since the head2 parameter of the function A is now a double pointer, it must be used differently inside that function. The line

    head2 = insertEnd_v(head2,nome,valores);

    must be changed to:

    *pp_head2 = insertEnd_v(*pp_head2,nome,valores);

    Please note that I had to add the * to dereference the double pointer once. I also had to change the variable name in that line, because I had changed the name of the function parameter.