Linked List Issue

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

    #1

    Linked List Issue

    Hello all again,

    Sorry for troubling you with my problems. I've tried to implement
    simple double linked lists, here's my structure:
    struct DResult {
    double val;
    char* title;
    struct DResult* next;
    struct DResult* prev;
    };

    I also have a typedef for struct DResult to DResult.

    Then I've written a function to append an element to the list with the
    following declation:
    int dresult_append( DResult* list, DResult* element);
    Then I used a debugger to trace down the issue with the function, so
    the this code fragment inside the function:
    if(list == NULL) // empty list
    {
    list = element;

    return 1;
    }

    The problem is that list is updated after the assignment but after the
    function returns, it goes back to NULL. I'm quite puzzled. Do I have to
    use a double pointer for the list like DResult** list and then update
    *list ( which a pointer to a DResult)?

    Regards

  • Chris Smith

    #2
    Re: Linked List Issue

    gamehack <gamehack@gmail .com> wrote:[color=blue]
    > int dresult_append( DResult* list, DResult* element);
    > Then I used a debugger to trace down the issue with the function, so
    > the this code fragment inside the function:
    > if(list == NULL) // empty list
    > {
    > list = element;
    >
    > return 1;
    > }
    >
    > The problem is that list is updated after the assignment but after the
    > function returns, it goes back to NULL. I'm quite puzzled.[/color]

    C is pass by value. If you assign to a formal parameter, that
    assignment has no effect outside of the function where it happens. For
    this reason, it's generally considered poor form to assign to a formal
    parameter in the first place.
    [color=blue]
    > Do I have to
    > use a double pointer for the list like DResult** list and then update
    > *list ( which a pointer to a DResult)?[/color]

    Yes, that would certainly solve your problem.

    --

    The Easiest Way To Train Anyone... Anywhere.

    Chris Smith - Lead Software Developer/Technical Trainer
    MindIQ Corporation

    Comment

    • gamehack

      #3
      Re: Linked List Issue

      [snip][color=blue]
      > this reason, it's generally considered poor form to assign to a formal
      > parameter in the first place.
      >[/color]

      What is the proper design for this kind of function? Should I use
      another proper approach?

      Thanks

      Comment

      • Chris Smith

        #4
        Re: Linked List Issue

        gamehack <gamehack@gmail .com> wrote:[color=blue]
        > [snip][color=green]
        > > this reason, it's generally considered poor form to assign to a formal
        > > parameter in the first place.
        > >[/color]
        >
        > What is the proper design for this kind of function? Should I use
        > another proper approach?[/color]

        Because C is so widely used, there aren't a lot of guidelines that are
        used throughout all of the C language. Passing a pointer-to-pointer
        would be okay, as would returning the new list pointer. I would
        intuitively prefer to return the new list pointer, but I've also seen a
        reasonable case made for non-idempotent functions to use the return
        value only for success/failure notification.

        The reason not to assign directly to a formal parameter is just that it
        doesn't work, for your definition of "work". Assigning to the thing
        that a formal parameter points to, on the other hand, is fine and
        actually very common.

        --
        Chris Smith

        Comment

        • CBFalconer

          #5
          Re: Linked List Issue

          gamehack wrote:[color=blue]
          >
          > Sorry for troubling you with my problems. I've tried to implement
          > simple double linked lists, here's my structure:
          > struct DResult {
          > double val;
          > char* title;
          > struct DResult* next;
          > struct DResult* prev;
          > };
          >
          > I also have a typedef for struct DResult to DResult.
          >
          > Then I've written a function to append an element to the list with the
          > following declation:
          > int dresult_append( DResult* list, DResult* element);[/color]

          There's your trouble. C passes by value, so to change a list you
          have to alter something. You want:

          struct DResult *appendto(struc t DResult *list,
          struct DResult *element);

          called by something like

          thelist = appendto(thelis t, newelement);

          and you better have some rules about the initial state, i.e. the
          empty list.

          --
          "The power of the Executive to cast a man into prison without
          formulating any charge known to the law, and particularly to
          deny him the judgement of his peers, is in the highest degree
          odious and is the foundation of all totalitarian government
          whether Nazi or Communist." -- W. Churchill, Nov 21, 1943


          Comment

          • Ben Bacarisse

            #6
            Re: Linked List Issue

            On Wed, 15 Feb 2006 14:41:04 -0800, gamehack wrote:
            [color=blue]
            > [snip][color=green]
            >> this reason, it's generally considered poor form to assign to a formal
            >> parameter in the first place.
            >>
            >>[/color]
            > What is the proper design for this kind of function? Should I use another
            > proper approach?[/color]

            I'd suggest that there are two common solutions to this problem. The
            fundamental issue is that the list is not properly represented by the
            structure that hold a node's data. A list can be empty so the real
            repsenetation of the list is a *pointer* to one of those structs (a
            pointer which might then be NULL).

            Option 1: Every list modifying function takes a list (i.e. a struct ptr)
            as an arguments and returns a list as a result. Every call of the
            function must then look something like this:

            struct DResult *my_list;
            ....
            my_list = list_append(my_ list, 1.2);

            Option 2: Define a new struct that holds (at least) the pointer to the
            start of the list. You can do more with this method, because the
            structure can hold extra information such as a pointer to last element
            (for appending) or a count of the number of elements or whatever else
            might help your design:

            struct DResultList {
            struct DResult *start;
            struct DResult *end;
            int n_elements;
            };

            All your list functions now take a pointer to a struct DResultList and
            operate on it.

            Option 1 makes it very simple to write short recusive list functions.
            Option 2 is much more flexible but requires more complexity.

            --
            Ben.

            Comment

            • gamehack

              #7
              Re: Linked List Issue


              Ben Bacarisse wrote:[color=blue]
              > On Wed, 15 Feb 2006 14:41:04 -0800, gamehack wrote:
              >[color=green]
              > > [snip][color=darkred]
              > >> this reason, it's generally considered poor form to assign to a formal
              > >> parameter in the first place.
              > >>
              > >>[/color]
              > > What is the proper design for this kind of function? Should I use another
              > > proper approach?[/color]
              >
              > I'd suggest that there are two common solutions to this problem. The
              > fundamental issue is that the list is not properly represented by the
              > structure that hold a node's data. A list can be empty so the real
              > repsenetation of the list is a *pointer* to one of those structs (a
              > pointer which might then be NULL).[/color]

              That's what I've done.
              [color=blue]
              > Option 1: Every list modifying function takes a list (i.e. a struct ptr)
              > as an arguments and returns a list as a result. Every call of the
              > function must then look something like this:
              >
              > struct DResult *my_list;
              > ....
              > my_list = list_append(my_ list, 1.2);[/color]

              I'm not really a fan of this approach - I think the user(programmer
              actually) should not be required to use this construct, it's much more
              intuitive to provide just two parameters and don't care about the
              result(with respect to the list and element variables).
              [color=blue]
              > Option 2: Define a new struct that holds (at least) the pointer to the
              > start of the list. You can do more with this method, because the
              > structure can hold extra information such as a pointer to last element
              > (for appending) or a count of the number of elements or whatever else
              > might help your design:
              >
              > struct DResultList {
              > struct DResult *start;
              > struct DResult *end;
              > int n_elements;
              > };
              >
              > All your list functions now take a pointer to a struct DResultList and
              > operate on it.
              >[/color]

              This is how I resolved my issue:

              int dresult_append( DResult** list, DResult** element);

              And in main.c I do something like:
              DResult* list = NULL;
              DResult* element = dresult_new();
              where dresult_new() mallocs the structure and initialises all the
              structure elements.
              [color=blue]
              > Option 1 makes it very simple to write short recusive list functions.
              > Option 2 is much more flexible but requires more complexity.
              >
              > --
              > Ben.[/color]

              Thanks

              Comment

              • stathis gotsis

                #8
                Re: Linked List Issue

                "gamehack" <gamehack@gmail .com> wrote in message
                news:1140100887 .130957.244470@ g43g2000cwa.goo glegroups.com.. .[color=blue]
                > This is how I resolved my issue:
                >
                > int dresult_append( DResult** list, DResult** element);[/color]

                Why is the second argument a double pointer? Is any modification necessary
                for *element?
                [color=blue]
                > And in main.c I do something like:
                > DResult* list = NULL;
                > DResult* element = dresult_new();
                > where dresult_new() mallocs the structure and initialises all the
                > structure elements.[/color]


                Comment

                • Default User

                  #9
                  Re: Linked List Issue

                  gamehack wrote:

                  [color=blue]
                  > Then I used a debugger to trace down the issue with the function, so
                  > the this code fragment inside the function:
                  > if(list == NULL) // empty list
                  > {
                  > list = element;
                  >
                  > return 1;
                  > }
                  >
                  > The problem is that list is updated after the assignment but after the
                  > function returns, it goes back to NULL. I'm quite puzzled. Do I have
                  > to use a double pointer for the list like DResult** list and then
                  > update *list ( which a pointer to a DResult)?[/color]


                  You received the answer already, but I'll also point out that this
                  issue is covered in the FAQ:




                  It's a good idea to run through that with your questions first.



                  Brian

                  Comment

                  • Ben Bacarisse

                    #10
                    Re: Linked List Issue

                    On Thu, 16 Feb 2006 06:41:27 -0800, gamehack wrote:
                    [color=blue]
                    > Ben Bacarisse wrote:[color=green]
                    >> On Wed, 15 Feb 2006 14:41:04 -0800, gamehack wrote:
                    >>[color=darkred]
                    >> > [snip]
                    >> >> this reason, it's generally considered poor form to assign to a
                    >> >> formal parameter in the first place.
                    >> >>
                    >> >>
                    >> > What is the proper design for this kind of function? Should I use
                    >> > another proper approach?[/color]
                    >>
                    >> I'd suggest that there are two common solutions to this problem.
                    >> <two linked-list options snipped>[/color][/color]
                    [color=blue]
                    > This is how I resolved my issue:
                    >
                    > int dresult_append( DResult** list, DResult** element);[/color]

                    I should have included this as option 3 (although it follows naturally
                    from my first paragrah). It is fine, of course, but not my favourite.

                    Having gone to the effort of passing a pointer to a mutable "thing" I
                    think it makes sense to make it a struct even if it has only one pointer
                    in it! At least you get the chance to grow it later if your
                    implementation requires it -- and you get another name: struct DResultList
                    which helps to distinguish between the nodes and the list itself.

                    BTW, it is best not to quote sigs (unless you want to talk about them).

                    --
                    Ben.

                    Comment

                    Working...