8

I am creating a client/server application and want to call functions dynamically. i have create the following struct:

typedef struct _cmd cmd;
struct _cmd
{
    const char *name;
    void (*func)(int s,int ac, char **av);
};

When the client send a command to the server the server will browse through an array of commands:

cmd cmds[] = {
        { "CREATE", cmd_create },
        { "EXIT" ,  cmd_exit },
        { "LIST", cmd_list },
        { "READ", cmd_read },
        { "DELETE", cmd_delete },
        { "UPDATE", cmd_update }
};


cmd *find_cmd(const char *name) {
    cmd *c;
    for (c = cmds; c->name; c++) {
        if (stricmp(name, c->name) == 0)
            return c;
    }
    return NULL;
}    

Please not that

stricmp()

is not a typo, it a case-insensitive version of strcmp.

I now the following problem. When I call find_cmd() and pass an invalid commmand, my application crashes. my debugging messages showed the following:

Browsing Command: CREATE
Browsing Command: EXIT
Browsing Command: LIST
Browsing Command: READ
Browsing Command: DELETE
Browsing Command: UPDATE
Browsing Command: �p�
Browsing Command: �(�

After that i get the segfault. This looks to me as if there are some undefined elements in that struct arraym but where do they come from? What am I overlooking? Thanks in advance for any pointers.

4
  • 1
    You need a sentinel value to terminate your command list. Since this is a struct, null command and null function pointer will work. Commented Jun 20, 2014 at 17:13
  • 1
    Not the answer but just note. Don't use identifier starting with _ because it's reserved for implementation. Commented Jun 20, 2014 at 17:15
  • Thanks for the hints, this works fine, see my comment below :) Commented Jun 20, 2014 at 17:18
  • Also, I like as this thread is well-written, well-structured and is very clear what the author is looking for. :) Commented Jun 20, 2014 at 17:20

1 Answer 1

11

You need a "null" element at the end of your list to trigger the c->name (!= NULL) test in your for loop.

Change

cmd cmds[] = {
        { "CREATE", cmd_create },
        { "EXIT" ,  cmd_exit },
        { "LIST", cmd_list },
        { "READ", cmd_read },
        { "DELETE", cmd_delete },
        { "UPDATE", cmd_update }
};

to

cmd cmds[] = {
        { "CREATE", cmd_create },
        { "EXIT" ,  cmd_exit },
        { "LIST", cmd_list },
        { "READ", cmd_read },
        { "DELETE", cmd_delete },
        { "UPDATE", cmd_update },
        { NULL, NULL }
};
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for the quick reply, this works as a charme. How come I need to explicitly add a NULL, NULL element to the list? I'm not checking for (c->name == NULL) but return NULL when nothing was found?
But you are testing c->name == NULL. That's the termination condition on your for loop. That's what the center expression on the for statement does.
@Fish-Guts, your loop termination condition is c->name i.e c->name != NULL. By adding the sentinel NULL element, it allows the for loop to exit.

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.