Home > Net >  How to update the pointer to create a list
How to update the pointer to create a list

Time:11-16

I'm trying to learn C and I'm having some trouble creating a list using pointers.

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

typedef struct _tDateTimeNode
{
    struct _tDateTimeNode *next;
} tDateTimeNode;

typedef struct _ApiData
{
    tDateTimeNode *timeNodeList;
} tApiData;

void dateTimeNode_insert(tDateTimeNode **_list)
{
    bool found = false;
    tDateTimeNode *list = (*_list);
    while (list != NULL && !found)
    {
        printf("This code never runs!\n");
        list = list->next;
    }

    if (list == NULL)
    {
        printf("This if is always executed!\n");
        list = (tDateTimeNode *)malloc(sizeof(tDateTimeNode));
    }

    if (*_list == NULL)
    {
        printf("This if is also executed!\n");
        _list = &list;
    }
}

int main()
{
    tApiData data;
    data.timeNodeList = NULL;

    tDateTimeNode **timeNode = &(data.timeNodeList);
    dateTimeNode_insert(timeNode);
    dateTimeNode_insert(timeNode);
    dateTimeNode_insert(timeNode);
    dateTimeNode_insert(timeNode);
}

After compiling the problem with gcc -o t test.c && ./t, I'm getting the following output:

This if is always executed!
This if is also executed!
This if is always executed!
This if is also executed!
This if is always executed!
This if is also executed!
This if is always executed!
This if is also executed!

As you can see, the last two if are always executed. But the while is never run. The while block should be run after the first execution of the function because supposedly I have added a new element. I think I'm not updating the value of _list correctly, but I have already run out of options to try. Any idea how to solve it?

CodePudding user response:

There are many problems in the way you wrote this

void dateTimeNode_insert(tDateTimeNode **_list)
{
    bool found = false;
    tDateTimeNode *list = (*_list);
    while (list != NULL && !found)
    {
        printf("This code never runs!\n");
        list = list->next;
    }

    if (list == NULL)
    {
        printf("This if is always executed!\n");
        list = (tDateTimeNode *)malloc(sizeof(tDateTimeNode));
    }

    if (*_list == NULL)
    {
        printf("This if is also executed!\n");
        _list = &list;
    }
}

Note that found is always false and can be deleted, since !false is always true, never changed

_list is tDateTimeNode** so it is supposed to bring in the address of the head of the list in *_list

When you write

   _list = &list;

The only reference to the list is gone for good. Maybe you intended to write *_list = list; in order to save the new head of the list when inserting the first element

The naming is also confusing: list, _list.

Note that a list is a container. You should not mix the list with the data. Your list today is of DateTimeNode but it is still just a list. In your next program may be that one of books, the one of songs in a playlist, all classic list exercises. If the code is more generic it is trivial to create lists. All sorts of lists

Example: a list and a DateTimeNode

I will post an example using your code, but using what I wrote above

Imagine a list of tickets to control a queue. Each customer on enter gets a ticket with a sequence number and a timestamp in the format yyyy-mm-dd hh:mm:ss. Customer enter at the end of the queue.

Here is a possible ticket

typedef struct
{
    char*    ts;   // time stamp
    unsigned USN;  // sequence number

}   Ticket;

A possible Node for a list of these tickets

typedef struct _Node
{
    Ticket*       tk;
    struct _Node* next;

}   Node;

As expected each node of the list points to a ticket. A list is just a container.

The list itself could be

typedef struct
{
    Node*    head;  // first node if any
    unsigned size;  // actual Node count

}   List;

These way things are easier to understand: A list has nodes, each node points to some data. The data is numbered, so it is easy to test. And have a timestamp. Sure, computers are fast, and the time stamp resolution is seconds, so we would need thousands of nodes to see different time stamps...

a minimal set of functions

List* create();
List* destroy(List*);
int   insert(Ticket*, List*);
int   show(List*, const char*);

show() accepts an optional string for a message and destroy() returns NULL as a courtesy, so we can invalidate the list pointer in the same line we destroy the list.

A test

int main(void)
{
    Ticket ticket;
    List*  one = create();
    for (int i = 1; i <= 10; i  = 1)
    {
        ticket.USN = i;
        ticket.ts  = get_ts();
        insert(&ticket, one);
    };
    show(one, "After 10 tickets inserted...\n");
    one = destroy(one);  // destroys list, invalidate pointer
    return 0;
}

The code creates a list with 10 tickets, show them and deletes the list.

output

After 10 tickets inserted...

   List has 10 elements:

    1  2021-11-15 14:12:06
    2  2021-11-15 14:12:06
    3  2021-11-15 14:12:06
    4  2021-11-15 14:12:06
    5  2021-11-15 14:12:06
    6  2021-11-15 14:12:06
    7  2021-11-15 14:12:06
    8  2021-11-15 14:12:06
    9  2021-11-15 14:12:06
   10  2021-11-15 14:12:06

Example code

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

typedef struct
{
    char*    ts;   // time stamp
    unsigned USN;  // sequence number
} Ticket;

typedef struct _Node
{
    Ticket*       tk;
    struct _Node* next;

} Node;

typedef struct
{
    Node*    head;  // first node if any
    unsigned size;  // actual Node count
} List;

// List stuff
List* create();
List* destroy(List*);
int   insert(Ticket*, List*);
int   show(List*, const char*);

// helpers
char* get_ts();  // get time in format "yyyy-mm-dd hh:mm:ss"

int main(void)
{
    Ticket ticket;
    List*  one = create();
    for (int i = 1; i <= 10; i  = 1)
    {
        ticket.USN = i;
        ticket.ts  = get_ts();
        insert(&ticket, one);
    };
    show(one, "After 10 tickets inserted...\n");
    one = destroy(one);  // destroys list, invalidate pointer
    return 0;
};  // main()



List* create()
{
    List* list = (List*)malloc(sizeof(List));
    if (list == NULL) return NULL;
    list->head = NULL;
    list->size = 0;
    return list;
}

List* destroy(List* list)
{
    if (list == NULL) return NULL;
    Node* tmp = list->head->next;
    Node* p   = list->head;
    for (unsigned i = 0; i < list->size - 1; i  = 1)
    {  // delete ticket and node at p
        free(p->tk);
        free(p);
        p   = tmp;
        tmp = p->next;
    }
    // p now points to last
    free(p->tk);
    free(p);
    free(list);  // the List itself
    return NULL;
}

int insert(Ticket* tk, List* L)
{  // insert tk into list L, at the end
    if (L == NULL) return -1;
    if (tk == NULL) return -2;
    // get a new ticket
    Ticket* nt = (Ticket*)malloc(sizeof(Ticket));
    *nt        = *tk;
    // now creates a new Node for this ticket
    Node* nnd = (Node*)malloc(sizeof(Node));
    nnd->next = NULL;
    nnd->tk   = nt;

    // list is empty?
    if (L->size == 0)
    {
        L->head = nnd;
        L->size = 1;
        return 0;  // ok
    }

    // search List end
    Node* p = L->head;
    while (p->next != NULL) p = p->next;
    p->next = nnd;  // last now points to new
    L->size  = 1;
    return 0;  // ok
}

int show(List* L, const char* msg)
{
    if (msg != NULL) printf("\n%s\n", msg);
    if (L == NULL)
    {
        printf("There is no list: nothing to display");
        return -1;
    }
    printf("   List has %d elements:\n\n", L->size);
    Node* p = L->head;
    for (unsigned i = 0; i < L->size; i  = 1)
    {
        printf("%5u  %s\n", p->tk->USN, p->tk->ts);
        p = p->next;
    }
    printf("\n\n");
    return L->size;
}

char* get_ts()
{  // return string in format: "yyyy-mm-dd hh:mm:ss"
    time_t moment;
    time(&moment);  // get time
    // convert time to struct tm
    struct tm* t_info     = localtime(&moment);
    char*      time_stamp = (char*)malloc(20);
    // format time stamp and return to caller
    strftime(time_stamp, 20, "%Y-%m-%d %H:%M:%S", t_info);
    return time_stamp;
}
  • Related