Go Down

Topic: confirmation about passing char arrays to function (Read 22547 times) previous topic - next topic

GordonEndersby

Dec 01, 2008, 06:45 pm Last Edit: Dec 01, 2008, 06:51 pm by GordonEndersby Reason: 1
Dear all,

Just a quick question about passing char arrays to functions.
I just want to confirm Ive read the reference and docs properly.

Can anyone confirm that you cant pass a char array to a function except via reference (char*)?

Also can you return a char array from a function or do you have to include the array you want to return through a referenced array in the parameters?
so I cant do:

char string[] = myFunction();

char myFunction(){
 return "abcde";
}

but would have to do:

char string[5];
myFunction( string );

void myFunction( char* localString){
 localString = "abcde";
}


Thanks

Gordon

mikalhart

#1
Dec 01, 2008, 06:53 pm Last Edit: Dec 01, 2008, 06:57 pm by mikalhart Reason: 1
Gordon, in C and C++ you cannot pass arrays to functions as parameters, nor return them from functions.  There are several options for getting around this, however.  As you mentioned, you can pass a pointer to the array or return a pointer (or reference) from the function.  You can also wrap the array in a struct or class to return it.

If your goal is to write a function that "returns" static strings like the one in your example, it is perfectly reasonable to write

Code: [Select]
char *myFunction()
{
 return "returnedText"; // this returns a pointer to the string, not the string itself
}

char *str = myFunction();
Serial.println(str); // prints "returnedText"


Mikal

mikalhart

#2
Dec 01, 2008, 07:04 pm Last Edit: Dec 01, 2008, 07:08 pm by mikalhart Reason: 1
Quote
char string[5];
myFunction( string );

void myFunction( char* localString){
localString = "abcde";
}


Gordon, I'd like to spend a minute explaining why this won't work either, even though it compiles correctly.

char string[5]; // declare a 5-character array
myFunction( string ); // create a pointer to the first char in string and pass the pointer to myFunction

void myFunction( char* localString){
// At this point localString is a 16-bit pointer variable containing the address of string.  It "points" to string.
// The following line changes localString so that now it points somewhere else: to the string "abcde"
// Note that it DOESN'T change the contest of "string" in any way.  All it does is point localString elsewhere.
localString = "abcde";
// myFunction exits: nothing has been done.
}

If you want "string" to be filled up with the string "abcde" you need to do two things.  First modify myFunction so that it actually copies the string into "string":

Code: [Select]
void myFunction( char* localString){
 strcpy(localString, "abcde");
}


Secondly, remembering that a C string is terminated by a 0 character, increase the size of string to 6 to account for the 0:

Code: [Select]
char string[6];

This kind of programming is dangerous, though.  As you have already demonstrated, it's easy to cause buffer overflows this way.

Mikal

GordonEndersby

Thanks,

Sorry the examples were simple semi pseudo code written from memory and not checked and compiled. I understand the 0 end character for the string array.
There wont be any static strings in the final functions.

My aim is to write some functions to parse xml retrieved by the Ethernet shield and libraries. What Im trying to write is a function that accepts 2 parameters, the start and end tags wrapped around the text I want, and returns the text between.
for example <title>Title</title>.
Id liked to have written :

char title[] = getText( "<title>", "</title>");

Where the function getText() steps through the xml returned by the ethernet libraries
and returns the string "Title". Ive no problem with the processing the xml or the ethernet libraries. Its just the best way of passing the parameters and returning the results.

I think combining what you've both replied with is what Ill have to do.

<my rougth un-compiled code warning>
char startTag = "<title>";
char endTag = "</title>";
char text[50];            //being vary careful later to make sure there's no overflow
getText( startTag, endTag, text);

void getText( char* localStartTag, char* localEndTag, char* localText){
 /*
 Take the start and end tags and find the text
 The ethernet library results are returned one character at a time
 When I find the text I put each character into localText till its full with a "0" at the end
 */
}

I think Im explaining it clearly, does it make sense?

Thanks

Gordon


mikalhart

Your explanation is very clear, and I think you understand what needs to happen.  Does your getText function actually read from the XML stream directly?  I would assume so.

To be perfectly safe, you might add a "size" parameter so that getText knows how big the available buffer space is.  Something like

void getText(char *localStartTag, char *localEndTag, char *resultingInnerText, int buffer_size)
{...}

getText("<title>", "</title>", text, 50);

Looks good!

Mikal

GordonEndersby

Thanks,

Yes, it reads the stream a single character at a time as this is how the ethernet library passes the response from the web server. I then build it up into a variable the same size as the tag and keep rolling through it till I find a matching tag. That way I use as little ram on the Arduino as possible.
Its a pity the ethernet shield hasnt enough memory to hold the whole response and allow you to move around it as you like. Ive looked through the specs and libraries and unless if missed something theres only a 16k buffer. So Im stuck with a single walk through the response unless I make another request and start at the top again.

I was going to simply check the size of the referenced array rather than pass the size to the function.

getText("<title>", "</title>", text, 50);
Can I really do that, passing the strings as a reference?
I thought I would have to pass variables rather than the string literals.
So the location of the string literals are passed. That ties up with what Ive read that strings like this are copied from program space to ram.
Im getting there.

All my previous programming hasnt been this restricted since using a ZX81.
Ive got too used to big web servers, lots of storage and ram.

Gordon


mikalhart

Quote
I was going to simply check the size of the referenced array rather than pass the size to the function.


There is no way to determine the size of the text buffer inside the getText() function, because all you have is a pointer to the first element.

Quote
getText("<title>", "</title>", text, 50);
Can I really do that, passing the strings as a reference?


Yup! :)

Mikal

GordonEndersby


Thanks.

"There is no way to determine the size of the text buffer inside the getText() function, because all you have is a pointer to the first element."

That explains why a bit of code I was experimenting with didnt do what I expected.
Maybe iterating through each character till I hit the 0 end of string marker would do
Ill decide if its worth the hassle/program memory.

Once Ive finished this Ill post it up.
It may be useful to someone. I work slow so dont hold your breath.
I have to wait till health and family commitments allow me some time and energy to work.

Gordon


mikalhart

Quote
Maybe iterating through each character till I hit the 0 end of string marker would do.


This is a good general technique, but remember that in this case you are not passing a string with a terminating 0, but a buffer with unknown contents.  The size you want is the physical size of the buffer, not the length of its contents.  There really is no way of calculating this value at either compile or run time.  If you want the size, you will have to either pass it in to getText or make some assumptions about it.

Mikal

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy