passing arg char[X][Y] to function expecting (char**)

M

MackS

I've come across the following difficulty, related to questions 6.12,
6.13 and 6.18 in the FAQ, which I am unable to overcome:

void fun(char **array_of_strings, int num_elements);

int main(void)
{
char static_array_of_strings[NUM_STRINGS][MAX_STRING_LEN+1];

fun ((char**)&static_array_of_strings, NUM_STRINGS);

return 0;
}

This code compiles but is wrong (I get a segmentation fault). How can I
correctly call fun on static_array_of_strings?

I can't modify the prototype of fun() because it also receives "true"
char** (in the sense of dynamically allocated arrays of strings, ie,
both the number of elements in the array as well as the length of each
string are unknown size at compile time).

How can I pass static_array_of_strings to it? The way I read FAQ 6.18
suggests this is impossible and the prototype of fun() would have to
modified to include MAX_STRING_LEN+1.
Thank you for any help,

Mack
 
M

MackS

Let me add that, in the mean time, the work-around I have found is

void fun(char **array_of_strings, int num_elements);

int main(void)
{
char static_array_of_strings[NUM_STRINGS][MAX_STRING_LEN+1];

/* do other stuff * /

{
char* tmp_array_of_strings[NUM_STRINGS];
int i = 0;
for (; i < NUM_STRINGS; i++)
tmp_array_of_strings = static_array_of_strings;

fun (tmp_array_of_strings, NUM_STRINGS);

}

return 0;
}

Since fun() doesn't need to modify the (char*) pointers themselves,
this works. But is there a more elegant way of doing this?

Mack
 
E

E. Robert Tisdale

MackS said:
I've come across the following difficulty, related to questions 6.12,
6.13 and 6.18 in the FAQ, which I am unable to overcome:

void fun(char **array_of_strings, int num_elements);

This is the same as

void fun(char* array_of_strings[], int num_elements);
int main(int argc, char* argv[]) {

char static_array_of_strings[NUM_STRINGS][MAX_STRING_LEN+1];

fun((char**)&static_array_of_strings, NUM_STRINGS);

This should be something like

char* static_array_of_strings = {"s1", "s2", "s3"};
fun(static_array_of_strings, 3);
return 0;
}

This code compiles but is wrong (I get a segmentation fault).
How can I correctly call fun on static_array_of_strings?

I can't modify the prototype of fun() because it also receives "true"
char** (in the sense of dynamically allocated arrays of strings, ie,
both the number of elements in the array
as well as the length of each string
are unknown size at compile time).

How can I pass static_array_of_strings to it?
The way I read FAQ 6.18 suggests this is impossible
and the prototype of fun() would have to modified
to include MAX_STRING_LEN+1.

You can write

char* array_of_strings
= (char*)malloc(NUM_STRINGS*sizeof(char*));
for (size_t i = 0; i < NUM_STRINGS; ++i)
array_of_strings = &(static_array_of_strings[0]);
fun(array_of_strings, NUM_STRINGS);
free((void*)array_of_strings);

assuming that each array of char in static_array_of_strings
contains at least one '\0'.

If you have a C99 compiler, you could write a wrapper function:

void
fun2(size_t strings, size_t length,
char* static_array_of_strings[strings][length]) {
char* array_of_strings[strings];
for (size_t i = 0; i < strings; ++i)
array_of_strings = &(static_array_of_strings[0]);
fun(array_of_strings, strings);
}

using variable size arrays.
 
K

Keith Thompson

MackS said:
I've come across the following difficulty, related to questions 6.12,
6.13 and 6.18 in the FAQ, which I am unable to overcome:

void fun(char **array_of_strings, int num_elements);

int main(void)
{
char static_array_of_strings[NUM_STRINGS][MAX_STRING_LEN+1];

fun ((char**)&static_array_of_strings, NUM_STRINGS);

return 0;
}

This code compiles but is wrong (I get a segmentation fault). How can I
correctly call fun on static_array_of_strings?

fun() expects a pointer to an array of pointers.

static_array_of_strings is an array of array of characters; it
contains no pointers.

(Incidentally, the name "static_array_of_strings" is a bit misleading,
since it isn't static in any of the senses that C uses the term.)

If you want an array of pointers for fun() to chew on, you're going to
have to build it yourself. The workaround you describe in your
followup is actually a good solution.
 
K

Keith Thompson

E. Robert Tisdale said:
char* array_of_strings
= (char*)malloc(NUM_STRINGS*sizeof(char*));

char *array_of_strings = malloc(NUM_STRINGS * sizeof *array_of_strings);

[...]
free((void*)array_of_strings);

free(array_of_strings);

The cast is useless.

[...]
If you have a C99 compiler, you could write a wrapper function:
[...]

And if you don't, much of ERT's other code (which I haven't quoted)
won't compile (unless your compiler implements some C99 features as
extensions).
 
E

E. Robert Tisdale

Keith said:
free(array_of_strings);

The cast is useless.
> cat main.c
#include <stdlib.h>

int main(int argc, char* argv[]) {
const
char* p =(const char*)malloc(13);
free(p);
return 0;
}
> gcc -Wall -std=c99 -pedantic -o main main.c
main.c: In function `main':
main.c:6: warning: passing arg 1 of `free' \
discards qualifiers from pointer target type
And if you don't,

get one.
 
C

CBFalconer

MackS said:
I've come across the following difficulty, related to questions
6.12, 6.13 and 6.18 in the FAQ, which I am unable to overcome:

void fun(char **array_of_strings, int num_elements);

int main(void)
{
char static_array_of_strings[NUM_STRINGS][MAX_STRING_LEN+1];

fun ((char**)&static_array_of_strings, NUM_STRINGS);
return 0;
}

This code compiles but is wrong (I get a segmentation fault).
How can I correctly call fun on static_array_of_strings?
.... snip ...

How can I pass static_array_of_strings to it? The way I read FAQ
6.18 suggests this is impossible and the prototype of fun() would
have to modified to include MAX_STRING_LEN+1.

You can't. Fun is expecting a pointer to a pointer to a char. I
see no pointers in static_array_of_strings. (henceforth to be known
as sas)

If you don't need to modify the strings, you could use:

static const char *sas[] = {"string1",
"string2",
"string3",
"laststring"};

and call with fun(&sas, sizeof(sas)/sizeof(sas[0]));

If you do need to modify the strings, create the modifiable strings
and then gather pointers to them in sas.

char string1[MAX_STR_LEN] = "string1";
char string2[MAX_STR_LEN] = "string2";
char string3[MAX_STR_LEN] = "string3";
char laststring[MAX_STR_LEN] = "laststring";

char *sas[] = {&string1, &string2, &string3, &laststring};
 
C

Christian Kandeler

CBFalconer said:
char string1[MAX_STR_LEN] = "string1";
char string2[MAX_STR_LEN] = "string2";
char string3[MAX_STR_LEN] = "string3";
char laststring[MAX_STR_LEN] = "laststring";

char *sas[] = {&string1, &string2, &string3, &laststring};

The address operators in the last initializer seem wrong to me. They
indicate that we have an array of pointers to arrays, which is not
compatible with the left hand side. I'm curious, though: If we wanted to
leave the right hand side as it is, what would the lhs need to look like? I
can't seem to figure it out.


Christian
 
C

Christian Kandeler

Christian said:
char *sas[] = {&string1, &string2, &string3, &laststring};

[ ... ]
If we wanted to leave the right hand side as it is, what would the lhs
need to look like? I can't seem to figure it out.

Okay, I remembered there's cdecl. It looks like this:
char (*sas[])[MAX_STR_LEN]
According to the precedence rules, this makes perfect sense, but looking at
it, I never would have guessed that the outer brackets refer to the inner
arrays. I hope I'll never have to use such a construct.


Christian
 
K

Keith Thompson

E. Robert Tisdale said:
Keith said:
free(array_of_strings);
The cast is useless.
cat main.c
#include <stdlib.h>

int main(int argc, char* argv[]) {
const
char* p =(const char*)malloc(13);
free(p);
return 0;
}
gcc -Wall -std=c99 -pedantic -o main main.c
main.c: In function `main':
main.c:6: warning: passing arg 1 of `free' \
discards qualifiers from pointer target type

So what? There was no const in the previous code; the cast in your
free((void*)array_of_strings);
is indeed useless.
 
E

E. Robert Tisdale

Keith said:
The cast in your

free((void*)array_of_strings);

is indeed useless.

So what?
It doesn't hurt. It always works.
And I don't need to consider
whether array_of_strings points to a const or not.
 
R

Richard Bos

E. Robert Tisdale said:
So what?
It doesn't hurt.

_All_ superfluous casts hurt. Even if they do not hurt the compiler,
they hurt the programmer and the maintainer.

Richard
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top