-2

Hello I have a problem in my code. I want to convert vector of strings in C++ to array of strings in C but I got a error "double free or corruption (out):"
in my code I have two functions
C++ function: void get_num_apn( unsigned int *num_apn , char **arr) : that convert the vector of strings to array of strings C function : in my C function I have called get_num_apn but I need to call this function one time any one can help please and thanks.

c++ code:

void get_num_apn( unsigned int *num_apn , char **arr)
{
     vector<std::string>apn={ "ghadz", "internet.ooredoo.tn",  "mms.ooredoo.tn","internet.tn","gprs.tn",
    "mms.tn",
    "weborange",
    "mms.otun" }   ;
    *num_apn=apn.size();

    for (int i = 0; i < apn.size(); i++) 
    {
        arr[i] = strdup(apn[i].c_str());
    } 
}

c code :

int main()
{
    unsigned int num_apn=0;
    char **arr = NULL;
    arr = (char**)malloc(num_apn*sizeof(char*));
    get_num_apn(&num_apn, arr);
    for (int i=0 ; i<num_apn ; i++)
    {
        printf("arr[i]=%s\n" , arr[i]);
    }
    for (int i = 0; i <num_apn; i++) 
    {
        free(arr[i]);
    }
    free(arr);
    return 0;
}
eglease
  • 2,445
  • 11
  • 18
  • 28
sarra
  • 11
  • 2

1 Answers1

2

You don't know how many strings there are before calling get_num_apn, so you don't know how much space to pre-allocate. The example code ends up allocating nothing, with the result that get_num_apn attempts some invalid memory accesses. There are multiple possible solutions, but they all fall into two broad categories:

  • provide a way for the caller to determine in advance how much space to allocate, or

  • have get_num_apn perform the allocation.

In the example code, get_num_apn relies on private, internal information about the data to be copied, and in such a case, it seems most sensible to exercise the second alternative.

The next question is how get_num_apn should provide results to the caller. You again have two good options: via its parameters or via its return value. Or both. To deliver the array pointer itself via a parameter would require a triple pointer, which is stylistically nasty, but you do need to return the array length as well.

The simplest way forward would be to return the array pointer, and provide the length via an out parameter as you already do. However, you have indicated in comments that you want to reserve the return value for another purpose, so the next simplest way is to provide both the array pointer and the length via out parameters. For example:

// C++

#include <cstdlib>
#include <string>
#include <vector>

extern "C" char *strdup(const char *);

extern "C"
void get_num_apn(unsigned int *num_apn, char ***arr) {
    std::vector<std::string> apn = {
         "ghadz", "internet.ooredoo.tn", "mms.ooredoo.tn", "internet.tn",
         "gprs.tn", "mms.tn", "weborange", "mms.otun"
    };

    char **temp = (char **) malloc(apn.size() * sizeof(*temp));

    if (!temp) {
        *num_apn = 0;
    } else {
        for (int i = 0; i < apn.size(); i++) {
            temp[i] = strdup(apn[i].c_str());
        } 
        *num_apn = apn.size();
    }

    *arr = temp;
}
// C

#include <stdlib.h>
#include <stdio.h>

void get_num_apn(unsigned int *num_apn, char ***arr);

int main(void) {
    unsigned int num_apn = 0;
    char **arr;

    get_num_apn(&num_apn, &arr);
    for (unsigned int i = 0; i < num_apn; i++) {
        printf("arr[i]=%s\n", arr[i]);
        free(arr[i]);
    }
    free(arr);

    return 0;
}

That could be made safer by checking for and handling strdup() failures, of course, but that's not what I'm demonstrating.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • i need the type of "get_num_apn" is unsigned int because i have another variable to return – sarra Aug 17 '23 at 14:44
  • @sarra, if you need the function's return value for another purpose -- which you did not disclose in the question -- then you can deliver the array pointer via an out parameter, as this answer already indicates. Note well that that requires an additional level of indirection, hence my remark about triple pointers. – John Bollinger Aug 17 '23 at 14:54
  • @ John Bollinger can you edit your solution as i need because i dont understand well what you mean ? – sarra Aug 17 '23 at 14:58
  • Ok, @sarra, done. In the future, please present all your requirements up front. – John Bollinger Aug 17 '23 at 15:09
  • hello John Bollinger why i got this error "free(): double free detected in tcache 2" – sarra Aug 21 '23 at 08:54
  • @sarra, for some reason outside the scope of this answer. I have made minor updates to show exact, complete code for a compilable demo program. If I compile it and run it under Valgrind or with relevant AddressSanitizer options then they do not detect any double free or other misuse. – John Bollinger Aug 21 '23 at 13:49