C beginner: struct inside another struct...

M

Mark McIntyre

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
 
E

Eric Sosman

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.
 
F

Flash Gordon

Yourko said:
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
 
M

Michael Mair

Yourko said:
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
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
 
Y

Yourko

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?
 
Y

Yourko

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 :)
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top