2

I'm trying to return 4 pointers which are stored in another pointer from a function in C, but I get segmentation fault. Do anyone know how to do this?

That's the way I tried to do this:

//declaration of 5 pointers (int * ptr0, float * ptr1, ..., int * ptr4)

int * function()
{
    int * ptr;
    ptr = malloc(sizeof(int)*4);

    float * ptr1;
    ptr1 = malloc(sizeof(float)*4);

    float * ptr2;
    ptr2 = malloc(sizeof(float)*4);

    float * ptr3;
    ptr3 = malloc(sizeof(float)*4);

    int * ptr4;
    ptr4 = malloc(sizeof(int)*4);

    retunr ptr;
}

ptr0 = function();
ptr1 = ptr0[0];
ptr2 = ptr0[1];
//and so on...

Ok, I changed my program but now I can not write in the pointers anymore. I know this is a realy 'stupid' question but I realy dont know. Can someone help ?

noName
  • 132
  • 1
  • 9

6 Answers6

9

You can only return a singe value from a function. A simple solution is to return a struct that contains the desired pointers.

struct pointers {
    float* ptr1;
    float* ptr2;
    float* ptr3;
    // or perhaps an array instead:
    // float* f_ptrs[3];
    int*   ptr4;
}

struct pointers function() {
    struct pointers p;
    // initialize the members here
    return p;
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
4
void ** function()
{
    void ** ptr;
    ptr = (void **)malloc(sizeof(void *)*4);

    ptr[0] = malloc(sizeof(float)*4);
    ptr[1] = malloc(sizeof(float)*4);
    ptr[2] = malloc(sizeof(float)*4);
    ptr[3] = malloc(sizeof(int)*4);

    return ptr;
}
mvidelgauz
  • 2,176
  • 1
  • 16
  • 23
  • Im going to check this out – noName Jun 21 '16 at 14:56
  • 1
    @noName beware that `ptr0[x]` are **void** pointers. you'll need to cast them to work with `int`a and `float`s – mvidelgauz Jun 21 '16 at 14:59
  • 1
    No need to cast in C. – alk Jun 21 '16 at 15:06
  • @alk maybe, doesn't it depend on compiler and/or its settings? I usually prefer to cast anyway at least for better readability – mvidelgauz Jun 21 '16 at 15:10
  • 2
    C implicitly converts to/from `void`-pointers to any other type. – alk Jun 21 '16 at 15:15
  • 1
    casting may hide an error the compiler would catch in the absence of the cast. – pmg Jun 21 '16 at 15:22
  • Correcting my previous comment: "*... any other **pointer**-type.*" @user2079303 Sry for being sloppy! – alk Jun 21 '16 at 15:29
  • Thank you @user2079303. You clarified what I meant in my first comment here by saying _"you'll need to cast them to work with ints and floats"_. To read/write `int`s and `float`s pointed by void pointers those pointers need to be casted, am I wrong? – mvidelgauz Jun 21 '16 at 15:34
  • Sure, to *dereference* a `void`-pointer it needs to be casted to any other pointer-type beforehand. @user2079303 – alk Jun 21 '16 at 15:35
  • 1
    @alk I am happy that we reached the agreement ))) – mvidelgauz Jun 21 '16 at 15:36
  • My initial comment referred to this cast `... = (void **)malloc(...`. Also I wrote it *before* you places your 1st comment. A classical misunderstanding due to an incomplete protocol implementation ... ;-) – alk Jun 21 '16 at 15:37
  • 2
    @mvidelgauz & alk, oh I see ambiguity now. alk's comment seems to respond to mvidelgauz's comment which is about one thing, but alk is commenting on the line `(void **)malloc(sizeof(void *)*4);` from the answer. (deleting redundant comments) – eerorika Jun 21 '16 at 15:39
3

i saw it wasn't mentioned, but you could also pass double pointers into the function and have the function fill them out, another way to return multiple values:

void function(int** p1, float** p2, float** p3, float** p4, int** p5)
{
    *p1 = malloc(sizeof(int)*4);

    *p2 = malloc(sizeof(float)*4);

    *p3 = malloc(sizeof(float)*4);

    *p4 = malloc(sizeof(float)*4);

    *p5 = malloc(sizeof(int)*4);
}

int* ptr1;
float* ptr2;
float* ptr3;
float* ptr4;
int* ptr5;

function(&ptr1, &ptr2, &ptr3, &ptr4, &ptr5);
iedoc
  • 2,266
  • 3
  • 30
  • 53
2

There are three choices, you could return a void** (basically, a pointer to an array of void* that you then cast), you can declare a struct that contain the pointers, then allocate and return a pointer to such a struct (then let the caller de-allocate the struct) or you can use a func(float **ptr0, float **ptr1, float **ptr2, int **ptr3) and assign your malloced memory to *ptr0, ...

Neither of these are perfect, depending on circumstances I would pick either solution 2 or solution 3, on the basis that it's going to end up messy remembering all the relevant casts and allowing the compiler to help you with types is a good idea.

Vatine
  • 20,782
  • 4
  • 54
  • 70
1

You didn't fill *ptr, but even if you did, don't do this. Use std::tuple<> or pair of std::pair<>s - or return a struct.

Edit: since it's no more C++, just return a struct with the four fields.

lorro
  • 10,687
  • 23
  • 36
  • `since it's no more C++, just return a struct with the four fields.` Which I would heartily recommend in C++ as well, because you get to give descriptive names for the members. – eerorika Jun 21 '16 at 15:35
  • @user2079303: in C++, you'd simply say std::tie(ptr1, ptr2, ptr3, ptr4) = function(), but otherwise yes, I agree. – lorro Jun 21 '16 at 16:09
1

What about this:

#include <stdlib.h>
#include <stdio.h>  /* for perror() */


int function(void ** ptrs, size_t n)
{
  int result = -1;

  pptrs[0] = malloc(...);
  if (NULL == ptrs[0])
  {
    goto err;
  }

  ...

  ptrs[n - 1] = malloc(...);
  if (NULL == ptrs[n - 1])
  {
    goto err;
  }

  result = 0;

err:

  return result;
}

int main(void)
{
  size_t n = 5;
  void * ptrs[n];
  for (size_t i = 0; i < n; ++n)
  {
    ptrs[n] = NULL;
  }

  if (-1 == function(ptrs, n))
  {
     perror("function() failed");
     exit(EXIT_FAILURE);
  }

  /* Do stuff. */

  /* Free memory where ptrs' are pointing to. */

  return EXIT_SUCCESS;
}

If VLAs are not supported change the beginning of main() to be:

#define N (5)

int main(void)   
{
  size_t n = N;
  void * ptrs[N] = {0};

  if (-1 == function(ptrs, n))
  {
    ...
alk
  • 69,737
  • 10
  • 105
  • 255