1
\$\begingroup\$

I have only been working with C for a couple of months and I think I have a pretty good function to insert a node in the front of the circular doubly linked list. I have tested in adding several nodes to it, but would like some feedback.

struct used in functions:

typedef struct TCB_t
{
    struct TCB_t * next;
    struct TCB_t * previous;
    ucontext_t context;
    int val;
}TCB_t;

Here is the function that calls the add_to_list() function:

void start_thread(void (*function)(void), int *arg)
{
    printf("In main: creating thread\n");
    struct stack * stackP = (struct stack*)malloc(8192);
    tcb = (struct TCB_t *)malloc(sizeof(struct TCB_t));
    init_TCB (tcb, function, stackP,  8192);
    tcb->val = iter;
    iter++;
    add_to_list( &ptr, &tcb);
}

This is the function in which I am not sure if I am adding the nodes correctly:

void add_to_list( struct TCB_t **ptrBlock, struct TCB_t **addQ)
{
    (*addQ)->val = iter;
    iter++;

    if(!*ptrBlock)
    {
        *ptrBlock = *addQ;
        (*ptrBlock)->next= *ptrBlock;
        (*ptrBlock)->previous = *ptrBlock;
    }
    else
    {
        (*ptrBlock)->previous->next = *addQ;
        (*addQ)->previous = (*ptrBlock)->previous;
        (*addQ)->next = *ptrBlock;
        (*ptrBlock)->previous = *addQ;
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ Include the definition of struct TCB_t, and ideally, some complete but short test code, for better reviews. \$\endgroup\$
    – Edward
    Commented Nov 10, 2014 at 21:47
  • \$\begingroup\$ I don't understand why add_to_list takes TCB_t **addQ as an argument instead of just TCB_t *addQ. You never modify the actual pointer passed in, so you are just adding a level of indirection for nothing. Also I personally like to use a local variable p which is set to *ptrBlock and then use p to do the list manipulation, then at the end set *ptrBlock = p. It gets rid of all the awkward (*ptrBlock)s. \$\endgroup\$
    – JS1
    Commented Nov 15, 2014 at 11:16

1 Answer 1

2
\$\begingroup\$

Here are some things that will help you improve your code.

Provide complete code to reviewers

This is not so much a change to the code as a change in how you present it to other people. Without the full context of the code and an example of how to use it, it takes more effort for other people to understand your code. This affects not only code reviews, but also maintenance of the code in the future, by you or by others. One good way to address that is by the use of comments. Another good technique is to include test code showing how your code is intended to be used.

Consider how your code is used

When somebody uses this code, they will probably want to insert a value into a data structure, and have the data structure handle all of the messy details, such as memory management. However, this code only seems to store successive integers (from a global variable) and requires the caller to allocate memory for the entire structure. So instead of an interface like this:

void add_to_list( struct TCB_t **ptrBlock, struct TCB_t **addQ)

a better interface would probably be this:

void add_to_list(struct TCB_t *node, int value)

This interface would allocate space for an additional TCB_t, add the passed value to it and link it appropriately to the existing node.

Provide convenience functions for testing

In order to test your function, it would be useful to be able to do things like print out the contents of the list. One way to do that is to provide a convenience functions such as this one:

void print_list(const struct TCB_t *n)
{
    if (n == NULL) {
        printf("empty list\n");
        return;
    }
    printf("%d", n->val);
    for (struct TCB_t *p=n->next; p!=n; p = p->next) 
        printf(", %d", p->val);
    printf("\n");
}

Consider providing a whole interface

Instead of providing just one function, it is often more useful to provide a couple of related functions to deal with a particular structure. For example, in the case of a circular doubly-linked list, node insertion, node deletion, printing, initialization and destruction are all reasonable things to expect from an interface. Providing only one fails to provide a sufficient spectrum that makes the data structure actually usable.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the comments, I added more code. I always have trouble with how much code to add. The function is supposed to add a node (the second struct TCB_t) to the end of the first node and (the first struct TCB_t). Since it is a circular linked list I am trying to add the second node in previous to the first one and than make the first node the next of the second node. \$\endgroup\$
    – Aaron
    Commented Nov 11, 2014 at 2:55

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.