2012-01-23 2 views
0

Когда я возвращаю указатель из функции, ее значение можно получить по отдельности. Но когда цикл используется для вывода значения этой переменной указателя, отображается неправильное значение. Где я ошибаюсь, не могу понять.Возвращаемый указатель из функции в C++

#include <iostream> 
#include <conio.h> 

int *cal(int *, int*); 

using namespace std; 

int main() 
{ 
    int a[]={5,6,7,8,9}; 
    int b[]={0,3,5,2,1}; 
    int *c; 
    c=cal(a,b); 

    //Wrong outpur here 
    /*for(int i=0;i<5;i++) 
    { 
     cout<<*(c+i); 
    }*/ 

    //Correct output here 
    cout<<*(c+0); 
    cout<<*(c+1); 
    cout<<*(c+2); 
    cout<<*(c+3); 
    cout<<*(c+4); 

return 0; 
} 

int *cal(int *d, int *e) 
{ 
    int k[5]; 
    for(int j=0;j<5;j++) 
    { 
     *(k+j)=*(d+j)-*(e+j); 
    } 
    return k; 
} 
+10

Включите предупреждения своего компилятора, а затем прочитайте их. –

+1

Есть очень мало, если таковые имеются, случаи, когда вам нужно вернуть указатель из функции. По моему опыту, необходимость возврата указателя чаще всего возникает из-за неправильного дизайна программы. Чаще всего вы возвращаете результат через один из параметров и позволяете вызывающему абоненту беспокоиться о том, где распределять данные. – Lundin

+2

@ Lundin С несколькими заметными исключениями (например, функции поиска, которые могут завершиться неудачей). С другой стороны, возврат через один из параметров следует использовать только в случае крайней необходимости, когда профайлер говорит, что у вас нет выбора. В большинстве случаев правильным решением является возврат по значению. Что, конечно, означает не использование массивов стилей C (но это хорошая рекомендация в целом). –

ответ

1

int k[5] массив создается на стеке. Таким образом, он становится разрушенным, когда он выходит из сферы действия, возвращаясь с cal. Вы можете использовать третий параметр в качестве выходного массива:

void cal(int *d, int *e, int* k) 
{ 
    for(int j=0;j<5;j++) 
    { 
     *(k+j)=*(d+j)-*(e+j); 
    } 
} 

вызова cal так:

int a[]={5,6,7,8,9}; 
int b[]={0,3,5,2,1}; 
int c[5]; 
cal (a, b, c); // after returning from cal, c will be populated with desired values 
+0

Вы возвращаете значение в функцию возврата void! :) –

+0

@ another.anon.coward исправлено – Meysam

+0

Вы все еще играете с необработанными указателями, и в этом нет необходимости! – Johnsyweb

6

Вы возвращаете указатель на локальную переменную.

k создано в стеке. Когда cal() выходит из стека, он разматывается, и память свободна. После этого ссылка на память впоследствии приводит к неопределенному поведению (как это объясняется здесь красиво: https://stackoverflow.com/a/6445794/78845).

Ваш компилятор C++ должен предупредить вас об этом, и вы должны прислушаться к этим предупреждениям.

Для чего это стоит, вот как я бы реализовать это в C++:

#include <algorithm> 
#include <functional> 
#include <iostream> 
#include <iterator> 

int main() 
{ 
    int a[] = {5, 6, 7, 8, 9}; 
    int b[] = {0, 3, 5, 2, 1}; 
    int c[5]; 
    std::transform (a, a + 5, b, c, std::minus<int>()); 
    std::copy(c, c + 5, std::ostream_iterator<int>(std::cout, ", ")); 
} 

See it run!

+3

int k [5] будет уничтожен. – RvdK

+0

@PoweRoy: Разве это не может быть «может быть» уничтожено? Не гарантируется, что он будет уничтожен, не так ли? Это незаконный доступ наверняка, хотя ... –

+1

@ another.anon.coward: Он будет уничтожен, иначе RAII не будет работать. Не может ли гарантировать что-либо еще эта память. – Johnsyweb

0

Как уже отмечалось, вы возвращающая указатель на локальный переменной, которая неопределенное поведение. Однако реальная проблема - , что вам нужно вернуть массив, а массивы типов C сломаны. Замените свои массивы на std::vector<int>, забудьте о указателях (потому что вы имеете дело со значениями), и код будет работать.

+0

'std :: vector' (или даже valarray) здесь не требуется, но вы правы, нет необходимости в указателях. – Johnsyweb

+0

@Johnsyweb Для его конкретного примера 'std :: vector ' является очевидным и правильным решением. –

+0

В C++ 11 с списками инициалов я могу согласиться с вами, но «правильный» субъективен. Я думаю, например, что код, указанный в [моем ответе] (http://stackoverflow.com/a/8969311/78845), является «правильным», не использует контейнеры из стандартной библиотеки. – Johnsyweb

Смежные вопросы