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.