3

Possible Duplicate:
Declaring a C function to return an array

I am new to C, and need to your thoughts to help me to return the result array from the following function:

void getBase(int n, int b)
{
    const size_t SIZE = 32;
    char arr[32+1]={0}; int digits=SIZE, i;
    char* ptr = arr;
    while (n > 0)
    {
        int t = n%b;
        n/=b;
        arr[--digits] = numbers[t];
    }
    while ( *ptr == '\0') ptr++;
    // NEED To return a ref to `ptr`
}

My solution:

void getBase(int n, int b, /*send some  array as a parameter*/ char* str)
{
    const size_t SIZE = 32;
    char arr[32+1]={0}; int digits=SIZE, i;
    char* ptr = arr;
    while (n > 0)
    {
        int t = n%b;
        n/=b;
        arr[--digits] = numbers[t];
    }
    while ( *ptr == '\0') ptr++;

    /* and use strcpy ... perhaps memcpy if non-string )*/
    strcpy(str, ptr);
}

I need further ideas....

Thanks.

Community
  • 1
  • 1
Muhammad Hewedy
  • 29,102
  • 44
  • 127
  • 219

3 Answers3

4

Your solution looks fine.

Instead, you don't even need the local arr array at all. You can just write directly into str:

EDIT : Cleaned up and working version.

const char numbers[] = "0123456789abcdef";

void getBase(int n, int b, char* str)
{
    const size_t SIZE = 32;
    int digits=SIZE;
    while (n > 0)
    {
        int t = n%b;
        n/=b;
        str[--digits] = numbers[t];
    }

    int length = SIZE - digits;

    memmove(str,str + digits,length);
    str[length] = '\0';
}

You just have to make sure that your str is large enough to avoid an array-overrun.


int main(){

    char str[33];

    getBase(684719851,10,str);

    printf(str);

    return 0;
}

Output:

684719851
Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • 3
    Passing a pointer to a buffer without passing in the size of the buffer also is not a good idea. – Jim Rhodes Jan 14 '12 at 23:04
  • @JimRhodes Hence the disclaimer I added. You could also pass in the length. But then you'd need some sort of error-handling in case the length isn't large enough... – Mysticial Jan 14 '12 at 23:06
  • I am trying calling it with `char str[32]; getBase(2, 2, str);` but returns invalid values, can please tell me why? – Muhammad Hewedy Jan 14 '12 at 23:06
  • Oh wait, yeah I forgot that you skip over the NULL-characters in the front. Gimme a sec to fix that with a `memmove()`. – Mysticial Jan 14 '12 at 23:10
  • @Muhammad Also as a side note, the variable `i` is unused, you can remove it. One other thing, if you use pointers instead of indices, you can avoid the `while` at the end (and probably shorten up the code). – Seth Carnegie Jan 14 '12 at 23:11
1
  1. As other mention, the common solution is to allocate an array, an return a pointer to it. Be sure that you free it in the caller function.

  2. If you know (at compilation time) the size of the array, you can make a struct that contain an array, and return the struct. note that it will push the array to the stack, and may slow the program. If it's a really big array you even may get a stack overflow.

asaelr
  • 5,438
  • 1
  • 16
  • 22
  • I don't like the pattern followed in `#1`, I prefer Objective-c pattern. Please see my comment on `bchurchill` answer. About `#2` I gonna try it, thanks. – Muhammad Hewedy Jan 14 '12 at 23:09
  • There is not simple solution to this problem. (In c++ there are some types of pointers that will do the work). You can use your solution (which is fine and common too), or use my second solution (If the size is constant and you know it at compilation-time). – asaelr Jan 14 '12 at 23:12
0

If you want to return an array of length n, you should first create the array with malloc, and then you can return a pointer. E.g.

char *arr = malloc(n*sizeof(char));

//now arr points to an array, use it as you like

return arr;

be sure to set the return type of your function to char*. You can do the same thing for any type of array - just be sure to update all the types accordingly.

bchurchill
  • 1,410
  • 8
  • 23
  • 2
    This is actually less preferable than having the user pass in the array to use, because it lets the user know he is responsible for managing the lifetime of the memory that is used. In this example, if you forget to `free` the return value of the function, you have a memory leak. Also, `n * sizeof(char)` is redundant because `sizeof(char)` is defined to be 1. Also, if you do what he's doing and fill the array from the back to the front and return a pointer to the middle of the array, you can't even call `free` so you're stuck with a memory leak – Seth Carnegie Jan 14 '12 at 22:55
  • `@bchurchill`, exactly as `Seth Carnegie` said, the responsibility (ownership) of this pointer will be lost unless I am documenting somewhere something like `Note, You should free the pointer returned from the function after use`... and this something that I dislike! – Muhammad Hewedy Jan 14 '12 at 23:01
  • The other problem with this is that the receiver of the allocated memory has no way of knowing the length of the array unless there is a sentinel value at the end. – BillRobertson42 Jan 14 '12 at 23:24