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

passing arrays of strings

P: n/a
Hi, I need to pass an array of strings to a function, but I can't get it
to work. This is what I wrote :

#include <stdio.h>

void a_function(char *blah[]) {

printf("%s %s %s", blah[0], blah[1], blah[2]);

}
main() {

char *blah[3];

strcpy(blah[0], "This");
strcpy(blah[1], "doesn't");
strcpy(blah[2], "work");

a_function(blah);

}

Note that I do not want to use

char *blah[3] = {"This", "doesn't", "work"};

because I need to create the strings on the fly.
Thanks very much
Colin.
colin _ doig AT hotmail DOT com

Nov 14 '05 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Colin Doig wrote:

Hi, I need to pass an array of strings to a function, but I can't get it
to work. This is what I wrote :

#include <stdio.h>

void a_function(char *blah[]) {

printf("%s %s %s", blah[0], blah[1], blah[2]);

}

main() {

char *blah[3];

strcpy(blah[0], "This");
strcpy(blah[1], "doesn't");
strcpy(blah[2], "work");

a_function(blah);

}

Note that I do not want to use

char *blah[3] = {"This", "doesn't", "work"};

because I need to create the strings on the fly.


/* BEGIN blah.c */

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

void a_function(char (*blah)[sizeof "doesn't"])
{
printf("%s %s %s\n", blah[0], blah[1], blah[2]);
}

int main(void)
{
char (*blah)[sizeof "doesn't"];

blah = malloc(3 * sizeof *blah);
if (blah) {
strcpy(blah[0], "This");
strcpy(blah[1], "doesn't");
strcpy(blah[2], "work");
a_function(blah);
free(blah);
}
return 0;
}

/* END blah.c */

--
pete
Nov 14 '05 #2

P: n/a
Colin Doig wrote:
Hi, I need to pass an array of strings to a function, but I can't get it
to work. This is what I wrote :

#include <stdio.h>

void a_function(char *blah[]) {

printf("%s %s %s", blah[0], blah[1], blah[2]);

}
main() {

char *blah[3];
This is an array of 3 pointers to char. None of the pointers has any
allocated memory assciated with it...
strcpy(blah[0], "This");
....so this...
strcpy(blah[1], "doesn't");
....and this... strcpy(blah[2], "work");
...and this...invokes undefined behavior.
a_function(blah);

}

Note that I do not want to use

char *blah[3] = {"This", "doesn't", "work"};

because I need to create the strings on the fly.


It depends what you mean by "on the fly". If you are, say, choosing your
strings from a collection of possibilites, setting those pointers to a
string literal (i.e. `blah[2] = "a possibilty";') is legitimate;
otherwise you'll have to allocate enough memory to each member of `blah'
to contain whatever you want to put in it (with one extra for the
trailing NUL).

HTH,
--ag
--
Artie Gold -- Austin, Texas

Nov 14 '05 #3

P: n/a
On Fri, 09 Jan 2004 14:23:11 +1300, Colin Doig
<no****@yourbusiness.com> wrote in comp.lang.c:
Hi, I need to pass an array of strings to a function, but I can't get it
to work. This is what I wrote :

#include <stdio.h>

void a_function(char *blah[]) {

printf("%s %s %s", blah[0], blah[1], blah[2]);

}
main() {
Implicit int is finally illegal under the current C standard. Best
make this:

int main()

....or even better:

int main(void)

char *blah[3];
This defines an array of three pointers to char. They are not
initialized and do not point to anything useful.

You could change this to:

char blah[3][25]; /* or some large enough number */

strcpy(blah[0], "This");
Calling strcpy() without having included <string.h> or otherwise
having a prototype in scope is undefined behavior. Trying to write to
memory through an uninitialized pointer is undefined behavior.
strcpy(blah[1], "doesn't");
strcpy(blah[2], "work");

a_function(blah);
Even without the implicit int return type on main(), you told the
compiler that your main() would return an int, then you lied and did
not return anything. Add:

return 0;
}

Note that I do not want to use

char *blah[3] = {"This", "doesn't", "work"};

because I need to create the strings on the fly.
Thanks very much
Colin.
colin _ doig AT hotmail DOT com


If there are a large number of strings and their length can vary
greatly, you could dynamically allocate the memory for each string
with malloc().

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #4

P: n/a

On Fri, 9 Jan 2004, pete wrote:

Colin Doig wrote:

Hi, I need to pass an array of strings to a function, but I can't get it
to work. This is what I wrote :

void a_function(char *blah[]) {
printf("%s %s %s", blah[0], blah[1], blah[2]);
} char *blah[3];

[and then pete wrote...]
void a_function(char (*blah)[sizeof "doesn't"])
{
printf("%s %s %s\n", blah[0], blah[1], blah[2]);
}

char (*blah)[sizeof "doesn't"];


Ye gods! Please, don't frighten the questioners! :) The OP
should note carefully that this code does *NOT* follow the same
design as the other couple of responses you've gotten, and I
think there's a reason for that. This way is bad. :)
Essentially, with two dimensions in your "array" of strings,
you have four different ways to design your data structure.
You can fix both dimensions:

char blah[3][sizeof "the longest string you'll encounter"];
strcpy(blah[0], "This");
strcpy(blah[1], "will");
strcpy(blah[2], "work");

You can fix the first dimension and let the second vary, as
others have suggested:

char *blah[3];
if ((blah[0] = malloc(sizeof "This")) != NULL);
strcpy(blah[0], "This");
if ((blah[1] = malloc(sizeof "will")) != NULL);
strcpy(blah[1], "will");
if ((blah[2] = malloc(sizeof "work")) != NULL);
strcpy(blah[2], "work");

You can vary the first dimension and fix the second, which
is what pete suggested, and will allow you to realloc() the
array as needed where the first two ways won't:

char (*blah)[sizeof "the longest string you'll encounter"];
blah = malloc(3 * sizeof *blah);
strcpy(blah[0], "This");
strcpy(blah[1], "will");
strcpy(blah[2], "work");

And finally you can vary both dimensions, which is IMHO often
the most extensible and useful solution, but does require more
bookkeeping. This is the structure with which 'argv' is defined
to work, by the way:

char **blah;
blah = malloc(3 * sizeof *blah);
if ((blah[0] = malloc(sizeof "This")) != NULL);
strcpy(blah[0], "This");
if ((blah[1] = malloc(sizeof "will")) != NULL);
strcpy(blah[1], "will");
if ((blah[2] = malloc(sizeof "work")) != NULL);
strcpy(blah[2], "work");

So there you have it. Four ways to do one simple thing, and
it's up to you to pick which one is right for this particular
problem you're solving.

HTH,
-Arthur

Nov 14 '05 #5

P: n/a

"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> wrote in message
news:Pi**********************************@unix46.a ndrew.cmu.edu...
You can fix the first dimension and let the second vary, as
others have suggested:

char *blah[3];
if ((blah[0] = malloc(sizeof "This")) != NULL);
strcpy(blah[0], "This");
if ((blah[1] = malloc(sizeof "will")) != NULL);
strcpy(blah[1], "will");
if ((blah[2] = malloc(sizeof "work")) != NULL);
strcpy(blah[2], "work");


Are those trailing semi-colons really valid? ;-)

Tom
Nov 14 '05 #6

P: n/a
Colin Doig wrote:
main() {

char *blah[3];

strcpy(blah[0], "This");
strcpy(blah[1], "doesn't");
strcpy(blah[2], "work");


That doesn't work, because you haven't allocated memory in blah to hold your
strings. Your code probably results in a segmentation violation --- that's
your clue that you're writing into memory improperly! The strcpy function just
copies characters from one location in memory to another, and in this case you
haven't allocated space at the destination.

One way to fix this is to allocate the memory manually. This will allow blah[0]
to store a string up to 1023 characters long:

blah[0] = (char *)malloc(1024);
strcpy(blah[0], "This");

Something more along the lines of what you wrote originally is to use "strdup",
which allocates enough memory to hold a copy of a string, and then copies the
string:

blah[0] = strdup("This"); // five bytes are allocated

That is equivalent to this:

blah[0] = (char *)malloc(strlen("this")+1);
strcpy(blah[0],"this");

HTH

Tobin


Nov 14 '05 #7

P: n/a

On Fri, 9 Jan 2004, Tom St Denis wrote:

"Arthur J. O'Dwyer" <aj*@nospam.andrew.cmu.edu> wrote...

if ((blah[0] = malloc(sizeof "This")) != NULL);
strcpy(blah[0], "This");
if ((blah[1] = malloc(sizeof "will")) != NULL);
strcpy(blah[1], "will");


Are those trailing semi-colons really valid? ;-)


Sure... who needs to do any complicated "branching", as long
as you've *tested* for NULL, right? :P

Whoops!

-Arthur
Nov 14 '05 #8

P: n/a
Tobin Fricke wrote:
Colin Doig wrote:
main() {

char *blah[3];

strcpy(blah[0], "This");
strcpy(blah[1], "doesn't");
strcpy(blah[2], "work");
That doesn't work, because you haven't allocated memory in blah
to hold your strings.


Correct.

<snip>
One way to fix this is to allocate the memory manually. This will allow
blah[0] to store a string up to 1023 characters long:

blah[0] = (char *)malloc(1024);
The cast is unnecessary (and can hide the bug of failing to #include
<stdlib.h>), but you really ought to test that the allocation succeeded
before you use it...

if(blah[0] != NULL)
{
strcpy(blah[0], "This");
If you're only using five bytes, why allocate 1024? After all, if you need
more later, you can always realloc.
Something more along the lines of what you wrote originally is to use
"strdup", which allocates enough memory to hold a copy of a string, and
then copies the string:
The C language does not specify a strdup function.

blah[0] = strdup("This"); // five bytes are allocated

That is equivalent to this:

blah[0] = (char *)malloc(strlen("this")+1);
strcpy(blah[0],"this");


Better:

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

char *dupstr(const char *s)
{
char *p = malloc(strlen(s) + 1);
if(p != NULL)
{
strcpy(p, s);
}
return p;
}

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #9

P: n/a


Colin Doig wrote:

.........snip..........
Note that I do not want to use

char *blah[3] = {"This", "doesn't", "work"};

because I need to create the strings on the fly.


If you want to dynamic create and array of strings, one
way to approach this would be to create a struct type
that will have the array and a count of the number of
strings in the array. You would write functions that will
manage this struct type, Write functions that will add
strings to the array , printing, removing, freeing
and others of interest.

An example:

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

typedef struct StrArray
{
char **name;
size_t count;
} StrArray;

typedef enum {FALSE, TRUE} bool;

bool AddName(StrArray *p,const char *s);
void FreeAllNames(StrArray *p);
void PrintNames(StrArray *p);
bool RemoveName(StrArray *p, size_t ele_num);

int main(void)
{
StrArray president = {NULL, 0};

AddName(&president, "George Washington");
AddName(&president, "Bill Clinton");
AddName(&president, "George Bush");
PrintNames(&president);
puts("\nRemoving Name #2\n");
RemoveName(&president,2);
PrintNames(&president);
FreeAllNames(&president);
return 0;
}

bool AddName(StrArray *p,const char *s)
{
char **tmp, *value;

if((tmp = realloc(p->name,(p->count+1)*(sizeof *tmp))) == NULL)
return FALSE;
if((value = malloc(strlen(s)+1)) == NULL) return FALSE;
strcpy(value,s);
tmp[p->count++] = value;
p->name = tmp;
return TRUE;
}

void FreeAllNames(StrArray *p)
{
size_t i;

for(i = 0;i < p->count;i++)
free(p->name[i]);
free(p->name);
p->name = NULL;
p->count = 0;
return;
}

void PrintNames(StrArray *p)
{
size_t i;

for(i = 0; i < p->count; i++)
printf("%u. %s\n",i+1,p->name[i]);
return;
}

bool RemoveName(StrArray *p, size_t ele_num)
{
size_t i;
char **tmp;

if(ele_num == 0 || ele_num > p->count) return FALSE;
i = ele_num-1;
free(p->name[i]);
if(ele_num != p->count)
memmove(&p->name[i], &p->name[i+1],
(p->count-ele_num)*sizeof(char *));
tmp = realloc(p->name,--p->count*(sizeof *tmp));
if(tmp) p->name = tmp;
return TRUE;
}

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

Nov 14 '05 #10

This discussion thread is closed

Replies have been disabled for this discussion.