Different behaviour in different struct declaration types

Discussion in 'C Programming' started by __PaTeR, Dec 30, 2008.

  1. __PaTeR

    __PaTeR Guest

    These days i'm writing so much , now i was learning something about
    lists... In my code i have a while loop that ends up only when the
    NEXT member of the struct is equal to NULL; ( i'm just surfing in the
    list )

    Finding some good resource about structures has been really hard, for
    example, i found out by myself the difference between the 2 operators -
    > and . ... or at least i think i found it out.


    As i've seen through gdb and experiments, is that: when you declare a
    struct this way:
    struct lista a;

    To access the members u have to use the dot, and "a" doesn't contain
    the pointer to the memory, but the memory itself, just like an
    integer.

    Besides, if u declare it this way:
    struct lista *q; /* = malloc... etc */

    q is just a pointer to a memory region, just like a char definition
    ( char *a ). To access members you have to use the arrow -> .... don't
    you?

    SO: why this

    struct lista *q = malloc(sizeof(struct lista));
    q->num=n;
    q->next = NULL;

    works really good, but this one:

    struct lista a;
    a.num = n;
    a.next = NULL;

    does not?? This last code let my while ends never! And i ould the
    reason, look at this gdb output:

    -----------------------
    (gdb) print a.next
    $2 = (struct lista *) 0x0
    (gdb) print a
    $3 = {num = 1, next = 0x0}
    (gdb) print &a
    $4 = (struct lista *) 0xbfb4000c
    (gdb) x $4
    0xbfb4000c: 0x00000001
    (gdb) x $4+4
    0xbfb4002c: 0x08048b28
    (gdb) print $4+4
    $5 = (struct lista *) 0xbfb4002c <---- 1
    (gdb) x $5
    0xbfb4002c: 0x08048b28 <------ 2
    (gdb) print $5
    $6 = (struct lista *) 0xbfb4002c <----- 1
    (gdb) x $6
    0xbfb4002c: 0x08048b28 <------- 2
    (gdb) quit
    -----------------------
    As you can see, the last 4 outputs show the reason of the infinite
    loop.... But i ask.... why?
    __PaTeR, Dec 30, 2008
    #1
    1. Advertising

  2. __PaTeR <> writes:
    > These days i'm writing so much , now i was learning something about
    > lists... In my code i have a while loop that ends up only when the
    > NEXT member of the struct is equal to NULL; ( i'm just surfing in the
    > list )
    >
    > Finding some good resource about structures has been really hard,
    > for example, i found out by myself the difference between the 2
    > operators -> and . ... or at least i think i found it out.


    It shouldn't be that hard; any decent C textbook should explain this.
    K&R2 (Kernighan & Ritchie, "The C Programming Language", 2nd Edition)
    is widely considered to be an excellent book. See also question 18.10
    in the comp.lang.c FAQ, <http://www.c-faq.com/>.

    > As i've seen through gdb and experiments, is that: when you declare a
    > struct this way:
    > struct lista a;
    >
    > To access the members u have to use the dot, and "a" doesn't contain
    > the pointer to the memory, but the memory itself, just like an
    > integer.
    >
    > Besides, if u declare it this way:
    > struct lista *q; /* = malloc... etc */
    >
    > q is just a pointer to a memory region, just like a char definition
    > ( char *a ). To access members you have to use the arrow -> .... don't
    > you?


    Correct. "x->y" is an abbreviation for "(*x).y". But I'm at a loss
    to understand why you needed "gdb and experiments" to learn this.

    > SO: why this
    >
    > struct lista *q = malloc(sizeof(struct lista));
    > q->num=n;
    > q->next = NULL;
    >
    > works really good, but this one:
    >
    > struct lista a;
    > a.num = n;
    > a.next = NULL;
    >
    > does not?? This last code let my while ends never! And i ould the
    > reason, look at this gdb output:

    [snip]
    > As you can see, the last 4 outputs show the reason of the infinite
    > loop.... But i ask.... why?


    You've shown us the code that initializes the struct object, but you
    haven't shown us either the declaration of the struct type itself or
    the code that traverses the list. Without seeing the code, we can't
    possibly guess what might be causing the problem. Well, maybe we
    could; if I spent enough time studying your description and your gdb
    output, I might be able to reconstruct what's going on. But I'm not
    going to expend the effort.

    Post a complete program (compilable and executable) that illustrates
    your problem. Tell us what you expected it to do, what it actually
    did, and how those differ. Try to keep your program fairly small.

    (And it's spelled "you", not "u". This is a newsgroup, not a chat
    room.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Dec 30, 2008
    #2
    1. Advertising

  3. __PaTeR

    __PaTeR Guest

    sorry for the 'u', writing fast i often forget the 'yo' :\

    And also sorry for the rest of the code: here it's the compilable:

    I first tried to apply the structs in an already-functional program,
    but when i figured out thing were getting dirty, i wrote a test
    program to expecially study lists:

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

    struct lista {
    int num;
    struct lista *next;
    };

    void stampa(struct lista *list) {
    struct lista *i;
    for(i = list; i != NULL; i=i->next )
    printf("%d\n", i->num);
    }

    void inserisci(struct lista *p, int n)
    {
    struct lista *q = malloc(sizeof(struct lista));
    q->num=n;
    q->next = NULL;
    p->next = &a;
    }


    void appendi(int num, struct lista *q) {
    while ( q->next != NULL && q->next->num < num) {
    q = q->next;
    }
    inserisci(q, num);
    }

    int main() {
    struct lista *a = malloc(sizeof(struct lista));
    a->next = NULL;
    appendi(1, a);
    appendi(5, a);
    appendi(9, a);
    stampa(a);

    return 0;
    }

    Function and structs names are in italian... but i think code is
    obviously readable to everyone.
    __PaTeR, Dec 30, 2008
    #3
  4. __PaTeR <> writes:
    > sorry for the 'u', writing fast i often forget the 'yo' :\
    >
    > And also sorry for the rest of the code: here it's the compilable:


    No, it isn't.

    [...]
    > void inserisci(struct lista *p, int n)
    > {
    > struct lista *q = malloc(sizeof(struct lista));
    > q->num=n;
    > q->next = NULL;
    > p->next = &a;
    > }

    [...]

    "a" is undeclared. Always copy-and-paste your code, making sure it's
    *exactly* the same code that you fed to the compiler. If you re-type
    it, you'll almost inevitably introduce errors, making it impossible
    for us to tell which problems actually occur in your original code.

    When I change "p->next = &a;" to "p->next = &q;", I get

    warning: assignment from incompatible pointer type

    When I change it to "p->next = q;", it compiles no diagnostics, and
    produces the following run-time output:

    0
    1
    5
    9

    Since you didn't, as I requested, tell us either what output you got
    or what output you expected, it's difficult to tell whether that's
    correct or not.

    A couple of notes on your code:

    You don't check whether malloc() succeeded. That's probably ok in a
    tiny demo like this, but you should at least add a comment saying that
    you've dropped any error checking.

    It appears that each time you append a new item to your linked list,
    you traverse from the head to the tail before appending it. This can
    be grossly inefficient for long lists. Either insert at the head, or
    keep track of the tail.

    The commonly recommended idiom for malloc is:

    ptr = malloc(sizeof *ptr);

    In your case:

    struct lista *q = malloc(sizeof *q);

    There will probably be some vocal disagreement on this point, but it
    has the advantage that you don't have to repeat the type, so there's
    no risk of getting it wrong.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Dec 30, 2008
    #4
  5. pete <> writes:
    > Keith Thompson wrote:
    >> __PaTeR <> writes:
    >>> sorry for the 'u', writing fast i often forget the 'yo' :\
    >>>
    >>> And also sorry for the rest of the code: here it's the compilable:

    >> No, it isn't.
    >> [...]
    >>> void inserisci(struct lista *p, int n)
    >>> {
    >>> struct lista *q = malloc(sizeof(struct lista));
    >>> q->num=n;
    >>> q->next = NULL;
    >>> p->next = &a;
    >>> }

    >> [...]
    >> "a" is undeclared. Always copy-and-paste your code, making sure it's
    >> *exactly* the same code that you fed to the compiler. If you re-type
    >> it, you'll almost inevitably introduce errors, making it impossible
    >> for us to tell which problems actually occur in your original code.
    >> When I change "p->next = &a;" to "p->next = &q;", I get
    >> warning: assignment from incompatible pointer type
    >> When I change it to "p->next = q;", it compiles no diagnostics, and
    >> produces the following run-time output:
    >> 0
    >> 1
    >> 5
    >> 9

    >
    > When *I* change it to "p->next = q;", it compiles no diagnostics, and
    > produces the following run-time output:
    >
    > -842150451
    > 1
    > 5
    > 9


    The first node in the list, allocated in main(), never has its "n"
    member initialized.

    It would be simpler to set up an initially empty list, and call
    appendi() for each node to be appended.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, Dec 31, 2008
    #5
  6. __PaTeR

    Guest

    On Dec 30, 4:27 pm, __PaTeR <> wrote:

    > These days i'm writing so much , now i was learning something about
    > lists... In my code i have a while loop that ends up only when the
    > NEXT member of the struct is equal to NULL; ( i'm just surfing in the
    > list )
    >
    > Finding some good resource about structures has been really hard, for
    > example, i found out by myself the difference between the 2 operators
    > [->] and . ... or at least i think i found it out.


    get a good text book. Eg. K&R

    > As i've seen through gdb and experiments, is that: when you declare a
    > struct this way:
    > struct lista a;
    >
    > To access the members u have to use the dot, and "a" doesn't contain
    > the pointer to the memory, but the memory itself, just like an
    > integer.
    >
    > Besides, if u declare it this way:
    > struct lista *q; /* = malloc... etc */
    >
    > q is just a pointer to a memory region, just like a char definition
    > ( char *a ). To access members you have to use the arrow -> .... don't
    > you?
    >
    > SO: why this
    >
    > struct lista *q = malloc(sizeof(struct lista));
    > q->num=n;
    > q->next = NULL;
    >
    > works really good, but this one:
    >
    > struct lista a;
    > a.num = n;
    > a.next = NULL;
    >
    > does not??


    there's no reason why the above "shouldn't work" (whatever /that/
    means).
    Post your code.

    > This last code let my while ends never! And i ould the
    > reason, look at this gdb output:


    <snip>

    I'd rather see your code

    --
    Nick Keighley
    , Dec 31, 2008
    #6
  7. On Wed, 31 Dec 2008 08:58:29 -0500, pete <>
    wrote:

    snip

    >/* BEGIN listi.c */
    >
    >#include <stdio.h>
    >#include <stdlib.h>
    >
    >struct listi {
    > struct listi *next;
    > int num;
    >};
    >
    >void stampi(struct listi *i)
    >{
    > while (i != NULL) {
    > printf("%d\n", i -> num);
    > i = i -> next;
    > }
    >}
    >
    >struct listi *appendi(struct listi **head, struct listi *tail, int data)
    >{
    > struct listi *node;
    >
    > node = malloc(sizeof *node);
    > if (node != NULL) {
    > node -> next = NULL;
    > node -> num = data;
    > if (*head != NULL) {


    On the first call (data == 1), *head is NULL.

    On the second call (data == 5), * head points to N1 but tail is still
    NULL.

    > tail -> next = node;


    On the second call, this dereferences a NULL tail and invokes
    undefined behavior.

    > } else {
    > *head = node;


    On the first call, *head is set to point to the first node (call it
    N1)

    > }
    > }
    > return node;
    >}
    >
    >void freei(struct listi *q)
    >{
    > struct listi *next_node;
    >
    > while (q != NULL) {
    > next_node = q -> next;
    > free(q);
    > q = next_node;
    > }
    >}
    >
    >int main(void)
    >{
    > struct listi *a = NULL;
    > struct listi *b = NULL;


    At no point is b ever changed.

    >
    > b = appendi(&a, b, 1);
    > b = appendi(&a, b, 5);
    > b = appendi(&a, b, 9);
    > stampi(a);
    > freei(a);
    > return 0;
    >}
    >
    >/* END listi.c */


    --
    Remove del for email
    Barry Schwarz, Dec 31, 2008
    #7
  8. On Wed, 31 Dec 2008 18:47:31 -0500, pete <>
    wrote:

    >Barry Schwarz wrote:
    >> On Wed, 31 Dec 2008 08:58:29 -0500, pete <>
    >> wrote:
    >>
    >> snip

    >
    >>> struct listi *appendi(struct listi **head, struct listi *tail, int data)
    >>> {
    >>> struct listi *node;
    >>>
    >>> node = malloc(sizeof *node);

    >
    >>> return node;
    >>> }

    >
    >> At no point is b ever changed.
    >>
    >>> b = appendi(&a, b, 1);
    >>> b = appendi(&a, b, 5);
    >>> b = appendi(&a, b, 9);

    >
    >(b) is assigned the return value from malloc,
    >which tends to be a different value each time that appendi is called.


    You're right and I have no idea why I missed it. Sorry for wasting
    your time.

    --
    Remove del for email
    Barry Schwarz, Jan 1, 2009
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Fogelklou
    Replies:
    36
    Views:
    1,376
    Chris Fogelklou
    Apr 20, 2004
  2. Andy Chambers
    Replies:
    1
    Views:
    385
    Daniel Dyer
    May 14, 2007
  3. Ehud Shapira
    Replies:
    20
    Views:
    1,127
    Ehud Shapira
    Jun 30, 2007
  4. slocum
    Replies:
    3
    Views:
    508
    slocum
    Apr 11, 2008
  5. John Reye
    Replies:
    28
    Views:
    1,368
    Tim Rentsch
    May 8, 2012
Loading...

Share This Page