two dimensional arrays passed to functions

R

Ruben

I'm trying to pass an array of string to a function without knowing how
many strings I have beforehand.

I've defined one functions as

char * insert(char table[256],int cols, char values[3][256]);

out of deperation because when I defined it as

char * insert(char table[255],int cols, char values)

I keep getting no data passed.

char * insert(char table[256],int cols, char values * [3]);

Gets me only one arguement passed. I thought I used to do this all the
time. In fact, main does this. I've loaded the entire source code I'm
working with onto htto://www.freedom-it.com/clinical.tgz ifd anyone wants
to look. The code is using GTK 2.x and MYSQL 4.0x for anyone interested.

Ruben
 
R

Ruben

out of deperation because when I defined it as

char * insert(char table[255],int cols, char values)

I keep getting no data passed.

Actually, I originally defined this function as
char * insert(char table[255],int cols, char **values)

Everything I'm reading seems to say I have to define this
as
char * insert(char table[255],int cols, char values[][256])

but main can be defined as int main (int argv, char **argc) without any
problem.

This is driving me crazy because I could sware I did this on SCO
compilers about 8 years ago without any trouble.

Ruben

<<I'm trying to pass an array of string to a function without knowing how
many strings I have beforehand.

I've defined one functions as

char * insert(char table[256],int cols, char values[3][256]);

out of deperation because when I defined it as

char * insert(char table[255],int cols, char values)

I keep getting no data passed.

char * insert(char table[256],int cols, char values * [3]);

Gets me only one arguement passed. I thought I used to do this all the
time. In fact, main does this. I've loaded the entire source code I'm
working with onto https://www.freedom-it.com/clinical.tgz ifd anyone wants
to look. The code is using GTK 2.x and MYSQL 4.0x for anyone interested.

Ruben>>
 
J

Jens.Toerring

Ruben said:
out of deperation because when I defined it as

char * insert(char table[255],int cols, char values)

I keep getting no data passed.

Actually, I originally defined this function as
char * insert(char table[255],int cols, char **values)
Everything I'm reading seems to say I have to define this
as
char * insert(char table[255],int cols, char values[][256])
but main can be defined as int main (int argv, char **argc) without any
problem.
This is driving me crazy because I could sware I did this on SCO
compilers about 8 years ago without any trouble.

Sorry, but the URL you gave for the code doesn't work. The main
question is: what exactly is it that you want to pass to the
function? From what you write it looks as if in the caller you
have the 'value' array defined as

char values[ N ][ 256 ];

where I don't know N but it doesn't really matter. If that is the case
then the form

char * insert(char table[255],int cols, char values[][256])

looks reasonable. The difference to the way argv is used is comes
from argv not being a 2-dimensional array but a 1-dimensional array
of char pointers. I.e. argv is defined similar to this

char *x[ M ];

Each of the M pointers may point to a different string. And that's not
a 2-dimensional array - it only has room for M char pointers and nothing
more. All the strings pointed to must get their memory independently of
that definition

If you now pass something like argv to a function what the function
gets is a pointer to the first element of this array, i.e. a pointer
to the first pointer - that's why argv can be written as either
"char **argv" or "char *argv[ ]" in the call of main().

On the other hand

char values[ N ][ 256 ];

has room for N strings, each 256 chars long. And it does not get
converted to a pointer to pointer when passed to a function, since
it's not a 1-dimensional array (what the function actually gets can
be treated as a pointer to the first char in the first string, so
you could define the function as

char * insert(char table[255],int cols, char *values)

But that has the obvious drawback that then the compiler has no idea
where the strings start and you have to calculate that all by yourself,
i.e. the start of the n-th string would then be (value + n * 256) if
you start counting at 0.
Regards, Jens
 
R

Ruben

Ruben said:
out of deperation because when I defined it as

char * insert(char table[255],int cols, char values)

I keep getting no data passed.

Actually, I originally defined this function as char * insert(char
table[255],int cols, char **values)
Everything I'm reading seems to say I have to define this as char *
insert(char table[255],int cols, char values[][256])
but main can be defined as int main (int argv, char **argc) without any
problem.
This is driving me crazy because I could sware I did this on SCO
compilers about 8 years ago without any trouble.

Sorry, but the URL you gave for the code doesn't work.

Someone else said that you me but it seems to be working now. Covad was
having some troubles over at tellhouse this morning

https://www.freedom-it.com/clinical.tgz is up currently

The main question
is: what exactly is it that you want to pass to the function? From what
you write it looks as if in the caller you have the 'value' array
defined as

char values[ N ][ 256 ];

where I don't know N but it doesn't really matter. If that is the case
then the form

char * insert(char table[255],int cols, char values[][256])

looks reasonable.

But it's not what I originally wanted. I'm quite sure and relooked at
old code on SCO and I used to just assign a char * to the address of the
array and then send it down as a single dimmensional array. This method
is dead appearently.

The difference to the way argv is used is comes from
argv not being a 2-dimensional array but a 1-dimensional array of char
pointers. I.e. argv is defined similar to this

char *x[ M ];
OK


Each of the M pointers may point to a different string.

x is a pointer to an array of chars.

And that's not a
2-dimensional array - it only has room for M char pointers and nothing
more.

But where is it allocated memory for the pointer address?
All the strings pointed to must get their memory independently of
that definition

Yes. I was using strcpy of string literals for that. In my main gtk
program, they are coming from editable text objects.

If you now pass something like argv to a function what the function gets
is a pointer to the first element of this array, i.e. a pointer to the
first pointer - that's why argv can be written as either "char **argv"
or "char *argv[ ]" in the call of main().

On the other hand

char values[ N ][ 256 ];
has room for N strings, each 256 chars long. And it does not get
converted to a pointer to pointer when passed to a function, since it's
not a 1-dimensional array (what the function actually gets can be
treated as a pointer to the first char in the first string, so you could
define the function as

char * insert(char table[255],int cols, char *values)

I thought I tried this variation and it failed.
I'll give it another run.
 
J

Jens.Toerring

Someone else said that you me but it seems to be working now. Covad was
having some troubles over at tellhouse this morning
https://www.freedom-it.com/clinical.tgz is up currently

Yep, got it now.
The main question
is: what exactly is it that you want to pass to the function? From what
you write it looks as if in the caller you have the 'value' array
defined as

char values[ N ][ 256 ];

where I don't know N but it doesn't really matter. If that is the case
then the form

char * insert(char table[255],int cols, char values[][256])

looks reasonable.
But it's not what I originally wanted. I'm quite sure and relooked at
old code on SCO and I used to just assign a char * to the address of the
array and then send it down as a single dimmensional array. This method
is dead appearently.

What exactly did you want? Please show a bit of real code, just describing
it in words tends to be too prone to misunderstandings.
The difference to the way argv is used is comes from
argv not being a 2-dimensional array but a 1-dimensional array of char
pointers. I.e. argv is defined similar to this

char *x[ M ];
Each of the M pointers may point to a different string.
x is a pointer to an array of chars.

No, x is an array of char pointers. Only if x is used in value context,
i.e. it's treated as if it would have a value, like for example when
used in a function call, it gets converted in this context (it "decays
to" as it's often called, see also <http://web.torek.net/torek/c/pa.html>)
to a pointer to the first element of this array, i.e. a pointer to the
first char pointer - that's what the called function sees of it if it
gets called like "f( x );".
But where is it allocated memory for the pointer address?

Which pointer address?
Yes. I was using strcpy of string literals for that. In my main gtk
program, they are coming from editable text objects.

Yes, but you're not working with an array of char pointers (like argv
is one) but with a two-dimensional array of chars (and that's why you
need to copy the strings and not just assign pointers to them).
If you now pass something like argv to a function what the function gets
is a pointer to the first element of this array, i.e. a pointer to the
first pointer - that's why argv can be written as either "char **argv"
or "char *argv[ ]" in the call of main().

On the other hand

char values[ N ][ 256 ];

has room for N strings, each 256 chars long. And it does not get
converted to a pointer to pointer when passed to a function, since it's
not a 1-dimensional array (what the function actually gets can be
treated as a pointer to the first char in the first string, so you could
define the function as

char * insert(char table[255],int cols, char *values)
I thought I tried this variation and it failed.
I'll give it another run.

Since in the caller you have

char *error;
char table[ ] = "patient";
char cols[ 3 ][ 256 ] = { { '\0' }, { '\0' }, { '\0' } };

strcpy( cols[ 0 ], patient.first );
strcpy( cols[ 1 ], patient.last );
strcpy( cols[ 2 ], patient.mrn );
error = insert( table, 3, cols );

the correct way to define the function, as far as I can see would be

char *insert( char table[ ], int cols, char values[ ][ 256 ] )

or

char *insert( char *table, int cols, char values[ ][ 256 ] )

(Please note that there isn't a 3 as the first dimension for
'values' here since it looks like you want to be able to get the
function to work with an unspecified number of strings, otherwise
you wouldn't have to pass the number if strings in the 'cols'
variable to the function. And there's also no explicit size for
the length of 'table' since you don't know in advance, it's definitely
not 255. Finally, in your insert_patient() function you use the type
'gchar' for 'table' and '*error' but your insert() function expects
and returns 'char', which doesn't look right.)

Since you don't seem to change neither 'table' nor any of the strings
from 'values' within the insert() function it might make sense to
make that clear by using

char *insert( const char *table, int cols, const char values[ ][ 256 ] )

And if this will stay that way (i.e. none of the strings is ever going
to be changged from within insert()) you could even get rid of copying
all that strings from the 'patient' structure to the 'cols' matrix.
You could use an array of char pointers here and just do

char *error;
char *table = "patient";
char *cols[ ] = { patient.first, patient.last, patient,mrn };

error = insert( table, sizeof cols / sizeof *cols, cols );

Then you would have to define the insert() function as

char *insert( const char *table, int cols, const char *cols[ ] );

i.e. use the same method by which argv is passed to main(). In that
case the 'cols' in insert() would be an array of char pointers, each
pointing to a string (you're not supposed to modify).

BTW, your insert() function is badly leaking memory - you call malloc()
twice there without ever freeing the memory you got. And, of course,
you should check the return value of malloc() and not blindly assume
that it did succeed. Actually, the 'value' array, for which you also
allocate memory is never used at all. Moreover, this part

strcpy( query,"INSERT INTO " );
strcat( query, table );
strcat( query, " VALUES (NULL,'" );
str_length = strlen( query );
end = query + str_length;
str_length = strlen( query );
end = query + str_length;

looks strange - the two last lines look wrong because they make 'end'
point way beyond the end of the 'query' string. Actually, you could
do all you need to do in a single line, i.e.

end = query + sprintf( query, "INSERT INTO %s VALUES (NULL,'", table );

Also the following code won't work correctly:

for ( i = 0; i < cols; i++ )
{
end += mysql_real_escape_string( clinical_db, end, values[ i ],
strlen( values[ i ] ) );
*end++ = '\'';
*end++ = ',';
*end++ = '\'';
}

str_length = strlen( end ) - 2;
end[ str_length ] = ')';
str_length++;
end[ str_length ] = '\0';

If you get out of that loop, 'end' doesn't point to a '\0' terminated
string, so applying strlen() to it won't work. All you actually need
here is

*( end - 2 ) = ')';
*( end - 1 ) = '\0';

Regards, Jens
 
A

Al Bowers

Ruben said:
out of deperation because when I defined it as

char * insert(char table[255],int cols, char values)

I keep getting no data passed.


Actually, I originally defined this function as
char * insert(char table[255],int cols, char **values)

Everything I'm reading seems to say I have to define this
as
char * insert(char table[255],int cols, char values[][256])

but main can be defined as int main (int argv, char **argc) without any
problem.

Do you have a fixed array or do you have dynamic allocations?

I tend to enclose the array and the number of elements in a struct
and dynamically insert strings into the array. You can allocate 1d with
the char buffer being fixed, i.e. 256, or you can allocate 2d.

The 1d struct:
struct STRINGARR
{
char (*String)[256];
size_t numelements;
};

The 2d struct:
struct STRINGARR
{
char **String;
size_t numelements;
};

The prototype for the insert function would be:
char *insert(struct STRINGARR *array, const char *newstring);

Here is an example of the 1d version:

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

#define STR_SZ 64

typedef struct STRINGARR
{
char (*String)[STR_SZ];
size_t numstrings;
} STRINGARR;
/* Prototypes */
char *InsertSTRINGARR(STRINGARR *p, const char *s);
void PrintSTRINGARR(const STRINGARR *p);
void FreeSTRINGARR(STRINGARR *p);

int main(void)
{
STRINGARR presidents = {NULL}; /* Neccessary */

InsertSTRINGARR(&presidents,"George Washington");
InsertSTRINGARR(&presidents,"Abe Lincoln");
InsertSTRINGARR(&presidents,"Bill Clinton");
InsertSTRINGARR(&presidents,"George Bush");
puts("The presidents in the string array are:");
PrintSTRINGARR(&presidents);
FreeSTRINGARR(&presidents);
return 0;
}

char *InsertSTRINGARR(STRINGARR *p, const char *s)
{
char (*tmp)[STR_SZ];

tmp = realloc(p->String,(sizeof *tmp)*(p->numstrings+1));
if(!tmp) return NULL;
p->String = tmp;
strncpy(p->String[p->numstrings],s,STR_SZ);
p->String[p->numstrings][STR_SZ-1] = '\0';
return p->String[p->numstrings++];
}

void PrintSTRINGARR(const STRINGARR *p)
{
size_t i;

for(i = 0; i < p->numstrings; i++)
puts(p->String);
return;
}

void FreeSTRINGARR(STRINGARR *p)
{
free(p->String);
p->String = NULL;
p->numstrings = 0;
return;
}
 

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,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top