returning a pointer to an array of uint8_t from a C function - get compiler errors

StackOverflow https://stackoverflow.com/questions/23597259

  •  20-07-2023
  •  | 
  •  

Question

I have a function:

uint8_t*  createTestBuffer()
{

    uint8_t buffer[] = {5,7,3,4,1,9,3};
    return &buffer;
}

runing it:

uint8_t *buff = createTestBuffer();

returns compiler errors:

c_programming.c:11:9: warning: incompatible pointer types returning 'uint8_t (*)[7]' from a function with result type
      'uint8_t *' (aka 'unsigned char *') [-Wincompatible-pointer-types]
        return &buffer;

Im returning a pointer to an array of uint8_t from my function. So what am I getting wrong here?

Was it helpful?

Solution

The compiler told you that return &buffer; is returning a pointer to an array of 7 uint8_t (spelled uint8_t (*)[7]), but you said the function returns uint8_t *, and these are different and incompatible pointer types.

If you wrote return buffer;, the types would be correct but the code would still be wrong. You can't safely return a pointer to a local array that's on the stack.

Either make it static const uint8_t buffer[] = { … }; and change the function return type to const uint8_t *, and use accordingly (which is thread-safe because the data never changes):

const uint8_t *createTestBuffer(void)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    return buffer;
}

Or use dynamic allocation in some form as:

uint8_t *createTestBuffer(void)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    uint8_t *rv = malloc(sizeof(buffer));
    if (rv != 0)
        memmove(rv, buffer, sizeof(buffer));
    return rv;
}

Note that the calling code here needs to check that it gets a non-null pointer back again, and it must also ensure it calls free() on the returned pointer unless it is null (when calling free() becomes optional).

Or make the caller pass the buffer – living dangerously by assuming that the user knows to pass enough space:

void createTestBuffer(uint8_t *output)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    memmove(output, buffer, sizeof(buffer));
}

Or living less dangerously:

static inline size_t min(size_t a, size_t b) { return (a < b) ? a : b; }

void createTestBuffer(uint8_t *output, size_t outlen)
{
    static const uint8_t buffer[] = { 5, 7, 3, 4, 9, 1, 3 };
    memmove(output, buffer, min(sizeof(buffer), outlen));
}

There are other ways to handle 'output buffer smaller than copied buffer'; this code copied as much as was safe, but you could return a 0 or 1 status indicating truncation, or assert that the supplied length is not smaller than the required length, or …

OTHER TIPS

here you have two errors:

your first error, is that you're returning your buffer using the & operator (aka address of), which gives a pointer to your variable's address. Your array being already uint8_t* you're returning uint8_t(*)[7], as the error is telling you. And the compiler is grumpy, because you're trying to return that one whereas your function shall return the former.

But know that actually there's an even more important error in your code, as first spotted out by @TimCooper:

you're allocating a variable within the scope of a function, and want to use it outside of that function. In C, when you declare a variable within a function, the memory used to allocated it is freed upon exit of that function, so even if you correct the typing of your function that won't work as expected.

You need to either declare your uint8_t array outside of the function, and pass it as a parameter to your function:

uint8_t* createTestBuffer(uint8_t* array) {
    array[0] = 5;
    array[1] = 7;
    array[2] = 3;
    array[3] = 4;
    array[4] = 1;
    array[5] = 9;
    array[6] = 3;
    return array;
}

or you need to use malloc to allocate the memory in the heap instead of allocating it in the stack:

uint8_t* createTestBuffer() {
    uint8_t* array = , malloc(sizeof(uint8_t)*7);
    array[0] = 5;
    array[1] = 7;
    array[2] = 3;
    array[3] = 4;
    array[4] = 1;
    array[5] = 9;
    array[6] = 3;
    return array;
}

but then you'll have to not forget to free() the buffer variable once you've finished using it.

You get the warning because buffer is of type uint8_t*. The statement &buffer is of type uint8_t** - a pointer to a pointer.

In C and C++ an array name is the same as a pointer.

char s[4] = { 'a', 'b', 'c', '\0' };
char *p = &s[0];
printf("%s", s);
printf("%s", p);

The second thing is that you're returning a pointer to an array CREATED ON STACK. This array is not valid after function exit. In practice you're returning a dangling pointer.

If you want to return a pointer you should allocate memory on heap, using malloc():

uint8_t* createTestBuffer()
{
    uint8_t *buffer = (char*)malloc( 3 * sizeof(char) );
    buffer[0] = 10;
    buffer[1] = 20;
    buffer[2] = 30;
    return buffer;
}

But there is another problem. You're returning a pointer to a memory block, but you don't know how big the buffer is. You can modify the function to "return" 2 values this way:

void createTestBuffer(uint8_t **buffer, size_t *size)
{
    *buffer = (char*)malloc( 3 * sizeof(char) );
    buffer[0] = 10;
    buffer[1] = 20;
    buffer[2] = 30;
    *size = 3;
}

and call it like this:

char *buf;
size_t size;
createTestBuffer(&buf, &size);

Enjoy!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top