quick function question

Evening,

How do I pass a char[11] back from a function? Either as a value of a function - char[11] tmp = function(); or by changing a variable passed to it - function(tmp);?

I can't find anything in the reference section that tells me how to do it.

Either make the array static in the function, so it will survive after return, or pass a pointer when you call the function to where you want it to store the data.

Er... how do I do either of those?

cowjam,

The simplest way is to pass the whole array to the function. What actually gets passed is a pointer to (the beginning of) the array. The function can use this pointer to change the elements of the array. For example:

#define ARRAY_SZ 11

void setup()
{
    char my_array[ARRAY_SZ] = {0,1,2,3,4,5,6,7,8,9,10};

    add_one_to_array(my_array);
    // my_array now contains 1,2,3,...,11
}

void add_one_to_array(char a[])
{
     int i;

     for (i = 0; i < ARRAY_SZ; ++i)
        a[i] = a[i] + 1;
}

There are other ways to accomplish the same thing, but this is the most straightforward.

Regards,

-Mike

Hey there,

@Mike:

Did you mean

void add_one_to_array(char [glow]*[/glow]a)

InvalidApple,

In a function definition, you can say “char a” or “char *a”. They are interchangeable. Inside the function, you can say “*a” or “a[0]”, no matter which way you declared it in the function header.

I usually try to match the declaration to the usage, just as a matter of coding style. In this case, since I was going to use array subscripting, I declared it that way. Your way would work equally well.

Regards,

-Mike

I was just asking if you were meaning to pass by reference, because you said "pointer to the start of the array" instead of "makes a copy of the array".

My mistake.

Arrays are always passed by reference.

Arrays are always passed by reference

...unless they're part of a "struct".

...unless they're part of a "struct" that is passed by value.

-Mike

I learnt something from this!

I would have thought that a temporary version of the array would be set up, modified, and then discarded. However, in this example shown below, you can see that the original array is being modified, not a copy.

#define ARRAY_SZ 11

void setup()
{
  Serial.begin(9600);
  
    char my_array[ARRAY_SZ] = {'0','1','2','3','4','5','6','7','\0'};
    Serial.print(my_array);
    add_one_to_array(my_array);
    // my_array now contains 1,2,3,...,8
    Serial.print(my_array);
}

void loop() {/*do nothing*/}

void add_one_to_array(char a[])
{
     int i;

     for (i = 0; i <= 7; ++i)
        a[i] = a[i] + 1;
}

I believe that by using a instead of *a, anyone who looks at the code will understand that an array is being passed through. However, I believe that it may cause a problem if you wanted to use the array without changing the original one (and you didn’t know of this abnormality in passing by value). To me it doesn’t tell me that the original array is being modified, which makes me lean to the *a version {each to thier own…}.

Thanks for pointing this out to me.

:slight_smile:

Sorry, I forgot to answer the original question…

To return an array, you can do this…

(I know that this is a bad example, as it has been explained that it is unnessicary; but please humour me for a minute…)

char *add_one_to_array(char *a)
{
     int i;
     char *arr_Modified = a;

     for (i = 0; i <= 7; ++i) {
        arr_Modified[i] = arr_Modified[i] + 1;
     }

     return(arr_Modified);
}

ie- Function is “char *function_name

maybe a second example is needed…

void setup()
{
Serial.begin(9600);

int intNumber = 67;
Serial.println(is_number_even(intNumber));
}

void loop() {/do nothing/}

char *is_number_even(int i)
{
char is_even = “Yes”;
char is_not_even = “No”;

if(i%2) return(is_not_even);

return(is_even);
}

InvalidApple,

There is no abnormality in passing by value when passing in an array. That’s why I tried to point out that passing an array actually just passes a pointer to the array. In ‘C’, the array name can be used as a pointer to the array in most cases.

It’s still “call by value” because the value being passed in is a pointer. Inside the function, the pointer is a variable local to the function. You can change the pointer itself without affecting anything outside the function. This is the definition of “call by value”. However, the pointer points to something outside the function, the original array contents. If you de-reference the pointer, either with the ‘*’ operator or with array brackets – – then you are changing the thing pointed to, which is outside the function.

Your first example:

char *add_one_to_array(char *a)
{
     int i;
     char *arr_Modified = a;

     for (i = 0; i <= 7; ++i) {
        arr_Modified[i] = arr_Modified[i] + 1;
     }

     return(arr_Modified);
}

Will work fine. As you say, it declares and uses another pointer that is redundant, since it’s the same as the pointer passed in. You could just as well make the name of the pointer passed in ‘arr_Modified’ instead of ‘a’.

Returning the value of the pointer will also work correctly, although, since it’s the same value that was passed into the function, it really doesn’t tell the caller anything it didn’t already know, does it?

However, your second example wanders off into the weeds a bit:

char *is_number_even(int i)
{
    char is_even[] = "Yes";
    char is_not_even[] = "No";
    
    if(i%2) return(is_not_even);
    
    return(is_even);
}

The arrays ‘is_even’ and ‘is_odd’, are automatic variables, since they are declared within the function. That means that they are created when the function is called, and destroyed when the function returns. They reside in stack space that is allocated when the function starts up, and the stack is popped when the function returns.

That means that the pointer that the function is returning is pointing to a chunk of memory that can be overwritten by another function. This type of bug is very difficult to track down, because you have a pointer to a chunk of memory, and the values in the memory change seemingly at random as you call functions.

One solution is to declare the arrays as ‘static’. This tells the compiler that you don’t want these arrays to be on the stack, and you want their value to stay the same even after the function returns. A disadvantage of static variables is that, unlike automatic variables, they take up memory space all the time, even when not inside a function.

Here’s how it would look:

static char is_even[] = "Yes";
static char is_not_even[] = "No";

Regards,

-Mike

In this code:

char *add_one_to_array(char *a)
{
     int i;
     char *arr_Modified = a;

     for (i = 0; i <= 7; ++i) {
        arr_Modified[i] = arr_Modified[i] + 1;
     }

     return(arr_Modified);
}

arr_Modified is a pointer to the same memory space as that occupied by a. When you change the values pointed to by arr_Modified, you are changing the a array.

Nowhere have you made a copy of the array, so returning a pointer to the modified array is unnecessary.

Maybe I wasn’t clear in saying that these functions are a

Bad example

And that my original assumption was wrong; showing everyone how I was wrong with an example: But I did ask you to humour me for the purpose of showing something else.

The purpose of these examples where to answer the original question on how to return a charactor array.

To do this you need to declare the function as “char *function_name()”.

I do think that it is a little inconsistant (as my opinion). Look at it this way: You can pass in an array using “char *array” or “char array”, but when it comes to returning an array “char function_name” is an error - Try it with my code.

error: declaration of ‘is_number_even’ as array of functions In function ‘void setup()’:
At global scope:

… Even though “function_name” is usually a pointer to a start of an array just as *function_name would be.

Let’s look at another “pass by value”. Would you expect the intValue to be 4 or 5 at the end of this code…

intValue = 4;
AddOne(intValue);

If the fuction did this:

...
void AddOne(int intInput) {

intInput += 1;

}

… But if we passed in an array by value, the changes in a function remain.

That is why I think that it is an “abnormality in passing by value”.

I hope that I’ve explained myself.

:slight_smile:

InvalidApple,

You are correct about the inconsistency in function declaration. Call it a quirk of C. Another way to look at it is that being able to declare an array with brackets in the function parameters is what the creators of the language called "syntactic sugar", that gives the programmer another option that can make the code clearer. As far as I know, the two methods are exactly equivalent.

However, I don't think you understand how functions parameters are passed in C. In the C programming language, ALL parameters are passed by value. The calling routine pushes the values on to the stack, the function is called, and when the function returns, the stack is popped. If you want to change a variable in the calling routine, you pass the value of a pointer. The pointer can then be de-referenced to modify a variable.

However, there are limitations. For example, you cannot pass an array by value. You can only pass an array pointer.

Functions can return values. When you talk about returning values in C, you are talking about the value sent back to the calling function with the "return" statement.

The short answer to the original question is that in C, you cannot return a character array. Functions can only return simple data types and structures.

In the example you gave, intValue would definitely still be 4 after the call.

To summarize: All parameters passed to a function are passed by value, with a copy of the variable pushed on to the stack. Those variables are local to the called routine, and they go away when the function returns. Parameters must be simple data types (or structs), but they can be pointers to more complex data types, like arrays. Functions can use pointers passed to them to change the data pointed to.

To make it easy to pass an array pointer to a function, when you put the name of an array in a function call, it passes the value of a pointer to the first element of the array.

Functions can also return the value of simple data types (or structs) as the value of the function. Functions cannot return the value of an array, but can return a pointer to an array. Watch out, though, because returning a pointer to an array (or any other variable) that is local to the function will cause big trouble!

I think you and I are saying some of the same things, but using different terminology. "Call by value" and "call by reference" have specific, precise meanings. You can, however, accomplish some of the same effects of call by reference by using call by value with pointers.

Regards,

-Mike