1

I'm working on a function in C that should return a pointer to an array struct. The struct is

struct corr{
  char nome[128];
  char cognome[128];
  char password[10];
  float importo;
};
typedef struct corr correntista;

The function that return a pointer to this struct is

correntista *max_prelievo(FILE *fcorrentisti, FILE *fprelievi){
    correntista *corr_max[2];
    corr_max[0] = (correntista *)malloc(sizeof(correntista));
    corr_max[1] = (correntista *)malloc(sizeof(correntista));
    /*.........*/
    return *corr_max;
}

In the main program I want to print the returned value in the following way:

*c_max = max_prelievo(fc, fp);
printf("Correntista con max prelievi:\n");
printf("Nome: %s\n", c_max[0]->nome);
printf("Cognome: %s\n", c_max[0]->cognome);
printf("Max prelievo: %f\n\n", c_max[0]->importo);

printf("Correntista con max versamenti:\n");
printf("Nome: %s\n", c_max[1]->nome);
printf("Cognome: %s\n", c_max[1]->cognome);
printf("Max versamento: %f\n", c_max[1]->importo);

but only the first struct c_max[0] has the expected value. c_max[1] has garbage values. What should I change in my program?

11
  • 1
    What is the type of c_max? Try changing correntista *max_prelievo(FILE *fcorrentisti, FILE *fprelievi){ to correntista **max_prelievo(FILE *fcorrentisti, FILE *fprelievi){ and return *corr_max; to return corr_max;. and from the calling function, correntista **c_max = max_prelievo(fc, fp); Commented Jun 10, 2015 at 14:09
  • 3
    You don't need to cast the result of malloc - stackoverflow.com/questions/605845/… Commented Jun 10, 2015 at 14:11
  • 1
    @CoolGuy That would invoke undefined behaviour. Commented Jun 10, 2015 at 14:14
  • @undefinedbehaviour , What change will cause UB? Commented Jun 10, 2015 at 14:16
  • @CoolGuy returning a pointer into an array that isn't guaranteed to exist once the function returns is obviously UB. Commented Jun 10, 2015 at 14:21

2 Answers 2

2

There are several solutions, but they all require an overhaul of how your function is to operate. Perhaps the best solution is to consider how scanf works; It returns no objects, instead it operates solely on objects that are pointed to by parameters passed to it. Hence:

void max_prelievo(correntista *corr_max, FILE *fcorrentisti, FILE *fprelievi){
    /* NOTE: You should make a habit of separating your allocation from this logic;
     *       it makes debugging and testing so much easier... */

    corr_max[0] = (correntista) { .nome = "Michael",
                                  .cognome = "Anderson",
                                  .importo = 42.0 };

    corr_max[1] = (correntista) { .nome = "Undefined",
                                  .cognome = "Behaviour",
                                  .importo = -1.0 };


    /*.........*/
}

int main(void) {
    correntistia c_max[2] = { 0 };
    FILE *f1 = fopen(...), *f2 = fopen(...);

    max_prelievo(c_max, f1, f2);

    printf("Correntista con max prelievi:\n");
    printf("Nome: %s\n", c_max[0].nome);
    printf("Cognome: %s\n", c_max[0].cognome);
    printf("Max prelievo: %f\n\n", c_max[0].importo);

    printf("Correntista con max versamenti:\n");
    printf("Nome: %s\n", c_max[1].nome);
    printf("Cognome: %s\n", c_max[1].cognome);
    printf("Max versamento: %f\n", c_max[1].importo);
}

What scanf does return is a single integer, indicating success. Perhaps, if you are to use return values in the future, you could resort to using a similar pattern? Look at the bright side: There's no malloc or free here and no chance you could leak any memory; the code is as simple as it could possibly get.


Alternatively, as horrific as it seems, if you must resort to using such a pattern then less calls to malloc will serve you well. Consider something like this:

correntista *max_prelievo(FILE *fcorrentisti, FILE *fprelievi) {
    correntista *corr_max = malloc(2 * sizeof *corr_max);

    corr_max[0] = (correntista) { .nome = "Michael",
                                  .cognome = "Anderson",
                                  .importo = 42.0 };

    corr_max[1] = (correntista) { .nome = "Undefined",
                                  .cognome = "Behaviour",
                                  .importo = -1.0 };

    /*.........*/

    return corr_max;
}

The main entry point will be almost identical to the example I gave earlier... except for one thing: Don't forget to free that memory! :(

Sign up to request clarification or add additional context in comments.

2 Comments

@CoolGuy Thanks for the edits :) my astigmatism is too horrific to notice that I accidentally typed , instead of ....
I would also say that this is the preferred solution, as how and where the memory is allocated has nothing to do with the actual algorithm of that function.
1

Remember what you have is array of pointers so when you exit the function the array is out of scope. Have a pointer to pointer for this purpose as shown below.

correntista **max_prelievo(FILE *fcorrentisti, FILE *fprelievi){
    correntista **corr_max = malloc(sizeof(correntista *) * 2);
    corr_max[0] = malloc(sizeof(correntista));
    corr_max[1] = malloc(sizeof(correntista));
    /*.........*/
    return corr_max;
}

The call should be

correntista **c_max = max_prelievo(fc, fp);

3 Comments

This isn't correct though. A pointer to pointer is not a pointer to an array and you aren't allocating an array, you are allocating a segmented heap fiasco, which is something you should never do. Instead, allocate an array. correntista* corr_max = malloc(2 * sizeof(*corr_max)); or alternatively use an array pointer (although the syntax for returning array pointers from functions is very ugly).
@user3700643 Indeed. Technically speaking, this doesn't meet your requirements as specified in your comment to Cool Guy: "I am obliged to define the function as correntista *max_prelievo(FILE *fcorrentisti, FILE *fprelievi). c_max type is "correntista" as the struct"
@Lundin I agree!! I don't know where I was when I wrote this code.. Just going through it again I feel pointer to pointer is unnecessary here.. Anyways even though this approach is ugly it is not wrong so I keep this answer :)

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.