0

I'm "working" in a school project that needs to use linked lists with chars* and some other variables. The thing is:

I'm using a sub-function to open, read and store the data in a List but can't access to the string on it, I mean, can see other infos just dont that one...

void main()
{
    Palavra* P = lerPalavras();
    printf ("%s", P->c);               //Was just testing in this ...
}

The sub-funtion

Palavra* lerPalavras ()               //Just ignore what is going on here in the code, the problem is when I call it, within the function the output works just fine, but when I pass to main it's just not working at all. Thanks
{
    char linha [50];
    Palavra* P = NULL;
    Palavra* pv = NULL;
    FILE* ficheiro = fopen ("keywords.txt", "r");

    if(ficheiro == NULL)
    {
        printf ("Abertura do Ficheiro 'keywords.txt' Falhou!");
        return NULL;
    }   
    while (fgets (linha, sizeof (linha), 
    {
        if (linha [strlen(linha) - 1] != '\n')
            linha [strlen(linha)] = '\0';
        else
            linha [strlen(linha) - 1] = '\0';
        pv = CriaKW ();
        pv->c = linha;
        pv->tam = strlen (linha);
        P = insertKW (P, pv);
    }
    fclose (ficheiro);
    return (P);
}

The struct "Mensagem"

typedef struct KW
{
    char* c;
    struct KW* nseg;
    int ID;
    long int tam;
} Palavra;

The function "CriaKW"

Palavra* CriaKW ()                                          
{
    Palavra * pv = (Palavra*) malloc (sizeof (Palavra));
    return (pv);
}

The function "insertKW"

Palavra* insertKW (Palavra* P, Palavra* pv)
{
    pv->nseg = NULL;
    if (P == NULL)                      //Ver se a Lista está vazia
        return (pv);
    Palavra* p = P;                     //Variável Auxiliar para não perder a cabeça da Lista
    while (p->nseg != NULL)             //Ver se a "caixa" tem seguinte
        p = p->nseg;                    //Correr a Lista
    p->nseg = pv;
    return (P);
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Diogo Dias
  • 15
  • 8
  • Please fix the indentation and formatting. Put four spaces before every line of code – Erik W Dec 21 '17 at 00:12
  • Thanks @ppz, did it – Diogo Dias Dec 21 '17 at 00:16
  • I suggest [always using curly braces for branching and looping](https://stackoverflow.com/questions/2125066/is-it-bad-practice-to-use-an-if-statement-without-brackets). – Galen Dec 21 '17 at 00:17
  • What do you mean by "not working at all"? – Jose Fernando Lopez Fernandez Dec 21 '17 at 00:20
  • it is unclear what you are asking. Is the return value of `lerPalavras` not what you expected? If so, what is the definition of `insertKW`? Please provide a [Minimal, Complete, and Verifiable Example](https://stackoverflow.com/help/mcve). – Galen Dec 21 '17 at 00:21
  • 1
    @Diogo Dias The array linha is a local variable of the function. So this statement pv->c = linha; results in undefined behavior after exiting the function. That is the pointer will have an invalid value. – Vlad from Moscow Dec 21 '17 at 00:22
  • Did add the functions, sorry about that. @Jose I mean when I try to use P->c in main and P->c in function that are diferent values (only function is correct) – Diogo Dias Dec 21 '17 at 00:27
  • Yea, that's what @VladfromMoscow is saying. The function gets a correct value but then passes the *address* of the value, not the value itself. After the function returns, it's memory is used for something else and that address no longer holds the value it returned. – Jose Fernando Lopez Fernandez Dec 21 '17 at 00:35
  • oh thanks, any way to do that ? Should I convert char into char* than it should work? – Diogo Dias Dec 21 '17 at 00:46

3 Answers3

0

There are two problems due to the line: pv->c = linha;

  1. It's saving a pointer to a local variable in the structure that it's returning. That variable is destroyed when the function returns, so the pointer is no longer valid.
  2. You're using the same linha variable for every line that you read. So even if the variable weren't destroyed, all the Palavra structures would have the last line of the file.

You need to make a copy of the line to save it. Change that line to:

pv->c = strdup(linha);

strdup() is a POSIX function, not standard C. If that's a restriction on your code, it should be simple for you to write it yourself using malloc() and strcpy().

BTW, this line is not needed:

        linha [strlen(linha)] = '\0';

Since strlen() works by finding the position of the \0 character, this is just setting that character to what it already has. Change the if that contains this to:

if (linha[strlen(linha)-1] == '\n') {
    linha[strlen(linha)-1] = '\0';
}
Barmar
  • 741,623
  • 53
  • 500
  • 612
0

The array linha is a local object of the function

Palavra* lerPalavras ()
{
    char linha [50];
    //...

and has the automatic storage duration, After exiting the function it will not be alive and can be either overwritten by other objects of the program or even inaccessible.

In any case the pointer pv->c of each node initialized this way

pv->c = linha;

will have an invalid value after exiting the function.

You should dynamically allocate memory pointed to by this pointer and copy the original string to the allocated memory.

For example

linha[ strcspn( linha, "\n" ) ] = '\0';
size_t n = strlen( linha );

pv->c = malloc( n + 1 );
strcpy( pv->c, linha );
pv->tam = n;

Also you need to remember to free the memory allocated for the string when a node of the list is deleted.

Take into account that it is better instead of the type long int to use the type size_t for data member tam because in general it is not necessary that the type size_t is equivalent to the type long int though the standard function strlen and other string functions use the type size_t..

size_t tam;
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

Thanks to everyone, I'm new here but you all tried to help! Thanks a lot!

Did this code: pv->c = strdup(linha);

Diogo Dias
  • 15
  • 8