passing a dynamic number of strings to a function

E

Eps

Hi,

I need to pass a dynamic number of strings to a function, I can think of
two ways.

1) An array of char arrays, I would also make a note of the length of
top level array and pass that in to the function.

2) An array of char arrays, I would add an extra element to the top
level array and set it to null, then I know when to stop when iterating
through.

Both of these seem a bit fragile, especially if you have ever used any
of the nice containers in the c++ STL.

Are there any other ways I could do this ?.

Thanks.
 
G

Guest

I need to pass a dynamic number of strings to a function, I can think of
two ways.

1) An array of char arrays, I would also make a note of the length of
top level array and pass that in to the function.

2) An array of char arrays, I would add an extra element to the top
level array and set it to null, then I know when to stop when iterating
through.

Both of these seem a bit fragile, especially if you have ever used any
of the nice containers in the c++ STL.

Are there any other ways I could do this ?.

there are only really minor variants using raw C.

If you want something more robust you'll probably need
to wrap one of the above approaches in an ADT.

If you really wanted to you probably get close to the effect
of STL containers.

You could look for more robust string classes.

I probably write a fairly thin library to manipulate
the array of strings and scatter the magic assert dust liberally.
Then write a good test suite.

--
Nick Keighley

There are only two ways to live your life.
One is as though nothing is a miracle.
The other is as though everything is a miracle.
Albert Einstein
 
E

Eps

there are only really minor variants using raw C.

If you want something more robust you'll probably need
to wrap one of the above approaches in an ADT.

If you really wanted to you probably get close to the effect
of STL containers.

You could look for more robust string classes.

I probably write a fairly thin library to manipulate
the array of strings and scatter the magic assert dust liberally.
Then write a good test suite.

Thats kinda what I expected, I am not keen on implementing my own
container !.

I guess c arrays are by their nature powerful and fragile.

Cheers.
 
W

Wolfgang Draxinger

Eps said:
Hi,

I need to pass a dynamic number of strings to a function, I can
think of two ways.

1) An array of char arrays, I would also make a note of the
length of top level array and pass that in to the function.

2) An array of char arrays, I would add an extra element to the
top level array and set it to null, then I know when to stop
when iterating through.

Both of these seem a bit fragile, especially if you have ever
used any of the nice containers in the c++ STL.

Are there any other ways I could do this ?.

Use a robust container structure implemented in C. There are
ready to use libraries. One is the GLib (not to confuse with the
glibc) licenced under LGPL. And there is the more low
level 'libowfat', which is GPL.

Or you implement your own container, which is for this simple
task quite straightforward and done in well under 300 LOC.

Wolfgang
 
B

Bartc

Eps said:
Hi,

I need to pass a dynamic number of strings to a function, I can think of
two ways.

1) An array of char arrays, I would also make a note of the length of top
level array and pass that in to the function.

2) An array of char arrays, I would add an extra element to the top level
array and set it to null, then I know when to stop when iterating through.

Both of these seem a bit fragile, especially if you have ever used any of
the nice containers in the c++ STL.

I was going to say these both seem fairly solid ways of doing this,
especially (1).

But the other suggestions of building a small library to help out with
managing the array are also good, and I tried it out. The following was
quite painless to write in C (I've no idea what STL does, but I'd guess
get_string and put_string for random access would not go amiss):

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

struct tstring {char **data; int length;};
typedef struct tstring tstring;

void init_strings(tstring *ts) {
ts->data=NULL;
ts->length=0;
}

void delete_strings(tstring *ts){
int i;
for (i=1; i<=ts->length; ++i)
free(ts->data);

free(ts->data);

init_strings(ts);
}

int add_string(tstring *ts,char *s) {
char **p;
char *t;

if (s==NULL) return 0;

/* Assume I can realloc a NULL */
p=realloc(ts->data,((ts->length)+1)*sizeof(char*));
if (p==NULL) return 0;

t=malloc(strlen(s)+1);
if (t==NULL) return 0;

strcpy(t,s);

p[ts->length]=t;
++(ts->length);
ts->data=p;

return 1;
}

/* Test function */
void print_strings(char* caption,tstring ts) {
int i;

puts(caption);
for (i=0; i<ts.length; ++i)
printf("%d: \"%s\"\n",i,ts.data);
puts("");

}

int main (void) {
tstring strings;

init_strings(&strings);

add_string(&strings,"One");
add_string(&strings,"Two");
add_string(&strings,"Three");

print_strings("Strings:",strings);

delete_strings(&strings);

print_strings("Strings:",strings);
}
 
B

bert

Hi,

I need to pass a dynamic number of strings to a function, I can think of
two ways.

1) An array of char arrays, I would also make a note of the length of
top level array and pass that in to the function.

2) An array of char arrays, I would add an extra element to the top
level array and set it to null, then I know when to stop when iterating
through.

Method (1) is better because the called function
could pass any selected sub-block of its data to
another function, without having to copy it. If
you use method (2), then only trailing sub-blocks
could be passed so easily.
--
 
R

Richard

there are only really minor variants using raw C.

If you want something more robust you'll probably need
to wrap one of the above approaches in an ADT.

If you really wanted to you probably get close to the effect
of STL containers.

You could look for more robust string classes.

I probably write a fairly thin library to manipulate
the array of strings and scatter the magic assert dust liberally.
Then write a good test suite.

asserts suck. Don't use them. They dirty up code.
 
R

Richard

Eps said:
Thats kinda what I expected, I am not keen on implementing my own
container !.

I guess c arrays are by their nature powerful and fragile.

Cheers.

Nothing fragile about them at all. If you want horrible container like
functionality then use a head struct with a length and a pointer to an
array of char *. Trivial stuff for any half decent programmer. Possibly
a [double] linked list?

Quite what Nick Keighley meant with his asserts etc I have no idea since
your only real specification was to pass a bunch of strings to a
function.

Give us some idea of how you might want manipulate this array of strings.
 
E

Eps

Richard said:
Nothing fragile about them at all. If you want horrible container like
functionality then use a head struct with a length and a pointer to an
array of char *. Trivial stuff for any half decent programmer. Possibly
a [double] linked list?

Quite what Nick Keighley meant with his asserts etc I have no idea since
your only real specification was to pass a bunch of strings to a
function.

Give us some idea of how you might want manipulate this array of strings.

Ok well, my competence as a programmer aside, my main dislike about the
two methods I described is that without documentation either method
could confuse another programmer looking at the code cold.

I am not really doing anything with the strings, merely passing each one
away to another function.

Thanks for your help everybody.
 
R

Richard

Eps said:
Richard said:
Nothing fragile about them at all. If you want horrible container like
functionality then use a head struct with a length and a pointer to an
array of char *. Trivial stuff for any half decent programmer. Possibly
a [double] linked list?

Quite what Nick Keighley meant with his asserts etc I have no idea since
your only real specification was to pass a bunch of strings to a
function.

Give us some idea of how you might want manipulate this array of strings.

Ok well, my competence as a programmer aside, my main dislike about

I did not mean that as a slight. I meant it as in, well, it being a
fact. A null terminated array of char * is trivial stuff.
the two methods I described is that without documentation either
method could confuse another programmer looking at the code cold.

Not if its clean C. Anything can be hard if not documented. Certainly
some complex container suite for something so trivial would certainly
confuse someone else IMO.

Comment your code use clean variable names.
I am not really doing anything with the strings, merely passing each
one away to another function.

Even simpler.

char * strArray[] = {"hello", "there",NULL};

Anyone looping though that should not need any more pointers(!)/help
unless they are really, really new in which case they can ask here :-;
 
S

santosh

Eps said:
Thats kinda what I expected, I am not keen on implementing my own
container !.

I guess c arrays are by their nature powerful and fragile.

They're just primitive, not necessarily fragile. Look at Paul Hseih's
BStrlib library.
 
M

Mark Wooding

Eps said:
I need to pass a dynamic number of strings to a function, I can think
of two ways.

1) An array of char arrays, I would also make a note of the length of top
level array and pass that in to the function.

2) An array of char arrays, I would add an extra element to the top level
array and set it to null, then I know when to stop when iterating
through.

Array of char pointers, either null-terminated or with explicit length.
Single array of characters, containing concatenated null-terminated
strings with either an explicit length or a final empty-string. Any of
the above with a one-past-the-end pointer instead of a length.
Both of these seem a bit fragile, especially if you have ever used any
of the nice containers in the c++ STL.

They all rely on the caller doing something explicit to tell the
function how to detect the end of the input. There isn't a way around
this. Sorry.

-- [mdw]
 
R

Rafael

Eps escreveu:
Hi,

I need to pass a dynamic number of strings to a function, I can think of
two ways.

1) An array of char arrays, I would also make a note of the length of
top level array and pass that in to the function.

2) An array of char arrays, I would add an extra element to the top
level array and set it to null, then I know when to stop when iterating
through.

Both of these seem a bit fragile, especially if you have ever used any
of the nice containers in the c++ STL.

Are there any other ways I could do this ?.

Thanks.

#include <stdarg.h> ?

you can have a function like

int g_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format,args);
va_end(args);
return EXIT_WHATEVER;
}

And yes, you have access to every argument, one by one...

Rafael
 
Z

Zach

Eps escreveu:










#include <stdarg.h> ?

you can have a function like

int g_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format,args);
va_end(args);
return EXIT_WHATEVER;

}

And yes, you have access to every argument, one by one...

Rafael


Can you please post a complete program source code implementing this.
Thanks.

Zach
 
J

James Kuyper

Zach said:
Can you please post a complete program source code implementing this.

One problem with that function is that EXIT_WHATEVER is undefined. I'd
recommend the following modification:

int g_printf(const char *format, ...)
{
va_list args;
va_start(args, format);
int retval = vprintf(format,args);
va_end(args);

return retval;
}

Which this modification, g_printf() is a wrapper for vprintf() that
pointlessly behaves in exactly the same way as printf(); something that
would have been more obvious if a use case has been provided. As a
result, I don't see how this code can be considered to be a solution to
the OP's problem.

The following code shows how to write a function that takes a variable
number of string arguments and does something with each of them. Whether
or not such an approach would solve the OP's problem depends upon
precisely what he's trying to do.

void multi_string(size_t count, ...)
{
va_list args;
va_start(args, count);
while(count--)
{
char *pc = va_arg(args, char*);
// Code that processes the string pointed at by pc.
}
va_end(args);
}

I declared the function 'void' because it's too simplified to need a
return value; in real life you'd probably want to give it a return
value, if only an error code to indicate whether or not each of the
strings was processed correctly.

Use cases:

multi_string(3, "Tom", "Dick", "Harry");

multi_string(4, program_name, input_file, output_file, error_message);

Note the key disadvantage: while the number of arguments to the function
can vary from one call to the next, any given call to such a function
has to have a fixed number of arguments. I doubt that this is what was
meant when the OP referred to "a dynamic number of strings". However, if
it is, this approach would be workable.
 
R

Rafael

James Kuyper escreveu:
One problem with that function is that EXIT_WHATEVER is undefined. I'd

Ow sure. How can that pass by me? Since both FAILURE ans SUCCESS are
short to type then WHATEVER, why did I get this last one? I can't have
just left it to make the OP think about his return on failure options. I
feel so stupid.

Thank you Mr James Kuyper. You are right!!!!

You really saved the day. Now, the OP does not need to use google or
that useless reference manuals anymore.



I'm probably not ready to help on c.l.c. I'm too sweet. ;)

Rafael
 
J

James Kuyper

Rafael said:
James Kuyper escreveu:


Ow sure. How can that pass by me? Since both FAILURE ans SUCCESS are
short to type then WHATEVER, why did I get this last one? I can't have
just left it to make the OP think about his return on failure options. I
feel so stupid.

Sorry, you misunderstand my criticism. It was quite clear to me that you
wanted to leave EXIT_WHATEVER to be decided later. My actual criticism
was two-fold.

First of all, there was a perfectly obvious value to return, there was
no good reason for leaving the decision for later.

Secondly, with the obvious choice for the return value, your g_printf()
become a pointless duplicate for printf(); with any other return value,
it becomes a less-useful near-duplicate of printf(). I'm rather
surprised that you took more offense at my comment about EXIT_WHATEVER
than you did at my comment on the pointlessness of your code.
I'm probably not ready to help on c.l.c. I'm too sweet. ;)

My criticism of your code was quite mild, and not intended to be
offensive. If you felt hurt by my commentary, you need to either develop
a thicker skin, or stop going out in public.
 
E

Eps

James said:
Note the key disadvantage: while the number of arguments to the function
can vary from one call to the next, any given call to such a function
has to have a fixed number of arguments. I doubt that this is what was
meant when the OP referred to "a dynamic number of strings". However, if
it is, this approach would be workable.

OP here.

I think your solution would have worked well, I have decided to hard
code the strings in to the functions (I don't feel very good about it
but it is quite a specilized library anyway so it isn't as crazy as it
sounds).

Previously I was thinking about retrieving the strings from the
database, depending on different conditions the number of strings will
have varied, which is why I was looking for a robust way of passing a
dynamic number of strings to a function.

Thanks for your help everybody, you have given me a lot to think about.
 
R

Rafael

James Kuyper escreveu:
Sorry, you misunderstand my criticism. It was quite clear to me that you
wanted to leave EXIT_WHATEVER to be decided later. My actual criticism

Not later... never. Not by me, not by you.
First of all, there was a perfectly obvious value to return, there was
no good reason for leaving the decision for later.

I can't see the obvious return. Too many can change in OP code. What can
make us sure he will not return a char*? void*? typedef*?

Return value from fuction is way out of question scope. "passing a
dynamic number of strings to a function" tell's us everything about it.
Secondly, with the obvious choice for the return value, your g_printf()
become a pointless duplicate for printf(); with any other return value,

I just think printf is the best example to show how stdarg will deal
with unknow number of arguments. That makes the duplicate the most
important resource to find out if the solution fit the need or not.

My criticism of your code was quite mild, and not intended to be

I know... I was kidding on that one. Don't worry, some kidding it's just
my way to handle criticism. I'm not hurt at all.

Thanks for the joy, anyway

Rafael
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

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

Latest Threads

Top