((node*)&head)->next

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Francois Grieu

    #1

    ((node*)&head)->next

    Given that next is the first field in struct node,
    and head is a pointer to node,
    does assigning ((node*)&head)->next safely assign head ?

    Illustration (this code works on many platforms)


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

    /* node structure for linked list */
    typedef struct node
    {
    struct node* next;
    char payload;
    } node;

    int main(void)
    {
    node *head, *last, *temp;
    int c;
    /* build list from stdin */
    last = (node*)&head;
    while ((c = getchar())!=EOF )
    {
    if ((temp = malloc(sizeof(n ode)))==NULL)
    return 1;
    temp->payload = c;
    last->next = temp;
    last = temp;
    }
    last->next = NULL;
    /* then output list */
    temp = head;
    while (temp!=NULL)
    {
    putchar(temp->payload);
    temp = temp->next;
    }
    return 0;
    }

    --
    François Grieu
  • Chris Torek

    #2
    Re: ((node*)&amp;he ad)-&gt;next

    In article <fgrieu-82AB50.08532613 122004@individu al.net>
    Francois Grieu <fgrieu@francen et.fr> wrote:[color=blue]
    >Given that next is the first field in struct node,
    >and head is a pointer to node,
    >does assigning ((node*)&head)->next safely assign head ?
    >
    >Illustration (this code works on many platforms)[/color]

    I would be surprised to find a platform on which this does *not*
    work:
    [color=blue]
    >#include <stdlib.h>
    >#include <stdio.h>
    >
    >/* node structure for linked list */
    >typedef struct node
    > {
    > struct node* next;
    > char payload;
    > } node;
    >
    >int main(void)
    > {
    > node *head, *last, *temp;
    > int c;
    >/* build list from stdin */
    > last = (node*)&head;
    > while ((c = getchar())!=EOF )
    > {
    > if ((temp = malloc(sizeof(n ode)))==NULL)
    > return 1;
    > temp->payload = c;
    > last->next = temp;
    > last = temp;
    > }
    > last->next = NULL;[/color]
    [etc]

    But there is no need to resort to such subterfuge. Simply use
    pointers the way they are intended:

    node *head, *temp;
    node **npp = &head;

    while ((c = getchar()) != EOF) {
    temp = malloc(sizeof *temp);
    if (temp == NULL)
    return EXIT_FAILURE;
    temp->payload = c;
    *npp = temp;
    npp = &temp->next;
    }
    *npp = NULL;

    While the head is just a pointer (of type "struct node *", aka
    "node *"), each node also contains a pointer of that same type.
    If we point a separate pointer ("npp") at each pointer in turn, we
    can set each pointed-to pointer with absolute 100% guaranteed
    safety, even though the "head" pointer is *just* a pointer, and
    the other pointers are elements of a larger collection.

    Naturally, to point to "struct node *" objects, we need a pointer
    of type "struct node **" (aka "node **").

    Note that this code continues to work even if the "next" field is
    moved elsewhere in the list structure -- while the original code,
    with its cast, stops working.
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.

    Comment

    • Lawrence Kirby

      #3
      Re: ((node*)&amp;he ad)-&gt;next

      On Mon, 13 Dec 2004 08:53:27 +0100, Francois Grieu wrote:
      [color=blue]
      > Given that next is the first field in struct node,
      > and head is a pointer to node,
      > does assigning ((node*)&head)->next safely assign head ?[/color]

      This isn't safe because the alignment of a node structure may be stricter
      than the alignment of a pointer to node. Also you are creating a pointer
      to node value which isn't null and doesn't point at a valid node object,
      or 1 past the end of an array of nodes.
      [color=blue]
      > Illustration (this code works on many platforms)[/color]

      Yes, it is likely to work on many platforms but as far as C is concerned
      it invokes undefined behaviour.

      Chris's solution is well defined hence better.

      Lawrence

      Comment

      • Francois Grieu

        #4
        Re: ((node*)&amp;he ad)-&gt;next

        Chris Torek <nospam@torek.n et> wrote:
        [color=blue]
        > Simply use pointers the way they are intended
        >
        > node *head, *temp;
        > node **npp = &head;
        >
        > while ((c = getchar()) != EOF) {
        > temp = malloc(sizeof *temp);
        > if (temp == NULL)
        > return EXIT_FAILURE;
        > temp->payload = c;
        > *npp = temp;
        > npp = &temp->next;
        > }
        > *npp = NULL;[/color]

        Yes, that's clean.

        For reasons not apparent in the sample code that I posted,
        I wanted to keep a pointer to the last node in the list,
        and Chris's code does not do that. But now I realize
        that a pointer to the "next" field in the last node in the
        list will do just as well, if not better.

        Thanks Chris. Also, thanks Lawrence for a concrete reason
        why the original code could fail (beside plain non-conformance).

        --
        François Grieu

        Comment

        Working...