从函数返回动态分配的wchar_t *数组

时间:2011-03-18 04:07:54

标签: c++ memory-leaks memory-management

我有一个签名如下的函数:

GetCustomers( wchar_t** Name,int *count);

在主要方法中:致电客户如下:

GetCustomers( Name,&count);

该功能的主体如下:(由于客户数量未知,我正在尝试动态分配meomry)

GetCustomers( wchar_t** Name,int *count)
{
    //Logic to get customer count : Stored in int  myCustomersCount
    Names = new wchar_t*[myCustomersCount];

    for (int i=0; i < myCustomersCount; i++ )     
    {
        Names[i] = new wchar_t;
    }

    //Logic to get customer names in  wchar_t* strName = "Name1";
    Names[0] = strName;
    *count = myCustomersCount;
}

我认为这个实现将允许数组Name正确地传递回Main()函数,并在堆上进行内存分配,但似乎无法正常工作。这有什么不对? myCustomersCount似乎在调用者中是正确的。

PS:代码编译并执行但在Main中收到的数组是垃圾。

5 个答案:

答案 0 :(得分:3)

你似乎在想C,而不是C ++。我会使用类似的东西:

std::vector<std::string> GetCustomers();

或(可能更喜欢):

template <class outIt>
void GetCustomers(outIt output_iterator);

后者你会使用类似的东西:

std::vector<std::wstring> customers;

GetCustomers(std::back_inserter(customers));

第三个显而易见的可能性是为customers类配备一个begin()end()成员函数,将迭代器返回给客户数据。

Edit2:这是一些经过测试的演示代码:

#include <stdio.h>
#include <string.h>
#include <wchar.h>

void GetCustomers(wchar_t ***names, int *count) { 
    static wchar_t *myCustomers[] = { 
        L"You",
        L"Him",
        L"Her"
    };
    int myCustomersCount = 3;
    wchar_t **temp = new wchar_t *[myCustomersCount];

    *count = myCustomersCount;
    for (int i=0; i<myCustomersCount; i++) {
        temp[i] = new wchar_t[wcslen(myCustomers[i])+1];
        wcscpy(temp[i], myCustomers[i]);
    }
    *names = temp;
}

int main() { 
    wchar_t **customers;
    int count;

    GetCustomers(&customers, &count);

    for (int i=0; i<count; i++)
        printf("%S\n", customers[i]);
    return 0;
}

答案 1 :(得分:1)

我真的不确定你在这里要做什么;从我对你的代码的理解;你试图将一些字符串存储到一个字符指针数组的数组中。

GetCustomers(wchar_t **Name, int *count) {
   Name = new wchar_t*[myCustomersCount];
   for(int i = 0; i < myCustomersCount; i++) {
     /* Get your customer name and store into strName */
     Name[i] = strName;
   }
   *count = myCustomersCount;
}

答案 2 :(得分:0)

总的来说,大概是你有类似的东西

wchar_t *Name = NULL;

然后你说

GetCustomers( Name,&count);

这会按值传递Name,但您希望通过引用传递它:

GetCustomers( &Name,&count);

大概只是一个拼写错误,但你的参数名是Name(单数),但你在函数中将其称为Names(复数):

GetCustomers( wchar_t** Name,int *count)
{
    //Logic to get customer count : Stored in int  myCustomersCount
    Names = new wchar_t*[myCustomersCount];

在任何情况下,您都希望指定Name指向的位置,而不是指向自身:

*Names = new wchar_t*[myCustomersCount];

然后,为Names中的每个元素分配一个字符,然后用strName覆盖第一个字符。分配是不必要的(事实上是内存泄漏),你应该从strName分配给循环中的每个元素,就像Suroot的回答一样。

答案 3 :(得分:0)

您的代码存在2个确定问题和1个潜在问题。首先导致问题的主要问题:Name本身是按值传递的。这意味着当你new内存时,当你在函数的第一行分配给它时,你将分配给副本,而不是原始的!您有三个选项:1)保持双指针,让调用者负责分配内存,并为数组可以容纳的名称数量添加第三个参数(推荐)或2)使Name成为三重指针({{1然后您可以通过解除引用来分配它:{​​{1}}或3)只返回wchar_t*** Name,因为您没有使用传递的值。

然后是另一个明确的问题:当您为每个名称分配内存时,您还需要在那里使用*Name = new wchar_t*[myCustomersCount];运算符,否则您只为单个wchar_t**分配空间。

最后,潜在的问题。您没有显示此代码获取每个客户名称的准确程度。但是,如果new[]指向每个客户名称重用的内存,并将其全部放入数组中,那么每个名称都需要wchar_t到数组中。如果没有,那么您不需要为每个strName分配内存,因为您可以将结果直接存储到wstrcpy

最后一点:只是从查看这段代码看起来你的内存管理会遇到很多问题,因为它似乎非常不清楚谁负责分配和释放内存,这是可能会导致内存泄漏。尽量保持在同一位置分配和释放内存的责任,你将减少许多潜在的麻烦 - 让调用者在调用函数之前分配内存并让调用者在完成内存时释放内存用它。

Names[i]

修改 如果确实 绝对无法更改功能签名,我能想到的唯一解决方案是展平您的阵列并使用C内存功能(您也可以使用Names[i]/* changed */ wchar_t** GetCustomers( int *count) { //Logic to get customer count : Stored in int myCustomersCount wchar_t **Names = new wchar_t*[myCustomersCount]; for (int i=0; i < myCustomersCount; i++ ) { /* changed */ Names[i] = new wchar_t[MAX_NAME_SIZE]; } //Logic to get customer names in wchar_t* strName = "Name1"; Names[0] = strName; /* possible wstrcpy needed here? */ *count = myCustomersCount; /* changed */ return Names; } 的长系列,但为什么不使用new这就是它的用途,而你在不使用像STL这样的其他C ++功能的情况下管理内存?) :

delete

请注意,这假设realloc已经初始化并指向可存储GetCustomers( wchar_t **Names, int *count) { //Logic to get customer count : Stored in int myCustomersCount size_t names_size = 0; for (int i=0; i < myCustomersCount; i++ ) { strName = ???; // whatever you use to get the next name size_t old_names_size = names_size; names_size += (wstrlen(strName) + 1) * sizeof(wchar_t); //+1 for NULL *Names = realloc(*Names, names_size); if (!*Names) { // Memory allocation failed, log it, abort, do whatever } wstrcpy(Names[old_names_size], strName); } *count = myCustomersCount; } 的内存,就像假定Name的原始版本已初始化并指向内存您可以在哪里存储wchar_t*

答案 4 :(得分:0)

我以为我会在新的答案中重新开始。

这是一个简单的程序,可以执行我认为您正在尝试执行的操作,其约束条件是不得更改GetCustomers的签名。

void GetCustomers(wchar_t** Names,int *count)
{
    // Allocate the array of names
    wchar_t **ar = new wchar_t*[3];
    // Allocate space for each name in the array
    ar[0] = new wchar_t[10];
    ar[1] = new wchar_t[10];
    ar[2] = new wchar_t[10];
    // Fill in the names
    wcscpy(ar[0],L"joe");
    wcscpy(ar[1],L"jim");
    wcscpy(ar[2],L"bob");
    // Return the array through the bad GetCustomers signature
    *Names = (wchar_t*)ar;
    *count = 3;
}

int wmain(int argc, wchar_t* argv[])
{
    // names is an array of strings
    wchar_t **names = NULL;
    int count;
    // Squeeze names into the dodgy GetCustomers signature
    GetCustomers((wchar_t**)&names,&count);

    // Delete each name
    for(size_t x = 0; x < count; ++x)
        delete[] names[x];
    // Delete the array
    delete[] names;

    return 0;
}

请注意,我已将函数内的强制转换与main中的另一个匹配。通过这种方式,我们保留了应有的一切,除了那个讨厌的GetCustomers签名。

这有帮助吗?