By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,611 Members | 1,642 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,611 IT Pros & Developers. It's quick & easy.

Question about a pointer to an array of structs

P: n/a
Hi,
I wonder if anyone can help me, I've been headscratching for a few hours
over this.

Basically, I've defined a struct called cache_object:
struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

I plan to store an array of these which'll contain a cached list of
hostnames and IP addresses for a resolver part of my code.

To complicate matters, the array has to be available to child processes via
shm. Now, I'm pretty new to shm so I'm leaving that bit till last. Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];

HOSTNAME/IPSIZE/CACHESIZE are all #defined with integer values.

Now before I start work on the shm code I'm testing things with malloc()
because malloc will return a pointer to a piece of memory in the same way as
shmat(). (actually I wrote a load of shm code, couldn't get it to work and
removed it all in an attempt to get back to the root of the problem).

The problem I'm having, and this happened with my shm code as well was that
I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
as a sidenote, what should I typecast this to? I've tried:
cache = (struct *cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));

but I get "syntax error before '*' token" from gcc.. I've tried:
cache = (struct cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));
but I get "cast specifies array type"

Anyway, sizeof() should return the number of bytes I need to allocate in
order to store a CACHESIZE sized array of cache_object structs, correct?
Well, I thought so..

Running the following loop:

for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
}

With these #defines:
#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

Produces the following output:

cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
Segmentation fault (core dumped)

Strangely, decreasing CACHESIZE to 5 prevents the segfault and the program
runs as expected:

$ ./caching_logger
foo 127.0.0.1 foo
cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
cache: 4 ipaddr: hostname:

Any help with this would be very greatly appreciated, it's been driving me
nuts all day.

Incase anyone's interested, the code I'm working on sits on the end of a log
pipe from apache splitting out log lines for each vhost and logging them to
separate files, it also resolves IP addresses in the log lines to dns wait
time in apache itself. The main purpose of the program however is to
overcome apache's open file descriptor limit by requiring only one pipe to
this program - the program itself closes and re-opens each log file between
writes; less efficient, but necessary in the situation I run.

Below is the code I have so far (fork commented out to remove the need for
shm):

#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>

#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

struct cache_object (*cache)[CACHESIZE];
int *cachecount;

int main () {
char vhost[HOSTSIZE+1], ip[IPSIZE], line[2046], path[255],
finalhost[HOSTSIZE+1];
FILE *outstream;
struct in_addr iph;
struct hostent *hp;
int c;
signal(SIGCHLD, SIG_IGN);

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
cachecount = (int *) malloc(sizeof(int));
*cachecount=0;
while (!feof(stdin)) {
memset(vhost,0,255);
memset(ip,0,255);
memset(line,0,2046);
memset(path,0,255);
memset(finalhost,0,255);
fscanf(stdin, "%s %s ", vhost, ip);
fgets(line, 2046, stdin);
for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
}
// if (fork() == 0) {
sprintf(path,"/home/logs/access_logs/%s",vhost);
if (inet_aton(ip, &iph)) {
if ((hp=gethostbyaddr((const char *)&iph,
sizeof(struct in_addr), AF_INET)) != NULL) {
sprintf(finalhost,"%s",hp->h_name);
} else {
sprintf(finalhost,"%s",ip);
}
} else {
sprintf(finalhost,"%s",ip);
}
sprintf(cache[*cachecount]->ipaddr,"%s",ip);

sprintf(cache[*cachecount]->hostname,"%s",finalhost);
if (*cachecount < CACHESIZE) {
*cachecount = *cachecount + 1;
} else {
*cachecount=0;
}
outstream = fopen(path, "a");
if (outstream != NULL) {
fprintf(outstream,"%s %s",finalhost, line);
fclose(outstream);
}
// exit(0);
// }

}
exit(0);
}


--
~Kieran Simkin
Digital Crocus
http://digital-crocus.com/
Nov 14 '05 #1
Share this Question
Share on Google+
10 Replies


P: n/a

"Kieran Simkin" <ki****@digital-crocus.com> wrote in message
news:b1pcc.470$Xi.6@newsfe1-win...

Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];
OK so far.
HOSTNAME/IPSIZE/CACHESIZE are all #defined with integer values.

Now before I start work on the shm code I'm testing things with malloc()
because malloc will return a pointer to a piece of memory in the same way as shmat(). (actually I wrote a load of shm code, couldn't get it to work and
removed it all in an attempt to get back to the root of the problem).

The problem I'm having, and this happened with my shm code as well was that I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
cache = malloc(sizeof *cache);

-Mike
as a sidenote, what should I typecast this to?


Don't cast the return value from malloc(). Just
make sure you've #included <stdlib.h> for malloc()'s
prototype.

-Mike

Nov 14 '05 #2

P: n/a

"Kieran Simkin" <ki****@digital-crocus.com> wrote in message
news:b1pcc.470$Xi.6@newsfe1-win...

Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];
OK so far.
HOSTNAME/IPSIZE/CACHESIZE are all #defined with integer values.

Now before I start work on the shm code I'm testing things with malloc()
because malloc will return a pointer to a piece of memory in the same way as shmat(). (actually I wrote a load of shm code, couldn't get it to work and
removed it all in an attempt to get back to the root of the problem).

The problem I'm having, and this happened with my shm code as well was that I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
cache = malloc(sizeof *cache);

-Mike
as a sidenote, what should I typecast this to?


Don't cast the return value from malloc(). Just
make sure you've #included <stdlib.h> for malloc()'s
prototype.

-Mike

Nov 14 '05 #3

P: n/a
On Tue, 6 Apr 2004 03:52:41 +0100, "Kieran Simkin"
<ki****@digital-crocus.com> wrote:
Hi,
I wonder if anyone can help me, I've been headscratching for a few hours
over this.

Basically, I've defined a struct called cache_object:
struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

I plan to store an array of these which'll contain a cached list of
hostnames and IP addresses for a resolver part of my code.

To complicate matters, the array has to be available to child processes via
shm. Now, I'm pretty new to shm so I'm leaving that bit till last. Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];
This does indeed define a pointer to an array of CACHESIZE struct
chache_object. However, based on your code below, what you really
want is a pointer to a single struct which just happens to be the
first of an array of such struct. The obvious way to do this is
struct chache_object *cache;

HOSTNAME/IPSIZE/CACHESIZE are all #defined with integer values.

Now before I start work on the shm code I'm testing things with malloc()
because malloc will return a pointer to a piece of memory in the same way as
shmat(). (actually I wrote a load of shm code, couldn't get it to work and
removed it all in an attempt to get back to the root of the problem).

The problem I'm having, and this happened with my shm code as well was that
I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
as a sidenote, what should I typecast this to? I've tried:
cache = (struct *cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));

but I get "syntax error before '*' token" from gcc.. I've tried:
cache = (struct cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));
but I get "cast specifies array type"
You should very rarely ever need to cast the return from malloc and
this is not one of those times. If you included stdlib.h the compiler
will know that malloc returns a void* and be perfectly capable of
assigning that value to any object pointer variable you want.

While what you have in the first line will work, the recommended
approach is
cache = malloc(sizeof *cache);

If you change the definition of cache as I've recommended, then you
would need
cache = malloc(CACHESIZE * sizeof *cache);

Anyway, sizeof() should return the number of bytes I need to allocate in
order to store a CACHESIZE sized array of cache_object structs, correct?
Well, I thought so..
You thought correctly.

Running the following loop:

for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
Here is your problem.

cache is a pointer to an array of struct. Therefore cache[0] is
the array of struct itself. cache[1] would be a second array of
struct immediately following the first BUT you do not have such an
array. It only gets worse as you go up to cache[9]. All these
references after cache[0] attempt to evaluate to arrays that don't
exist. An overdose of undefined behavior.

As an aside, the reason this does not produce a syntax error is
that in most contexts the evaluation of an array expression (a
reference to an array without the necessary subscripts to specify a
particular element of the array) produces the address of the first
element of the array with type pointer to element. Therefore the
expression cache[c]->ipaddr evaluates exactly the same as
(&cache[c][0])->ipaddr. cache is a pointer to the array, cache[c] is
the array, cache[c][0] is the first element of the array and
&cache[c][0] is the address of the first element with type pointer to
struct. This is the correct type to appear to the left of the ->
operator.

If you change cache as recommended, your for loop will work as you
intend.

If you really want to leave cache as a pointer to an array, your
printf arguments should look like
printf(..., (*cache)[c].ipaddr,(*cache)[c].hostname);
cache is the pointer to the array, *cache is the array, (*cache)[c] is
the c-th element of the array with type struct, and the .ipaddr
selects the member of the struct.
}

With these #defines:
#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

Produces the following output:

cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
Segmentation fault (core dumped)

Strangely, decreasing CACHESIZE to 5 prevents the segfault and the program
runs as expected:
One of the more insidious manifestations of undefined behavior is to
appear as if everything is working properly.
$ ./caching_logger
foo 127.0.0.1 foo
cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
cache: 4 ipaddr: hostname:

Any help with this would be very greatly appreciated, it's been driving me
nuts all day.


snip code with no additional detail.
<<Remove the del for email>>
Nov 14 '05 #4

P: n/a
On Tue, 6 Apr 2004 03:52:41 +0100, "Kieran Simkin"
<ki****@digital-crocus.com> wrote:
Hi,
I wonder if anyone can help me, I've been headscratching for a few hours
over this.

Basically, I've defined a struct called cache_object:
struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

I plan to store an array of these which'll contain a cached list of
hostnames and IP addresses for a resolver part of my code.

To complicate matters, the array has to be available to child processes via
shm. Now, I'm pretty new to shm so I'm leaving that bit till last. Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];
This does indeed define a pointer to an array of CACHESIZE struct
chache_object. However, based on your code below, what you really
want is a pointer to a single struct which just happens to be the
first of an array of such struct. The obvious way to do this is
struct chache_object *cache;

HOSTNAME/IPSIZE/CACHESIZE are all #defined with integer values.

Now before I start work on the shm code I'm testing things with malloc()
because malloc will return a pointer to a piece of memory in the same way as
shmat(). (actually I wrote a load of shm code, couldn't get it to work and
removed it all in an attempt to get back to the root of the problem).

The problem I'm having, and this happened with my shm code as well was that
I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
as a sidenote, what should I typecast this to? I've tried:
cache = (struct *cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));

but I get "syntax error before '*' token" from gcc.. I've tried:
cache = (struct cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));
but I get "cast specifies array type"
You should very rarely ever need to cast the return from malloc and
this is not one of those times. If you included stdlib.h the compiler
will know that malloc returns a void* and be perfectly capable of
assigning that value to any object pointer variable you want.

While what you have in the first line will work, the recommended
approach is
cache = malloc(sizeof *cache);

If you change the definition of cache as I've recommended, then you
would need
cache = malloc(CACHESIZE * sizeof *cache);

Anyway, sizeof() should return the number of bytes I need to allocate in
order to store a CACHESIZE sized array of cache_object structs, correct?
Well, I thought so..
You thought correctly.

Running the following loop:

for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
Here is your problem.

cache is a pointer to an array of struct. Therefore cache[0] is
the array of struct itself. cache[1] would be a second array of
struct immediately following the first BUT you do not have such an
array. It only gets worse as you go up to cache[9]. All these
references after cache[0] attempt to evaluate to arrays that don't
exist. An overdose of undefined behavior.

As an aside, the reason this does not produce a syntax error is
that in most contexts the evaluation of an array expression (a
reference to an array without the necessary subscripts to specify a
particular element of the array) produces the address of the first
element of the array with type pointer to element. Therefore the
expression cache[c]->ipaddr evaluates exactly the same as
(&cache[c][0])->ipaddr. cache is a pointer to the array, cache[c] is
the array, cache[c][0] is the first element of the array and
&cache[c][0] is the address of the first element with type pointer to
struct. This is the correct type to appear to the left of the ->
operator.

If you change cache as recommended, your for loop will work as you
intend.

If you really want to leave cache as a pointer to an array, your
printf arguments should look like
printf(..., (*cache)[c].ipaddr,(*cache)[c].hostname);
cache is the pointer to the array, *cache is the array, (*cache)[c] is
the c-th element of the array with type struct, and the .ipaddr
selects the member of the struct.
}

With these #defines:
#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

Produces the following output:

cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
Segmentation fault (core dumped)

Strangely, decreasing CACHESIZE to 5 prevents the segfault and the program
runs as expected:
One of the more insidious manifestations of undefined behavior is to
appear as if everything is working properly.
$ ./caching_logger
foo 127.0.0.1 foo
cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
cache: 4 ipaddr: hostname:

Any help with this would be very greatly appreciated, it's been driving me
nuts all day.


snip code with no additional detail.
<<Remove the del for email>>
Nov 14 '05 #5

P: n/a
In article <news:b1pcc.470$Xi.6@newsfe1-win>
Kieran Simkin <ki****@digital-crocus.com> writes:
struct cache_object (*cache)[CACHESIZE];
Note that the only real use for this kind of pointer is:

cache = malloc(n * sizeof *cache);
if (cache == NULL) ... handle error ...
... now work with cache[i][j], where i is in [0..n) and
j is in [0..CACHESIZE) ...

In other words, this pointer points to the first of n arrays,
so that cache[i] is an array. Each such array -- each cache[i]
-- has CACHESIZE elements, and each cache[i][j] is a "struct
cache_object".

If you want each cache[i] to be a "struct cache_object", rather
than an array (of size CACHESIZE) of such objects, just use:

struct cache_object *cache;

You can then allocate n of them (whether n is CACHESIZE or any
other value) with the exact same allocation pattern:

cache = malloc(n * sizeof *cache);

Calls to malloc() should almost always look just like that -- the
only change might be the variable name, or you might omit "n" if
n is exactly 1:

p = malloc(sizeof *p);
q = malloc(3 * sizeof *q);
*r = malloc(sizeof **r);

There is always one more "*" on the "sizeof" than there is on the
left, so since the last one sets *r (not r) it needs sizeof **r
(not sizeof *r).
#include <sys/types.h>
#include <netinet/in.h>
This code is rather OS-dependent, but there are other "pure C" issues
here. The one that immediately leaped out at me is:
while (!feof(stdin)) { [code that reads from stdin] }


A "while (!feof(...))" loop is almost always wrong. The feof()
function does not even attempt to predict whether EOF will occur
in the future when you try to read. It only "post-dicts" whether
EOF has *already happened*. It does not forecast the earthquake;
it tells you whether the damage you see, upon discovering a problem,
was due to an earthquake.

To read input from anything -- a person (via an "interactive"
device), or a network connection, or a local disk file -- you should
just try to read. If the read fails, *then* you can ask: "did
that read just fail because of EOF?" That is what feof() will tell
you. If the read has not yet failed, do not ask why it failed;
feof() cannot possibly tell you.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #6

P: n/a
In article <news:b1pcc.470$Xi.6@newsfe1-win>
Kieran Simkin <ki****@digital-crocus.com> writes:
struct cache_object (*cache)[CACHESIZE];
Note that the only real use for this kind of pointer is:

cache = malloc(n * sizeof *cache);
if (cache == NULL) ... handle error ...
... now work with cache[i][j], where i is in [0..n) and
j is in [0..CACHESIZE) ...

In other words, this pointer points to the first of n arrays,
so that cache[i] is an array. Each such array -- each cache[i]
-- has CACHESIZE elements, and each cache[i][j] is a "struct
cache_object".

If you want each cache[i] to be a "struct cache_object", rather
than an array (of size CACHESIZE) of such objects, just use:

struct cache_object *cache;

You can then allocate n of them (whether n is CACHESIZE or any
other value) with the exact same allocation pattern:

cache = malloc(n * sizeof *cache);

Calls to malloc() should almost always look just like that -- the
only change might be the variable name, or you might omit "n" if
n is exactly 1:

p = malloc(sizeof *p);
q = malloc(3 * sizeof *q);
*r = malloc(sizeof **r);

There is always one more "*" on the "sizeof" than there is on the
left, so since the last one sets *r (not r) it needs sizeof **r
(not sizeof *r).
#include <sys/types.h>
#include <netinet/in.h>
This code is rather OS-dependent, but there are other "pure C" issues
here. The one that immediately leaped out at me is:
while (!feof(stdin)) { [code that reads from stdin] }


A "while (!feof(...))" loop is almost always wrong. The feof()
function does not even attempt to predict whether EOF will occur
in the future when you try to read. It only "post-dicts" whether
EOF has *already happened*. It does not forecast the earthquake;
it tells you whether the damage you see, upon discovering a problem,
was due to an earthquake.

To read input from anything -- a person (via an "interactive"
device), or a network connection, or a local disk file -- you should
just try to read. If the read fails, *then* you can ask: "did
that read just fail because of EOF?" That is what feof() will tell
you. If the read has not yet failed, do not ask why it failed;
feof() cannot possibly tell you.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 14 '05 #7

P: n/a


Kieran Simkin wrote:
Hi,
I wonder if anyone can help me, I've been headscratching for a few hours
over this.

Basically, I've defined a struct called cache_object:
struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

I plan to store an array of these which'll contain a cached list of
hostnames and IP addresses for a resolver part of my code.

To complicate matters, the array has to be available to child processes via
shm. Now, I'm pretty new to shm so I'm leaving that bit till last. Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];

I believe you want:
struct cache_object *cache;
The problem I'm having, and this happened with my shm code as well was that
I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
as a sidenote, what should I typecast this to? I've tried:
cache = (struct *cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));

but I get "syntax error before '*' token" from gcc.. I've tried:
cache = (struct cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));
but I get "cast specifies array type"

You would probably want:
cache = malloc(CACHESIZE * sizeof(struct cache_object));
or
cache = malloc(CACHESIZE * (sizeof *cache));
Instead of one huge block allocation, perhaps you should dynamic
allocate the array in smaller blocks and increase the allocations
as you need. You can define a struct with a member representing
the array pointer and another member representing the number of
elements in the array. You can write functions to maintain the
struct object.

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

#define HOSTSIZE 32
#define IPSIZE 16
#define BLOCK 10

struct cache_object
{
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

struct cache_obj_arr
{
struct cache_object *array;
size_t count;
};

int addCache(struct cache_obj_arr *p, const char *hname,
const char *ip);
int createCacheArray(struct cache_obj_arr *p, size_t nelement);
void freeCache(struct cache_obj_arr *p);

int main(void)
{
struct cache_obj_arr cache = {NULL};

puts("Attempting to create an array of 12 cache_obj...\n");
if(createCacheArray(&cache, 12))
{
printf("A cache_obj array of %u elements has been created\n",
cache.count);
puts("cache.array points to the array.\n"
"cache.count keeps a count of the number of elements");
freeCache(&cache);
puts("The array was freed(deallocated)\n");
}
else puts("Failure in creating the array");
puts("A new array has been started");
addCache(&cache,"tom.harry.com","192.168.42.42");
printf("cache.array[0].hostname = \"%s\"\n"
"cahce.array[0].ipaddr = \"%s\"\n",
cache.array[0].hostname,cache.array[0].ipaddr);
freeCache(&cache);
return 0;
}

int addCache(struct cache_obj_arr *p, const char *hname,
const char *ip)
{
struct cache_object *tmp;

if(p->count%BLOCK == 0)
{
tmp = realloc(p->array,(p->count+BLOCK)*(sizeof *tmp));
if(tmp == NULL) return 0;
p->array = tmp;
}
strncpy(p->array[p->count].hostname,hname,HOSTSIZE);
p->array[p->count].hostname[HOSTSIZE] = '\0';
strncpy(p->array[p->count].ipaddr,ip,IPSIZE);
p->array[p->count++].ipaddr[IPSIZE] = '\0';
return 1;
}

int createCacheArray(struct cache_obj_arr *p, size_t nelement)
{
size_t cnt;

for(cnt = 0; cnt < nelement;cnt++)
if(!addCache(p,"","")) return 0;
return 1;
}

void freeCache(struct cache_obj_arr *p)
{
free(p->array);
p->array = NULL;
p->count = 0;
return;
}


--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #8

P: n/a


Kieran Simkin wrote:
Hi,
I wonder if anyone can help me, I've been headscratching for a few hours
over this.

Basically, I've defined a struct called cache_object:
struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

I plan to store an array of these which'll contain a cached list of
hostnames and IP addresses for a resolver part of my code.

To complicate matters, the array has to be available to child processes via
shm. Now, I'm pretty new to shm so I'm leaving that bit till last. Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];

I believe you want:
struct cache_object *cache;
The problem I'm having, and this happened with my shm code as well was that
I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
as a sidenote, what should I typecast this to? I've tried:
cache = (struct *cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));

but I get "syntax error before '*' token" from gcc.. I've tried:
cache = (struct cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));
but I get "cast specifies array type"

You would probably want:
cache = malloc(CACHESIZE * sizeof(struct cache_object));
or
cache = malloc(CACHESIZE * (sizeof *cache));
Instead of one huge block allocation, perhaps you should dynamic
allocate the array in smaller blocks and increase the allocations
as you need. You can define a struct with a member representing
the array pointer and another member representing the number of
elements in the array. You can write functions to maintain the
struct object.

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

#define HOSTSIZE 32
#define IPSIZE 16
#define BLOCK 10

struct cache_object
{
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

struct cache_obj_arr
{
struct cache_object *array;
size_t count;
};

int addCache(struct cache_obj_arr *p, const char *hname,
const char *ip);
int createCacheArray(struct cache_obj_arr *p, size_t nelement);
void freeCache(struct cache_obj_arr *p);

int main(void)
{
struct cache_obj_arr cache = {NULL};

puts("Attempting to create an array of 12 cache_obj...\n");
if(createCacheArray(&cache, 12))
{
printf("A cache_obj array of %u elements has been created\n",
cache.count);
puts("cache.array points to the array.\n"
"cache.count keeps a count of the number of elements");
freeCache(&cache);
puts("The array was freed(deallocated)\n");
}
else puts("Failure in creating the array");
puts("A new array has been started");
addCache(&cache,"tom.harry.com","192.168.42.42");
printf("cache.array[0].hostname = \"%s\"\n"
"cahce.array[0].ipaddr = \"%s\"\n",
cache.array[0].hostname,cache.array[0].ipaddr);
freeCache(&cache);
return 0;
}

int addCache(struct cache_obj_arr *p, const char *hname,
const char *ip)
{
struct cache_object *tmp;

if(p->count%BLOCK == 0)
{
tmp = realloc(p->array,(p->count+BLOCK)*(sizeof *tmp));
if(tmp == NULL) return 0;
p->array = tmp;
}
strncpy(p->array[p->count].hostname,hname,HOSTSIZE);
p->array[p->count].hostname[HOSTSIZE] = '\0';
strncpy(p->array[p->count].ipaddr,ip,IPSIZE);
p->array[p->count++].ipaddr[IPSIZE] = '\0';
return 1;
}

int createCacheArray(struct cache_obj_arr *p, size_t nelement)
{
size_t cnt;

for(cnt = 0; cnt < nelement;cnt++)
if(!addCache(p,"","")) return 0;
return 1;
}

void freeCache(struct cache_obj_arr *p)
{
free(p->array);
p->array = NULL;
p->count = 0;
return;
}


--
Al Bowers
Tampa, Fl USA
mailto: xa******@myrapidsys.com (remove the x to send email)
http://www.geocities.com/abowers822/

Nov 14 '05 #9

P: n/a
Great, thanks everybody. Got it working perfectly and I think I understand
pointers a little better now.
Interesting about casting the return value of malloc().. I've always thought
it was "good practice" to do this..

Again, thanks for your help.
~Kieran Simkin
Digital Crocus
http://digital-crocus.com/

"Kieran Simkin" <ki****@digital-crocus.com> wrote in message
news:b1pcc.470$Xi.6@newsfe1-win...
Hi,
I wonder if anyone can help me, I've been headscratching for a few hours
over this.

Basically, I've defined a struct called cache_object:
struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

I plan to store an array of these which'll contain a cached list of
hostnames and IP addresses for a resolver part of my code.

To complicate matters, the array has to be available to child processes via shm. Now, I'm pretty new to shm so I'm leaving that bit till last. Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];

HOSTNAME/IPSIZE/CACHESIZE are all #defined with integer values.

Now before I start work on the shm code I'm testing things with malloc()
because malloc will return a pointer to a piece of memory in the same way as shmat(). (actually I wrote a load of shm code, couldn't get it to work and
removed it all in an attempt to get back to the root of the problem).

The problem I'm having, and this happened with my shm code as well was that I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
as a sidenote, what should I typecast this to? I've tried:
cache = (struct *cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));

but I get "syntax error before '*' token" from gcc.. I've tried:
cache = (struct cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));
but I get "cast specifies array type"

Anyway, sizeof() should return the number of bytes I need to allocate in
order to store a CACHESIZE sized array of cache_object structs, correct?
Well, I thought so..

Running the following loop:

for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
}

With these #defines:
#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

Produces the following output:

cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
Segmentation fault (core dumped)

Strangely, decreasing CACHESIZE to 5 prevents the segfault and the program
runs as expected:

$ ./caching_logger
foo 127.0.0.1 foo
cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
cache: 4 ipaddr: hostname:

Any help with this would be very greatly appreciated, it's been driving me
nuts all day.

Incase anyone's interested, the code I'm working on sits on the end of a log pipe from apache splitting out log lines for each vhost and logging them to separate files, it also resolves IP addresses in the log lines to dns wait
time in apache itself. The main purpose of the program however is to
overcome apache's open file descriptor limit by requiring only one pipe to
this program - the program itself closes and re-opens each log file between writes; less efficient, but necessary in the situation I run.

Below is the code I have so far (fork commented out to remove the need for
shm):

#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>

#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

struct cache_object (*cache)[CACHESIZE];
int *cachecount;

int main () {
char vhost[HOSTSIZE+1], ip[IPSIZE], line[2046], path[255],
finalhost[HOSTSIZE+1];
FILE *outstream;
struct in_addr iph;
struct hostent *hp;
int c;
signal(SIGCHLD, SIG_IGN);

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
cachecount = (int *) malloc(sizeof(int));
*cachecount=0;
while (!feof(stdin)) {
memset(vhost,0,255);
memset(ip,0,255);
memset(line,0,2046);
memset(path,0,255);
memset(finalhost,0,255);
fscanf(stdin, "%s %s ", vhost, ip);
fgets(line, 2046, stdin);
for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
}
// if (fork() == 0) {
sprintf(path,"/home/logs/access_logs/%s",vhost);
if (inet_aton(ip, &iph)) {
if ((hp=gethostbyaddr((const char *)&iph,
sizeof(struct in_addr), AF_INET)) != NULL) {
sprintf(finalhost,"%s",hp->h_name); } else {
sprintf(finalhost,"%s",ip);
}
} else {
sprintf(finalhost,"%s",ip);
}
sprintf(cache[*cachecount]->ipaddr,"%s",ip);

sprintf(cache[*cachecount]->hostname,"%s",finalhost);
if (*cachecount < CACHESIZE) {
*cachecount = *cachecount + 1;
} else {
*cachecount=0;
}
outstream = fopen(path, "a");
if (outstream != NULL) {
fprintf(outstream,"%s %s",finalhost, line); fclose(outstream);
}
// exit(0);
// }

}
exit(0);
}


--
~Kieran Simkin
Digital Crocus
http://digital-crocus.com/

Nov 14 '05 #10

P: n/a
Great, thanks everybody. Got it working perfectly and I think I understand
pointers a little better now.
Interesting about casting the return value of malloc().. I've always thought
it was "good practice" to do this..

Again, thanks for your help.
~Kieran Simkin
Digital Crocus
http://digital-crocus.com/

"Kieran Simkin" <ki****@digital-crocus.com> wrote in message
news:b1pcc.470$Xi.6@newsfe1-win...
Hi,
I wonder if anyone can help me, I've been headscratching for a few hours
over this.

Basically, I've defined a struct called cache_object:
struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

I plan to store an array of these which'll contain a cached list of
hostnames and IP addresses for a resolver part of my code.

To complicate matters, the array has to be available to child processes via shm. Now, I'm pretty new to shm so I'm leaving that bit till last. Anyway,
in order to work with shm I need a pointer to an array of my struct
"cache_object". I've defined my pointer like this:

struct cache_object (*cache)[CACHESIZE];

HOSTNAME/IPSIZE/CACHESIZE are all #defined with integer values.

Now before I start work on the shm code I'm testing things with malloc()
because malloc will return a pointer to a piece of memory in the same way as shmat(). (actually I wrote a load of shm code, couldn't get it to work and
removed it all in an attempt to get back to the root of the problem).

The problem I'm having, and this happened with my shm code as well was that I can't seem to figure out how much memory I should be allowing myself to
store this array of structs. Here's the code I've got:

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
as a sidenote, what should I typecast this to? I've tried:
cache = (struct *cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));

but I get "syntax error before '*' token" from gcc.. I've tried:
cache = (struct cache_object[CACHESIZE]) malloc(sizeof(struct
cache_object[CACHESIZE]));
but I get "cast specifies array type"

Anyway, sizeof() should return the number of bytes I need to allocate in
order to store a CACHESIZE sized array of cache_object structs, correct?
Well, I thought so..

Running the following loop:

for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
}

With these #defines:
#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

Produces the following output:

cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
Segmentation fault (core dumped)

Strangely, decreasing CACHESIZE to 5 prevents the segfault and the program
runs as expected:

$ ./caching_logger
foo 127.0.0.1 foo
cache: 0 ipaddr: hostname:
cache: 1 ipaddr: hostname:
cache: 2 ipaddr: hostname:
cache: 3 ipaddr: hostname:
cache: 4 ipaddr: hostname:

Any help with this would be very greatly appreciated, it's been driving me
nuts all day.

Incase anyone's interested, the code I'm working on sits on the end of a log pipe from apache splitting out log lines for each vhost and logging them to separate files, it also resolves IP addresses in the log lines to dns wait
time in apache itself. The main purpose of the program however is to
overcome apache's open file descriptor limit by requiring only one pipe to
this program - the program itself closes and re-opens each log file between writes; less efficient, but necessary in the situation I run.

Below is the code I have so far (fork commented out to remove the need for
shm):

#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>

#define HOSTSIZE 255
#define IPSIZE 255
#define CACHESIZE 10

struct cache_object {
char hostname[HOSTSIZE+1];
char ipaddr[IPSIZE+1];
};

struct cache_object (*cache)[CACHESIZE];
int *cachecount;

int main () {
char vhost[HOSTSIZE+1], ip[IPSIZE], line[2046], path[255],
finalhost[HOSTSIZE+1];
FILE *outstream;
struct in_addr iph;
struct hostent *hp;
int c;
signal(SIGCHLD, SIG_IGN);

cache = malloc(sizeof(struct cache_object[CACHESIZE]));
cachecount = (int *) malloc(sizeof(int));
*cachecount=0;
while (!feof(stdin)) {
memset(vhost,0,255);
memset(ip,0,255);
memset(line,0,2046);
memset(path,0,255);
memset(finalhost,0,255);
fscanf(stdin, "%s %s ", vhost, ip);
fgets(line, 2046, stdin);
for (c=0;c<CACHESIZE;c++) {
printf("cache: %i ipaddr: %s hostname:
%s\n",c,cache[c]->ipaddr,cache[c]->hostname);
}
// if (fork() == 0) {
sprintf(path,"/home/logs/access_logs/%s",vhost);
if (inet_aton(ip, &iph)) {
if ((hp=gethostbyaddr((const char *)&iph,
sizeof(struct in_addr), AF_INET)) != NULL) {
sprintf(finalhost,"%s",hp->h_name); } else {
sprintf(finalhost,"%s",ip);
}
} else {
sprintf(finalhost,"%s",ip);
}
sprintf(cache[*cachecount]->ipaddr,"%s",ip);

sprintf(cache[*cachecount]->hostname,"%s",finalhost);
if (*cachecount < CACHESIZE) {
*cachecount = *cachecount + 1;
} else {
*cachecount=0;
}
outstream = fopen(path, "a");
if (outstream != NULL) {
fprintf(outstream,"%s %s",finalhost, line); fclose(outstream);
}
// exit(0);
// }

}
exit(0);
}


--
~Kieran Simkin
Digital Crocus
http://digital-crocus.com/

Nov 14 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.