Возвращение динамически созданного массива из функции - PullRequest
1 голос
/ 20 марта 2010

Я пытаюсь создать функцию, которая динамически распределяет массив, устанавливает значения элементов и возвращает размер массива. Переменная массива - это указатель, который объявлен вне функции и передан в качестве параметра. Вот код:

#include <cstdlib>  
#include <iostream>  
using namespace std;  

int doArray(int *arr) {  
    int sz = 10;  
    arr = (int*) malloc(sizeof(int) * sz);  

    for (int i=0; i<sz; i++) {  
        arr[i] = i * 5;  
    }  

    return sz;  
}  

int main(int argc, char *argv[]) {  

    int *arr = NULL;  
    int size = doArray(arr);  

    for (int i=0; i<size; i++) {  
        cout << arr[i] << endl;  
    }  

    return 0;  

}  

По какой-то причине программа завершается на первой итерации цикла for в main ()! Я что-то не так делаю?

Ответы [ 7 ]

2 голосов
/ 20 марта 2010

Если вы хотите распределить память таким образом, вы должны использовать:

int doArray(int*& arr)

иначе указатель будет изменен только внутри области действия функции.

1 голос
/ 20 марта 2010

Вы передаете в массив указатель по значению ; это означает, что когда ваша функция doArray возвращается, значение в arr в main все еще равно NULL - назначение внутри doArray не меняет его.

Если вы хотите изменить значение на arr (то есть int *), вам необходимо передать либо указатель, либо ссылку на него; следовательно, ваша подпись функции будет содержать либо (int *&arr), либо (int **arr). Если вы передадите его как **, вам также придется изменить синтаксис внутри функции с использования arr на *arr (разыменование указателя), и вы будете называть его так: doArray(&arr).

Кроме того, в C ++ вы действительно должны использовать new int[sz] вместо malloc.

1 голос
/ 20 марта 2010

Вам необходимо добавить дополнительный уровень косвенности к doArray. Как написано, он правильно распределяет массив, но не передает значение указателя обратно вызывающей стороне. Указатель с malloc теряется при возврате.

Если вы написали функцию, которая принимает значение с плавающей точкой и изменяет значение, передавая измененное значение обратно вызывающей стороне, для этого потребуется указатель: foo(float *f). Точно так же здесь вы хотите передать обратно значение int* вызывающей стороне, поэтому ваша функция должна быть объявлена ​​как doArray(int **arr) со второй звездочкой.

int doArray(int **arr) {  
    int sz = 10;  
    *arr = (int*) malloc(sizeof(int) * sz);  

    for (int i=0; i<sz; i++) {  
        (*arr)[i] = i * 5;  
    }  

    return sz;  
}  

int main(int argc, char *argv[]) {  

    int *arr = NULL;  
    int size = doArray(&arr);  

    for (int i=0; i<size; i++) {  
        cout << arr[i] << endl;  
    }  

    return 0;  

}

Обратите внимание, как теперь он разыменовывает *arr внутри doArray, и как теперь вызов записывается как doArray(&arr).

0 голосов
/ 20 марта 2010

Как уже отмечали другие, вы передаете свой массив (int *) по значению, поэтому, когда вы говорите arr=..., вы на самом деле не изменяете массив, который передали.

You 'Вы также получили утечку памяти, как вы ее написали.Это не имеет большого значения, когда вы вызываете doArray только один раз в теле вашей программы, но если он вызывается повторно и массив никогда не будет free d (или delete d, если вы сделали это с помощью new) тогда это может вызвать проблемы.Как правило, лучший способ справиться с этим - использовать STL .Затем вы написали бы

#include <vector>
#include <iostream>
int doArray(std::vector<int> &arr) {  
    int sz = 10;
    arr.resize(sz);  
    for (int i=0; i<sz; i++) {  
        arr[i] = i * 5;  
    }
    return sz;  
}

int main(int argc, char *argv[]) {  
    std::vector<int> arr;
    int size = doArray(arr);  
    for (int i=0; i<size; i++) {  
        std::cout << arr[i] << std::endl;  
    }
    return 0;  
}

Однако, с STL есть более идиоматические способы, чем возвращение размера, так как вы можете просто запросить arr.size(), и, если вам действительно интересно, можете использовать такие функции, какfor_each или ostream_iterator для печати всех ваших элементов.

0 голосов
/ 20 марта 2010

Вам нужен указатель на указатель в параметре doArray (). Если вы никогда раньше не занимались программированием с указателями, это может сбить с толку. Я считаю, что легче увидеть правильные типы, если вы обильно аннотируете свой код с помощью typedefs.

Вы правильно поняли, что (int *) можно использовать для представления массива. Но если вы хотите изменить значение вашей переменной arr в main (), вам нужен указатель на , что , и поэтому вы получите (непроверенный код) что-то вроде следующего

typedef int *IntArray;

int doArray(IntArray *arr) {  
    int sz = 10;  
    *arr = (IntArray) malloc(sizeof(int) * sz);  
    IntArray theArray = *arr;

    for (int i=0; i<sz; i++) {  
        theArray[i] = i * 5;  
    }  

    return sz;  
}

при вызове doArray вам нужно будет передать адрес вашей переменной (чтобы doArray знал, куда писать):

int main(int argc, char *argv[]) {  

    int *arr = NULL;  
    int size = doArray(&arr);  

    for (int i=0; i<size; i++) {  
        cout << arr[i] << endl;  
    }  

    return 0;  

}  

Это должно сработать.

0 голосов
/ 20 марта 2010

Изменить подпись на (специфично для c ++):

int doArray(int *&arr)

, чтобы указатель был изменен при выходе из doArray.

0 голосов
/ 20 марта 2010

Переменная arr в вашей функции является локальной копией указателя arr в главной функции, и оригинал не обновляется. Вам нужно передать указатель на указатель или ссылку на указатель (первый также будет работать на простом c, а последний только на c ++).

int doArray(int **arr)

или

int doArray(int*& arr)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...