1

I am trying to assign a pointer to an array element inside the function get_by_id.

The function get_by_id finds the element correctly and assigns to element to lp, however when it comes back to the caller (set_attr), it reverts to NULL.

I'm not understanding why it's reverting to NULL in the caller, let alone how to fix it.

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


typedef struct
{
    int id;
    char name[128];
    int attr;
} Lookup;


static int num_sources = 0;

Lookup ltable[128];


void add(int id, const char *name)
{
    sprintf(ltable[num_sources].name, name);
    ltable[num_sources].id = id;
    ltable[num_sources].attr = 999;  // example default attr 999
    num_sources++; // increment the number of sources
}


int get_by_id(int id, Lookup *lp)
{
    int status = 1;
    for (int i = 0; i < 128; i++)
    {
        lp = &ltable[i];
        if (id == lp->id)
        {
            status = 0;
            break;
        }
    }
    return status;
}


int set_attr(const int id, const int attr)
{
    Lookup *lp = NULL;
    int status = get_by_id(id, lp);
    if (status == 0)
    {
        lp->attr = attr;
    }
    return status;
}

int main(void) {
    add(88, "main"); // example id 88
    set_attr(88, 9); // example attr 9
    return EXIT_SUCCESS;
}
3
  • 1
    C is pass by value. Pass its address. Commented Mar 2, 2018 at 17:23
  • " how to fix it." Do you expect lp in set_attr() to remain unchanged if a matching id not found? Commented Mar 2, 2018 at 17:28
  • I don't, I expect status to remain == 1 and check that from the caller. Commented Mar 2, 2018 at 19:05

2 Answers 2

3

To change the value of lp you must use a double pointer:

int get_by_id(int id, Lookup **lp)
{
    int status = 1;
    for (int i = 0; i < 128; i++)
    {
        *lp = &ltable[i];
        if (id == (*lp)->id)
        {
            status = 0;
            break;
        }
    }
    return status;
}

and call like:

    int status = get_by_id(id, &lp);

Because C is "pass by value", a copy of lp is made and passed to the function. Any change to that copy cannot be seen by the caller. To allow the called function to change the variable of the caller, you pass the address of the caller's variable, so the called function can change it. In your case, you pass the address of lp written as &lp.


The following version may be peferred:

#define T_SIZE (sizeof(ltable)/sizeof(ltable[0]))

Lookup *get_by_id(int id)
{
    for (int i = 0; i < T_SIZE; i++)
        if (id == ltable[i].id)
            return &ltable[i];

    return 0;
}

Note that it returns a pointer to the table entry and zero if not found.

Sign up to request clarification or add additional context in comments.

Comments

0

You need to just pass the Lookup parameter by reference rather by value. This is because you can only modify the parameter only if it is passed by reference.

int get_by_id(int id, Lookup *lp)
{
    int status = 1;
    for (int i = 0; i < 128; i++)
    {
        *lp = ltable[i];
        if (id == lp->id)
        {
            status = 0;
            printf("lp=%X\n", lp);
            break;
        }
    }
    return status;
}

int set_attr(const int id, const int attr)
{
    Lookup lp = {0};
    int status = get_by_id(id, &lp);
    if (status == 0)
    {
        printf("lp = %X\n", &lp);
        lp.attr = attr;
    }
    return status;
}

This should work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.