4

Consider this code:

typedef struct fruits_s
{
    char* key;
    char value;
} fruits_t;

static fruits_t fruit_array[] = {
{ "Apple", 1 },
{ "Banana", 2 },
{ "Grape", 3 },
{ "Orange", 4 } };

static fruits_t* getFruitFromValue(char value)
{
    int i;
    for (i = 0; i < sizeof(fruit_array)/sizeof(fruit_array[0]); i++){
        if (value == fruit_array[i].value){
            return fruit_array[i];
        }
    }
}

I am new to C and am still learning when pointers are necessary/used. I come spoiled from a Java background. So, in the above code, what I'm confused of is should the function return a pointer fruits_t*? Or something else? When I do fruit_array[i] is that a pointer to my struct, or the struct itself?

That being said, later in my code when I want to use the function, is it this:

 fruits_t* temp = getFruitFromValue(1);

or

 fruits_t temp = getFruitFromValue(1);

or

 fruits_t temp = &getFruitFromValue(1);
7
  • I think it will be return &fruit_array[i]; Commented Nov 20, 2012 at 1:32
  • 2
    fruit_array[i] is the struct, if you want to return a pointer to it, &fruit_array[i] or, equivalently, (fruit_array + i). Commented Nov 20, 2012 at 1:32
  • I guess that's part of my question... do I want to return a pointer to it, or not? Commented Nov 20, 2012 at 1:33
  • No need to declare your getFruitFromValue() as static when you to return a static array element. Commented Nov 20, 2012 at 1:41
  • @Deqing: the reason for declaring the function static may be so that it is not visible outside the source file; I would assume that was why. I grant you there could be confusion about it, but it's not clear that there is confusion about it. Commented Nov 20, 2012 at 1:57

1 Answer 1

4

The function could return either — your choice. You've said you'll return a pointer; that's OK as long as you do.

When you write:

static fruits_t *getFruitFromValue(char value)
{
    int i;
    for (i = 0; i < sizeof(fruit_array)/sizeof(fruit_array[0]); i++){
        if (value == fruit_array[i].value){
            return fruit_array[i];
        }
    }
}

There are several problems:

  1. fruit_array[i] is a structure, not a pointer. Use return &fruit_array[i];.
  2. If the loop exits, you don't return a value from the function at all.

Fixing those leads to:

static fruits_t *getFruitFromValue(char value)
{
    int i;
    for (i = 0; i < sizeof(fruit_array)/sizeof(fruit_array[0]); i++)
    {
        if (value == fruit_array[i].value)
            return &fruit_array[i];
    }
    return NULL;
}

This is OK because the pointer you return is to static data that will outlive the function. If you tried to return a pointer to non-static data, you would (probably) have a bug on your hands, unless you used dynamic memory allocation (via malloc() et al).

You could also return the structure; handling the error return becomes harder. If you've got C99, you can use a 'compound literal':

static fruits_t getFruitFromValue(char value)
{
    int i;
    for (i = 0; i < sizeof(fruit_array)/sizeof(fruit_array[0]); i++)
    {
        if (value == fruit_array[i].value)
            return fruit_array[i];
    }
    return (fruits_t){ .key = "", .value = 0 };
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for the detailed response. I understand most of your points. I guess what I'd like to know is, WHY would I return a pointer to this data vs the struct itself? Here as you said the struct outlives the function, so I know if it didn't a pointer to it would be a bad idea. But do you have any other thoughts?
For a small structure like this, it's reasonable to return a copy of the structure. If the structure was large (say hundreds of bytes or bigger), then returning a pointer is more sensible than returning the value. It's always important to ensure that a pointer points to live data; returning a value largely gets away from the issue (though even here, you have a char * within the structure; it's safe because of the way the structures are allocated, but it would not be hard to run into problems). You could use struct fruits_s { char key[11]; char value; }; to avoid a pointer in the structure.
For a small structure like this, it's reasonable to return a copy of the structure. So is a copy created and an implicit "malloc" performed, allocating memory to this copy? Like this uses more memory than returning a pointer, correct?
The mechanics are up to the compiler, but it won't usually use malloc() because it would then have to use free() at the right point in time too. But when returning a value, yes, a copy is created, usually in stack space, and the calling function copies the value into the variable it is assigned to. For most structures, yes, the copy uses more memory than a pointer, but the compiler minimizes the cost. OTOH, the value saves having to ensure that the pointer is stable. It depends on context, hence my opening comment: 'The function could return either [a pointer or a structure]'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.