注册 登录
编程论坛 C++教室

C++函数返回数组输出问题

ooole 发布于 2010-07-23 13:10, 3331 次点击
代码如下:
#include<iostream>
using namespace std;
int *test()
{
    int arr[] = {1,2,3,4,5};
    for(size_t i = 0 ; i < 5 ; ++i)
    {
        cout << &arr[i] << "\t" << arr[i] << endl;
    }
    return arr;
}
int main()
{
    int *p = test();
    for(size_t i = 0; i < 5 ; ++i)
    {
        cout << p << "\t" << *p <<endl;
        p = p + 1;
    }
    return 0;
}
在主函数里输出的时候只有第一个元素的输出是正确的,后面的四个元素都输出错误,而且后面四个元素每次的输出还不一样。请问这是怎么回事?
在test函数和主函数里输出的地址是一样的。

[ 本帖最后由 ooole 于 2010-7-23 13:12 编辑 ]
22 回复
#2
mxs8102010-07-23 13:34
int *test()
{
}
返回值就是一个int型的指针,
也就是说    int *p = test();
返回的p,只有*p是有意义的,后面的p = p + 1你那是非法操作~~
#3
mxs8102010-07-23 13:36
test的定义,建议声明称这样
bool test (int nTest[5]);
#4
tianxiao1102010-07-23 19:36
估计是这里错了:
程序的运行从 main 开始,首先执行这句int *p = test();  但是你可能忽略了,arr[]数组的内存是动态分配的,执行完一次test()内存会从新分配;因此执行完test()之后,p指的就不是数组的首地址了。

#5
pangding2010-07-23 23:53
这种在栈上分配内存的方法我们一般不叫动态分配。

楼主这个是个典型的错误,你可以跟踪一下程序,看看是怎么回事。上网查查资料,看能不能自己研究出来~
#6
ooole2010-07-24 09:02
回复 4楼 tianxiao110
我觉得p指的的应该是数组的首地址,因为我在test()打印的地址,和主函数里打印的地址是一样的
#7
ooole2010-07-24 12:01
回复 2楼 mxs810
我觉得P+1不是非法操作,因为我运行下面的语句得到的是正确的结果
p = p + 1;
cout << *p << endl;

p = p + 3;
cout << *p << endl;
这两种情况下的输出都是正确的
#8
ooole2010-07-24 12:04
回复 5楼 pangding
我按照你的提示自己研究了下,我觉得可能是作用域的问题,因为我将数组定义为全局变量后得到的结果是正确的,那可能就是,数组在调用完test函数后被撤消了,如果撤销的话那么应该所有的值都是错误的,但是我输出的时候第一个值是正确的,所以这个地方还有点疑惑
#9
ooole2010-07-24 12:05
回复 3楼 mxs810
不太明白你的意思,可以进一步解释下吗?
#10
南国利剑2010-07-24 14:10
回复 9楼 ooole
你的程序稍微做修改就没有问题了。这是我改的,我试过了,没有问题。
程序代码:
#include<iostream>
using namespace std;

int *test();

int main()
{
    int *p = test();
    int *n=p;
    for(size_t i = 0; i < 5 ; ++i)
    {
        cout << p << "\t" << *p <<endl;
        p = p + 1;
    }
    delete [] n;
    return 0;
}


int *test()
{
    int* arr=new int[5];
    for(int j=1,k=0;k<5;++j,++k)
        arr[k]=j;

    //int arr[] = {1,2,3,4,5};
    for(size_t i = 0 ; i < 5 ; ++i)
    {
        cout << &arr[i] << "\t" << arr[i] << endl;
    }
    return arr;
}

 
#11
tianxiao1102010-07-24 16:34
回复 6楼 ooole
  int*p=test();
这句是从右到左执行的,而第一个地址赋给了p,main函数不结束,p是不会释放的,而p里放的正是第一个元素的地址,因此第一个元素是对的而后面的就不对了;  而我上面所说的p不再指向数组的首地址,的意思是,虽然p里面保留了曾经数组的首地址,但此时p后面已经不是数组了。
#12
gq1987182010-07-24 17:04
觉得2楼是对的
#13
mxs8102010-07-24 22:42
仔细看了一下你的程序,发现问题啦:

问题就在于你的 int *p = test();执行后,
p指向了test()中的局部变量arr的首地址。
你要明白一点,int arr[] = {1,2,3,4,5};
这种方式声明的局部变量在test结束的时候就释放了,
你看到的int *p = test();执行后的p的确是指向了arr
的首地址,但是此时的这个地址是自由的内存了,
别的代码也可以再次申请使用了;
当调用到p = p + 1时,
这个地址的内存又被使用了,也就是在你印象中p指向了不明确的内容~~

也就是我前边说的p = p + 1是非法操作~~~

好好研究一下,变量的作用域,及合适申请、释放地址就明白了~~
#14
pangding2010-07-25 00:06
以下是引用ooole在2010-7-24 12:04:34的发言:

我按照你的提示自己研究了下,我觉得可能是作用域的问题,因为我将数组定义为全局变量后得到的结果是正确的,那可能就是,数组在调用完test函数后被撤消了,如果撤销的话那么应该所有的值都是错误的,但是我输出的时候第一个值是正确的,所以这个地方还有点疑惑

你用的是什么编译器?

test 中的那个数组的生命期确实已经没了。因此打出什么值都是有可能的(这种情况一般在C中称做未定义)。至于为什么第一个值总是对的,以后的值总不对是怎么个不对法?每次运行都不正确,还是有时正确有时不正确?是没次不正确的数都一样,还是每次不一样看上去像是没有规律?发生这种现像是原因与编译器的处理有关。
#15
ooole2010-07-25 09:46
回复 10楼 南国利剑
运行正常!按照我以前的做法在打印出第一个数组元素后整个数组空间都被撤销,所以后面的输出是错误的,而用动态数组的话如果不去释放空间那么数组中的元素就一直存在,直到程序运行完,不知道这样理解对不对,如果正确的话就可以结贴了!
#16
ooole2010-07-25 09:50
回复 11楼 tianxiao110
恩,我现在的理解和你差不多,不过我认为数组的撤销是发生在p的第一次输出之后,不管输出的是p+1的值还是p+2的值
#17
ooole2010-07-25 09:51
回复 13楼 mxs810
恩,谢谢,分析的很到位
#18
ooole2010-07-25 09:58
回复 14楼 pangding
就是说如果我打印*p则得到的是1,如果我打印*(p+2)则得到的是3,但是如果第一次打印的是*p得到正确结果,再去打印别的比如*(p+3)则得到的是错误结果,如果第一次打印*(p+2)得到的是正确的结果,然后再去打印别的比如*p则得到的是错误的结果,而且错误的结果是变化的不是固定值。
#19
南国利剑2010-07-25 12:20
回复 15楼 ooole
就是这样。虽然我们不必关心硬件,但是我们还是要清楚内存的分配情况的。
#20
pangding2010-07-26 00:01
反正这种回收了的空间就是不能再用了。使用动态分配就没问题。

不过像这种情况,要求调用者提供一个数组是更合理的。否则就会像这个例子这样,调个函数居然动态分配了空间,还得调用者想着回收。如果不是很了解那个函数的工作原理,非常容易忘记。是不好的实践方法。
不过作为演示程序理解栈分配和动态分配的区别,倒是还算合适~~
#21
saynotolx2010-07-26 17:22
顶顶顶顶顶!
#22
zhoufeng19882010-07-26 17:35
程序代码:
int *test()
{
    int arr[] = {1,2,3,4,5};
    for(size_t i = 0 ; i < 5 ; ++i)
    {
        cout << &arr[i] << "\t" << arr[i] << endl;
    }
    return arr;
}

小 哥,arr这个指针所指向的内存是调用test函数自动分配的,函数调用完了就释放了。你这种返回指针的做法是不好的。
你可以在
  int arr[] = {1,2,3,4,5};

前,加一个static,应该就不会出现你所说的问题 了。
#23
pangding2010-07-26 23:56
嗯,加个 static 就静态的了,存在数据段里。跟程序共存亡的,比堆分配的内存生命期还长。

不过它只在程序加载的时候初始化一次,有的时候用它不一定能达到目的。比较下面两个代码:
程序代码:

void test()
{
    int arr[] = {1,2,3,4,5};    /* static int arr[] = {1, 2, 3, 4, 5 }; */
    int i;
    for(i = 0 ; i < 5 ; i++)
    {
        cout << "a[" << i << "] = " << arr[i] << endl;
    }

    arr[1] += 2;
    for(i = 0 ; i < 5 ; i++)
    {
        cout << "a[" << i << "] = " << arr[i] << endl;
    }
}


没 static 的每次执行都是一样的結果,加了之后每次就不一样了。
如果这不是你期望的結果,那么在看代码时,又可能很难发现错误。所以 static 一般原则上不是很常用(其实是一般不这么用)。
1