Pointer is lost at function output

3

I have the following function

typedef struct userDataStruct
{
    char name [MAX_NAME_LENGTH+1];
    struct userDataStruct *next;
} userDataType;

errorType GetUsers (userDataType **list)
{
    FILE *file;
    char buffer [LINE_LENGTH+1];
    userDataType *first, *previous, *new;

    file = fopen ("abc.dat", "r");
    first = previous = NULL;

    while (fgets (buffer, LINE_LENGTH+1, file))
    {
         new = (userDataType *) malloc (sizeof (userDataType));

         /* Resto do codigo */

        if (first == NULL)
            first = new;

        if (previous != NULL)
            previous->next = new;

        previous = new;
    }

    list = &first;

    return ok;
}

(ignore any syntax errors, I had to wipe)

When I need to call this function, I declare a pointer and step it with the null value. For example:

int main (void)
{
    userDataType **usersList = NULL,
            *currentUser;
    GetUsers(usersList);

    currentUser = *usersList; /* Aqui está o erro */
}

In the line indicated, the variable currentUser is null.

If I used the malloc function to allocate memory, should that variable not be pointing to the first element in the list?

Thank you in advance.

    
asked by anonymous 12.12.2017 / 23:05

1 answer

4

There are some problems with your code. In particular what is preventing a node from being assigned to its list is the way pointers (and values in general) are passed as parameters in C.

C adopts the "go by value" convention. The simplified rule is: every function sees a local copy of the arguments that were passed in the call.

When you pass a pointer on the call, the function sees a copy of the pointer, not the original pointer.

errorType GetUsers(userDataType **list)
{
    userDataType *first = // algo
    list = &first;
    return ok;
}

The list = &first; statement can be read as "get the address" of first (which in turn is a pointer to a struct ) and assign that value to list , which is a local copy of a pointer that points to another null pointer. The local copy is completely independent of the original pointer pointer and is discarded when the function exits.

What you really want to do inside the function body is:

*list = first;

The difference is subtle. This statement can be read as:

  • Get the value for which my local copy of list points (i.e., a pointer that initially points to NULL ).
  • Get the value of first (an address for a memory space you have allocated).
  • Assign 2 to 1.
  • The point here is that you are passing a copy of list as a parameter. No direct assignment to a local copy survives outside the scope of the function. You can not directly change the original pointer pointer. You can however change the value to which your copy points, which in turn modifies the original pointer.

    Still on this front, knowing that your argument is just a copy of the address, I do not think it makes sense to declare a pointer pointer in the main method. You can declare a conventional pointer and pass its address as an argument to the function, eg:

    userDataType *usersList = NULL;
    GetUsers(&usersList);
    userDataType  *currentUser = usersList;.
    

    This version avoids the explicit declaration of a pointer pointer and makes the call to GetUsers clearer.

    While these changes should solve your original problem, there are other issues with the code ... Outside of exercises I would definitely rethink the API, this strategy using output parameter + return from me remember coding standards from the 1990s. Calling your new variable also does not seem to me to be the best of ideas (C ++ programmers pull their hair by reading this code).

        
    13.12.2017 / 01:01