Allocating an array of char* - newbie

J

john

Hello,
I wrote thsi small program ; I am quite a newbie in this.

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


typedef struct argsArray
{

char* ip_addresses[];
int no_of_addresses;
} argsArray;


int main()
{
argsArray* argsArrayPtr = (argsArray*)malloc(sizeof (argsArray));
argsArrayPtr->no_of_addresses = 3;
argsArrayPtr->ip_addresses[0]="10.0.0.0";
argsArrayPtr->ip_addresses[1]="10.0.0.1";

printf("no_of_addresses %d\n",argsArrayPtr->no_of_addresses);

printf("argsArrayPtr->ip_addresses[0] = %s\n",argsArrayPtr->ip_addresses[0]);
printf("argsArrayPtr->ip_addresses[1] = %s\n",argsArrayPtr->ip_addresses[1]);

}

this program prints:

no_of_addresses 134514264
argsArrayPtr->ip_addresses[0] = 10.0.0.0
argsArrayPtr->ip_addresses[1] = 10.0.0.1

where no_of_addresses should be 3;
It is obviously a matter of performing malloc() to the ip_addresses[] array;
but what should I exactly do it ? I do not know the sizes of the IP addresses :
they can vary from 7 to 15 characters length .Moreover, I do not know the
number of elements (ip addresses) in that array ; it is filled in run time
from some file. (I do have an upper bound).


regards,
John
 
J

Jens.Toerring

john said:
I wrote thsi small program ; I am quite a newbie in this.
#include <stdio.h>
#include <stdlib.h>

typedef struct argsArray
{
char* ip_addresses[];

That's not valid C, you can't create an array of (char pointers) of
indeterminate size. What you will need here is a pointer to pointer
to char and, once you know how many pointers you need, you must
allocate enough for them. So make that

char **ip_addresses;
int no_of_addresses;
} argsArray;
int main()
{
argsArray* argsArrayPtr = (argsArray*)malloc(sizeof (argsArray));

It usually doesn't make too much sense to cast the return value of
malloc(). The conversion is done automatically for you and the cast
will keep the compiler from warning you if you forget to include
<stdlib.h> where malloc() is declared. Furthermore, you should make
it a habit to always check the return value - if malloc() fails it
returns a NULL pointer. But if you only need one of these structures
it probably would make more sense here to use a real structure here
instead of using a pointer and then allocating memory for it...
argsArrayPtr->no_of_addresses = 3;
argsArrayPtr->ip_addresses[0]="10.0.0.0";
argsArrayPtr->ip_addresses[1]="10.0.0.1";

Before you can do that you need to allocate memory for the pointers.
Do that e.g. by

if ( ( argsArrayPtr->ip_addresses =
malloc( 2 * sizeof *argsArrayPtr->ip_addresses ) )
== NULL ) {
fprintf( stderr, "Running out of memory\n" );
exit( EXIT_FAILURE );
}

If you want not just to assign some addresses of literal strings
(like you do in your example code) but copy strings you also will
have to allocate memory for the strings themselves and assign that
to the char pointers you got from the previous allocation.
printf("no_of_addresses %d\n",argsArrayPtr->no_of_addresses);

printf("argsArrayPtr->ip_addresses[0] = %s\n",argsArrayPtr->ip_addresses[0]);
printf("argsArrayPtr->ip_addresses[1] = %s\n",argsArrayPtr->ip_addresses[1]);
}

this program prints:
no_of_addresses 134514264
argsArrayPtr->ip_addresses[0] = 10.0.0.0
argsArrayPtr->ip_addresses[1] = 10.0.0.1
where no_of_addresses should be 3;
It is obviously a matter of performing malloc() to the ip_addresses[] array;
but what should I exactly do it ? I do not know the sizes of the IP
addresses: they can vary from 7 to 15 characters length.

Well, first thing you need to do is allocate memory for the pointers
to the strings. Then you have to allocate memory for the strings. If
you don't know how long a string is going to be but have an upper bound
allocate enough memory for the worst case (and don't forget about the
trailing '\0' character!) and, when you find that this was too pessi-
mistic, i.e. you don't need all of it, use realloc() to reduce the size
of the allocated memory.
Moreover, I do not know the number of elements (ip addresses) in that
array ; it is filled in run time from some file. (I do have an upper
bound).

Again, if you have an upper bound you can always start with the worst
case scenario and later get rid of the memory you don't need by using
realloc(). But you can also employ a different strategy: start with a
guess and, if that turns out to be too optimistic, increase the size
by also using realloc(). In the simplest case you could start of with
a pointer for just a single string and, if you find that there's one
more, just increase the size and repeat until you got all of them.
Unless this part of the program is used extremely often the impact one
the performance probably is going to be neglectable. Or start with a
guess, and if that turns out to be too small, double the size and
continue and repeat if necessary. - and when you're finished get rid
of the superfluous memory by a final call of realloc().

Here's some C code mixed with pseudo code using the simplest method,
i.e. increasing the array of char pointers each time you find that
there's still one more IP address to store:

#define MAX_IP_LENGTH 16

int ip_count = 0;

argsArrayPtr->ip_addresses = NULL;

do {
determine if there's another IP address
if ( no_more_IP_addresses )
break;

argsArrayPtr->ip_addresses =
realloc( argsArrayPtr->ip_addresses,
( ip_count + 1 ) * sizeof *argsArrayPtr->ip_addresses );

if ( argsArrayPtr->ip_addresses == NULL ) {
fprintf( stderr, "Running out of memory\n" );
exit( EXIT_FAILURE );
}

argsArrayPtr->ip_addresses[ ip_count ] = malloc( MAX_IP_LENGTH );

if ( argsArrayPtr->ip_addresses[ ip_count ] == NULL ) {
fprintf( stderr, "Running out of memory\n" );
exit( EXIT_FAILURE );
}

store address of new IP address string into 'the_new_ip_address';
strcpy( argsArrayPtr->ip_addresses[ ip_count ], the_new_ip_address );

argsArrayPtr->ip_addresses[ ip_count++ ] =
realloc( argsArrayPtr->ip_addresses[ ip_count ],
strlen( the_new_ip_address ) + 1 );
}

If you want to write that in a way where you are able to recover from
the case that you run out of memory instead of just exit()ing make sure
you store the pointer with the address of the memory you already own
before you call realloc(), otherwise you won't be able to deallocate
it anymore.
Regards, Jens
 
N

Neil Kurzman

john said:
Hello,
I wrote thsi small program ; I am quite a newbie in this.

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

typedef struct argsArray
{

char* ip_addresses[];
int no_of_addresses;
} argsArray;


int main()
{
argsArray* argsArrayPtr = (argsArray*)malloc(sizeof (argsArray));
argsArrayPtr->no_of_addresses = 3;
argsArrayPtr->ip_addresses[0]="10.0.0.0";
argsArrayPtr->ip_addresses[1]="10.0.0.1";

printf("no_of_addresses %d\n",argsArrayPtr->no_of_addresses);

printf("argsArrayPtr->ip_addresses[0] = %s\n",argsArrayPtr->ip_addresses[0]);
printf("argsArrayPtr->ip_addresses[1] = %s\n",argsArrayPtr->ip_addresses[1]);

}

this program prints:

no_of_addresses 134514264
argsArrayPtr->ip_addresses[0] = 10.0.0.0
argsArrayPtr->ip_addresses[1] = 10.0.0.1

where no_of_addresses should be 3;
It is obviously a matter of performing malloc() to the ip_addresses[] array;
but what should I exactly do it ? I do not know the sizes of the IP addresses :
they can vary from 7 to 15 characters length .Moreover, I do not know the
number of elements (ip addresses) in that array ; it is filled in run time
from some file. (I do have an upper bound).

regards,
John

You do realize that standard IP address can be stored as 4 bytes
ie
byte[0] =10
byte[1] =0
byte[2] =0
byte[3] =0

people use 10.0.0.1 the computer uses 0x0A000000
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top