473,408 Members | 1,960 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,408 software developers and data experts.

Question about a pointer to an array of structs

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
10 4070

"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

"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
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
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
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 (40°39.22'N, 111°50.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
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 (40°39.22'N, 111°50.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


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


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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

36
by: Bhalchandra Thatte | last post by:
I am allocating a block of memory using malloc. I want to use it to store a "header" structure followed by structs in my application. How to calculate the alignment without making any assumption...
5
by: Kieran Simkin | last post by:
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; char ipaddr;...
1
by: mrhicks | last post by:
Hello all, I need some advice/help on a particular problem I am having. I have a basic struct called "indv_rpt_rply" that holds information for a particular device in our system which I will...
7
by: Kevin | last post by:
Hi al I have an interesting question.... I am working witha Win API this is the Function Public Declare Function EnumJobs Lib "winspool.drv" Alias "EnumJobsA" (ByVal hPrinter As Long, ByVal...
5
by: Zach | last post by:
When it is being said that, "value types are created on the stack or inline as part of an object". If a value type is created in an object, and that object is being called, the value type in that...
15
by: Paminu | last post by:
Still having a few problems with malloc and pointers. I have made a struct. Now I would like to make a pointer an array with 4 pointers to this struct. #include <stdlib.h> #include <stdio.h>...
14
by: Szabolcs Borsanyi | last post by:
Deal all, The type typedef double ***tmp_tensor3; is meant to represent a three-dimensional array. For some reasons the standard array-of-array-of-array will not work in my case. Can I...
0
by: mjaaland | last post by:
Hi! I've been working with DLLimports passing structs and various other parameters to unmanaged code. I had problems earlier sending pointer to structs to the unmanaged code, and this forum solved...
2
by: hal | last post by:
Hi, I'm trying to make an array of pointers to 'TwoCounts' structs, where the size of the array is arraySize. Right now I'm just mallocing enough space for all the pointers to the structs, and...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.