C beginner: struct inside another struct...

Discussion in 'C Programming' started by Mark McIntyre, Apr 21, 2006.

  1. On Sat, 22 Apr 2006 00:37:27 +0000, in comp.lang.c , Yourko
    <> wrote:

    >struct _client{
    > int fd; // file descriptor
    > struct sockaddr_in sock_name;
    >} * client;
    >
    >Later in that program i do:
    >client = (struct _client *) malloc(sizeof(struct _client));


    The cast is not necessary in C, and can conceal an error. Don't put it
    in.

    >and later:
    >realloc(client, sizeof(struct _client);
    >
    >Here is my question: is my client pointer an array now?


    No, you've just pointed "client" at some different block of memory. If
    you want an array, declare one.

    struct client ** pclient;

    pclient = malloc( 3* sizeof *pclient); // alloc pointers
    pclient[0] = malloc(sizeof *pclient[0]); // alloc first array member.
    etc
    Mark McIntyre
    --
    "Debugging is twice as hard as writing the code in the first place.
    Therefore, if you write the code as cleverly as possible, you are,
    by definition, not smart enough to debug it."
    --Brian Kernighan
    Mark McIntyre, Apr 21, 2006
    #1
    1. Advertising

  2. Mark McIntyre

    Eric Sosman Guest

    Yourko wrote On 04/21/06 20:37,:
    > Hi there! I`me currently trying to write some simple programs in C.
    > For one such program i created globals.h file. In that file i defined a structure of type _client, and a pointer of that type:
    >
    > struct _client{
    > int fd; // file descriptor
    > struct sockaddr_in sock_name;
    > } * client;
    >
    > Later in that program i do:
    > client = (struct _client *) malloc(sizeof(struct _client));


    This is all right, but can be improved in a couple of
    ways. First, you can get rid of the cast: it isn't needed,
    it can prevent some compilers from issuing a helpful message
    about failing to include <stdlib.h>, and it's even possible
    for a mistaken cast to create an error where none existed
    before. Second, replace `sizeof(struct _client)' with the
    simpler `sizeof *client'. The advantage is that it's harder
    to mis-match the pointer and the size, as in

    struct message_header *header
    = malloc(sizeof(struct message_header));
    struct message_sender *sender
    = malloc(sizeof(struct message_sender));
    struct message_trailer *trailer
    = malloc(sizeof(struct message_header));

    With these two changes, you'd have

    client = malloc(sizeof *client);

    .... which is short, sweet, and the Officially Approved Way
    to use malloc() and friends.

    > and later:
    > realloc(client, sizeof(struct _client);


    I suspect you misunderstand realloc(). This does not
    add another `sizeof(struct _client)' bytes to the memory
    that `client' points to. Instead, it rearranges things so
    the old memory area is replaced with a new one, possibly
    larger or smaller. In this case you're asking for the same
    size that the memory area already has, which is pointless.

    Also, realloc() may need to move the memory to a new
    location as part of the rearrangement. If it does so, the
    old pointer is no longer useful: it points to the spot where
    something used to be, not to the new spot the something now
    occupies. realloc() returns a pointer to the new spot -- it
    may be the same as the original, but you can't count on that.
    You need to remember the returned pointer so you don't lose
    track of the memory if realloc() moves it.

    Assuming you're trying to add one more struct instance
    to the allocated memory, so `client' now points to the first
    of two adjacent instances, you'd use

    client = realloc(client, 2 * sizeof *client);

    (Note the rewriting of the `sizeof', as before.) But this is
    still not quite right, because realloc() can fail (just as
    malloc() can). If realloc() cannot come up with a big enough
    piece of memory to satisfy your request, it does nothing and
    returns NULL to let you know that it failed. Fine, you can
    check `client' for NULL after the call -- but if it's NULL,
    what then? If you're just going to issue an error message
    and terminate the program, perhaps things are all right. But
    if you're going to issue a message like "Sorry; can't handle
    any more clients at the moment" and keep on running, you are
    in trouble. Why? Because you no longer know where the original
    memory is! You've just wiped out `client', your only pointer
    to that memory, so you can't find the struct instance(s) that
    existed before the failed realloc(). They still exist, but
    you don't know where. This is known as a "memory leak."

    The way to plug the leak is to store realloc()'s value in
    a second pointer, check that pointer for NULL, and then only
    overwrite `client' if you know realloc() succeeded:

    struct _client *temp
    = realloc(client, 2 * sizeof *client);
    if (temp == NULL) {
    issue_regretful_message();
    return; /* or otherwise bail out */
    }
    /* Good! realloc() succeeded! */
    client = temp;

    > Here is my question: is my client pointer an array now? Can i now do:
    > client[1]->fd = 3;


    If you want the `fd' element of the second struct instance
    in the allocated memory area, you can write any of

    (client + 1)->fd = 3;
    (*(client + 1)).fd = 3;
    client[1].fd = 3;

    The third form is recommended.

    --
    Eric Sosman, Apr 21, 2006
    #2
    1. Advertising

  3. Mark McIntyre

    Flash Gordon Guest

    Yourko wrote:
    > Hi there! I`me currently trying to write some simple programs in C.
    > For one such program i created globals.h file. In that file i defined a structure of type _client, and a pointer of that type:


    Don't use names starting with underscores. Many of them are reserved in
    many contexts and it's not worth the effort of remembering the few
    instances where you are allowed to use them.

    > struct _client{
    > int fd; // file descriptor
    > struct sockaddr_in sock_name;
    > } * client;
    >
    > Later in that program i do:
    > client = (struct _client *) malloc(sizeof(struct _client));


    Don't cast the return value of malloc. It isn't required and can hide
    serious problems from the compiler. The generally advised form around
    here is:
    ptr = malloc(N * sizeof *ptr);
    Where N is the number of elements you want space for.

    > and later:
    > realloc(client, sizeof(struct _client);


    That is still only enough space for 1 entry, and you seem to be throwing
    away the pointer it returns!

    Post complete real compilable code in future. It makes helping you easier.

    > Here is my question: is my client pointer an array now? Can i now do:
    > client[1]->fd = 3;
    > for example?
    > Compiler (gcc-3.3.6-linux-gnu) says no. But if so, how to do such things?


    If you post a real complete small program showing the problem we might
    be able to answer. Also, the exact error message is helpful rather than
    just "it doesn't work" or similar statements.
    --
    Flash Gordon, living in interesting times.
    Web site - http://home.flash-gordon.me.uk/
    comp.lang.c posting guidelines and intro:
    http://clc-wiki.net/wiki/Intro_to_clc

    Inviato da X-Privat.Org - Registrazione gratuita http://www.x-privat.org/join.php
    Flash Gordon, Apr 21, 2006
    #3
  4. Mark McIntyre

    Michael Mair Guest

    Yourko schrieb:
    > Hi there! I`me currently trying to write some simple programs in C.
    > For one such program i created globals.h file. In that file i defined a structure of type _client, and a pointer of that type:
    >
    > struct _client{
    > int fd; // file descriptor
    > struct sockaddr_in sock_name;
    > } * client;


    Do not define objects or functions in headers unless you want to achieve
    something specific[*].
    Declare them in headers to "make them known" to every translation
    unit directly or indirectly including this header.

    I.e.
    ,-- globals.h -
    #ifndef H_GLOBALS_H
    #define H_GLOBALS_H
    /* include whatever is necessary for struct sockaddr_in */
    .....

    struct _client{
    int fd; // file descriptor
    struct sockaddr_in sock_name;
    };

    extern struct _client *client;
    .....
    #endif
    `----
    ,-- globals.c -
    #include "globals.h"
    #include <stddef.h>

    struct _client *client = NULL;
    .....
    `----

    This way, you have no structural problems at all -- otherwise,
    your programme may exhibit some unexpected behaviour (or may not
    link at all).

    [*] If you have to define variables or functions in headers, it
    is most of the time with internal linkage -- this is something
    completely different. And even these definitions can be wrapped
    into headers and be effectively "instantiated" outside of the
    header


    >
    > Later in that program i do:
    > client = (struct _client *) malloc(sizeof(struct _client));


    The cast is unnecessary and may hide an error (forgetting to
    #include <stdlib.h>); the "best practice" around here is
    client = malloc(sizeof *client);

    > and later:
    > realloc(client, sizeof(struct _client);


    You probably mean:
    tmp = realloc(client, sizeof *client);
    if (tmp == NULL) {
    /* Handle error and do not continue below */
    }
    client = tmp;

    > Here is my question: is my client pointer an array now? Can i now do:
    > client[1]->fd = 3;
    > for example?


    1) No, a pointer never is an array. A pointer may point to an element
    of an array. You allocated memory for a single struct _client instance,
    so your pointer effectively grants you access to an array of one struct
    _client.
    2) No, for client[1] you would have needed to allocate enough memory
    for at least two struct _client variables, e.g.
    tmp = realloc(client, NumberOfClients * sizeof *client);
    if (tmp == NULL) {
    /* Handle error and do not continue below */
    }
    client = tmp;

    If you have client pointing to storage sufficient to have more than
    one struct _client object, then always accompany client by a size
    telling how much "array elements" can be accessed via client.


    Cheers
    Michael
    --
    E-Mail: Mine is an /at/ gmx /dot/ de address.
    Michael Mair, Apr 21, 2006
    #4
  5. Mark McIntyre

    Yourko Guest

    Hi there! I`me currently trying to write some simple programs in C.
    For one such program i created globals.h file. In that file i defined a structure of type _client, and a pointer of that type:

    struct _client{
    int fd; // file descriptor
    struct sockaddr_in sock_name;
    } * client;

    Later in that program i do:
    client = (struct _client *) malloc(sizeof(struct _client));
    and later:
    realloc(client, sizeof(struct _client);

    Here is my question: is my client pointer an array now? Can i now do:
    client[1]->fd = 3;
    for example?
    Compiler (gcc-3.3.6-linux-gnu) says no. But if so, how to do such things?




    ---------------
    "Software is like sex: it is better when it is free."
    Linus Torvalds
    Yourko, Apr 22, 2006
    #5
  6. Mark McIntyre

    Yourko Guest

    On Fri, 21 Apr 2006 23:21:39 +0100
    Mark McIntyre <> wrote:

    > On Sat, 22 Apr 2006 00:37:27 +0000, in comp.lang.c , Yourko
    > <> wrote:
    >
    > >struct _client{
    > > int fd; // file descriptor
    > > struct sockaddr_in sock_name;
    > >} * client;
    > >
    > >Later in that program i do:
    > >client = (struct _client *) malloc(sizeof(struct _client));

    >
    > The cast is not necessary in C, and can conceal an error. Don't put it
    > in.
    >
    > >and later:
    > >realloc(client, sizeof(struct _client);
    > >
    > >Here is my question: is my client pointer an array now?

    >
    > No, you've just pointed "client" at some different block of memory. If
    > you want an array, declare one.
    >
    > struct client ** pclient;
    >
    > pclient = malloc( 3* sizeof *pclient); // alloc pointers
    > pclient[0] = malloc(sizeof *pclient[0]); // alloc first array member.
    > etc
    > Mark McIntyre
    > --
    > "Debugging is twice as hard as writing the code in the first place.
    > Therefore, if you write the code as cleverly as possible, you are,
    > by definition, not smart enough to debug it."
    > --Brian Kernighan


    Thanx, you helped me much!
    Now i almost completely understand pointers, dynamic memory and arrays :)


    ---------------
    "Software is like sex: it is better when it is free."
    Linus Torvalds
    Yourko, Apr 23, 2006
    #6
    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. nail
    Replies:
    0
    Views:
    1,529
  2. monkeydragon

    Struct inside a struct

    monkeydragon, Dec 18, 2005, in forum: C++
    Replies:
    3
    Views:
    17,832
    Rolf Magnus
    Dec 20, 2005
  3. Replies:
    3
    Views:
    550
  4. arnuld

    struct inside struct

    arnuld, Jul 23, 2011, in forum: C Programming
    Replies:
    5
    Views:
    728
    Kleuskes & Moos
    Jul 24, 2011
  5. none
    Replies:
    8
    Views:
    390
Loading...

Share This Page