-2

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
Martim Correia
  • 483
  • 5
  • 16
  • 1
    You may want to read this: [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) – Andreas Wenzel May 22 '20 at 12:35
  • 1
    What does `remove_esp` do? What is `link_char`? What is `nome_jg`? Please make sure that the [mcve] you show really replicates your problem, and preferably can be copied and tested by us. – Some programmer dude May 22 '20 at 12:38
  • 1
    The problem is the `head2 = insertEnd_v(...)` assignment in the `A` function. In C all arguments are passed *by value*, which means that the value of the argument is *copied* into the functions local argument-variable. When you do the assignment in the `A` function, you only assign to the local variable `head2`, the variable `head2` in the `main` function remains unchanged. Now when you know what the issue is, it should be easier to find examples on how to solve it, but to help you I suggest you do some research about *emulate pass by reference in C*. – Some programmer dude May 22 '20 at 16:48
  • @Someprogrammerdude: I wouldn't call "pass by pointer" as an "emulation" of C++ "pass by reference". "Pass by pointer" has existed long before references were introduced into C++. – Andreas Wenzel May 22 '20 at 16:52
  • 1
    The function `insertEnd_v` returns the address of the new head. However, the function `A` does not do this, so the function `main` has no way of knowing the address of the new head. Therefore, you can either make `A` also return the address of the new head, or you provide some other way for `main` to obtain the address of the new head, for example by using "pass by pointer" with the head parameter instead of "pass by value". Alternatively, you can use a global variable, but I don't recommend this. – Andreas Wenzel May 22 '20 at 17:07
  • yeah i cant use global variables but thanks for the help ill try it then – Martim Correia May 22 '20 at 19:23
  • well ive tried ur approach of returning the head and it worked, thanks a lot!!! – Martim Correia May 22 '20 at 19:57
  • @MartimCorreia: I'm glad I was able to help. Unfortunately, this "return value" method is not very flexible, because a function can't return more than one value. Therefore, in future, you may want to consider using "pass by pointer" instead of "pass by value". If the called function receives a pointer to a variable of the caller function, it can write directly to that variable. However, passing the pointer to the head "by pointer" instead of "by value" means that you would be passing a pointer to the pointer to the head, i.e. a double pointer. Double pointers can be confusing for beginners. – Andreas Wenzel May 22 '20 at 21:55
  • Yeah i tried that but instead i get and i felt confused so i used the return method – Martim Correia May 22 '20 at 22:20
  • @MartimCorreia: I have now added an answer that shows you how to implement it with "pass by pointer". – Andreas Wenzel May 22 '20 at 23:05

2 Answers2

0

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.

0

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.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • Thanks man btw could u help me out with this https://stackoverflow.com/questions/61963925/sorting-a-linked-list-contaning-strings?noredirect=1#comment109595657_61963925 too pls – Martim Correia May 22 '20 at 23:25