从C中的函数返回数组

时间:2014-06-30 17:40:58

标签: c arrays function pointers scope

由于某种原因,我的函数只返回数组中的第一个元素,我无法弄清楚为什么数组的其余部分超出了范围。该函数接受两个整数数组,添加它们各自的元素,并将总和放入第三个返回的数组中。

这是我的代码:

#include <stdio.h>
/* count digits, white space, others */

int *sumarrays(int arr1[], size_t arr1len, int arr2[], size_t arr2len);

void main() {

    int arr1[10];
    size_t arr1len = 10;
    int arr2[10] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
    size_t arr2len = 10;
    int i;

    int *x;

    arr1[0] = 2;
    arr1[1] = 3;
    arr1[2] = 2;
    arr1[3] = 2;
    arr1[4] = 2;
    arr1[5] = 2;
    arr1[6] = 3;
    arr1[7] = 2;
    arr1[8] = 2;
    arr1[9] = 2;

    //printf("%d\t%d\t%d\n", arr1, *arr1, *(arr1 + 1));
    x = sumarrays(arr1, arr1len, arr2, arr2len);

    for (i = 0; i < 10; i++) {
        printf("Array1: %d\tArray 2: %d\tX = %d\n", arr1[i], arr2[i], x[i]);

    }

    //return 0;
}

int *sumarrays(int arr1[], size_t arr1len, int arr2[], size_t arr2len) {
    int i;
    int total[10];

    for (i = 0; i < 10; i++) {
        total[i] = *(arr1 + i) + *(arr2 + i);

    }
    for (i = 0; i < 10; i++) {
        printf("%d\t", total[i]);
    }

    printf("\n");
    return total;
}

这是输出:

4   5   4   4   4   4   5   4   4   4   
Array1: 2   Array 2: 2  X = 4
Array1: 3   Array 2: 2  X = 1974388256
Array1: 2   Array 2: 2  X = -161927102
Array1: 2   Array 2: 2  X = 2686628
Array1: 2   Array 2: 2  X = 8670801
Array1: 2   Array 2: 2  X = 0
Array1: 3   Array 2: 2  X = 27
Array1: 2   Array 2: 2  X = 2686540
Array1: 2   Array 2: 2  X = 4
Array1: 2   Array 2: 2  X = 2686916

第一行是函数中的sum数组元素。剩下的就是main()中发生的事情。

我错过了什么?

*编辑* 答案

谢谢大家的帮助!我实际上不久前学过C和C ++,但最近开始回过头来调整我的知识。非常感谢所有的帮助。

主要答案是

1)静态分配内存(使用static关键字)

2)动态分配内存(使用malloc())

3)使变量成为全局

4)将结果total()作为参数传递给函数,使其不会超出范围。

5 个答案:

答案 0 :(得分:2)

您正在为您的阵列进行堆栈分配,并且当函数返回时,堆栈分配的存储会消失。改为使用堆分配。

更改

int total[10];

int* total = malloc(10*sizeof(int))

当然,这意味着你完成后还必须free内存。在这种情况下,在main return 0;之前,您需要

free(x);

答案 1 :(得分:2)

  

我的函数只返回数组中的第一个元素,我无法弄清楚为什么数组的其余部分超出了范围。

不,它返回指向第一个元素的指针 - 整个数组超出范围。你看到的任何数据碰巧都保留在函数中,这是运气而不是判断,你不能使用它,因为它被释放供其他函数使用。

C中的数组不是first class data types - 您无法通过副本返回数组。

正常的解决方案是让调用者拥有该数组,并将其地址和大小传递给该函数。

int* func( int* arr, int arrlen )
{
    // write to arr[0] to arr[arrlen-1] ;

    return arr ;
}

int main()
{
    int array[256] ;
    func( array, sizeof(arr)/sizeof*(*arr) ) ;
}

其他不太常见且通常不明智的可能性是返回包含数组的结构(结构是第一类数据类型),但是在许多情况下这样做效率有点低,或者在内部动态分配数组函数,但它不是一个特别好的主意,因为调用者有责任释放内存,可能不知道这个责任 - 这是内存泄漏的一个秘诀。

答案 2 :(得分:1)

您无法返回指向自动本地变量的指针。 total是一个自动局部变量,在执行函数体之后它不存在。

可以返回指向static局部变量或动态分配变量的指针。更改
int total[10];

int *total = malloc(10 * sizeof(int));

答案 3 :(得分:1)

问题是当sumarrays返回时,total数组不再存在 1 ,因此指针值为{{1} } receive不再有效。简而言之,您无法从这样的函数返回数组。

您有几种选择。

第一个(和IMO首选选项)是将main数组作为您的参数之一传递,并让调用者负责留出足够的内存:

total

在这种方法中,调用者(void sumarrays(int arr1[], size_t arr1len, int arr2[], size_t arr2len, int *total, size_t totallen) { ... for (i = 0; i < totalLen; i++) { total[i] = *(arr1 + i) + *(arr2 + i); ... } #define ARRLEN 10 int main( void ) { ... int x[ARRLEN]; ... sumarrays( arr1, ARRLEN, arr2, ARRLEN, x, ARRLEN); )负责知道目标数组需要多大,并为其留出内存。帮助main函数与sumarrays分离,因为它不必依赖于参数列表未明确指定的信息(例如数组大小)。使用这种方法,您不仅限于大小为10的数组。

第二个选项是声明main,使其在total退出后不会消失。您可以通过在文件范围内声明(如ryyker的答案)或在sumarrays函数中声明static来执行此操作:

sumarrays

使用这种方法,int *sumarrays(int arr1[], size_t arr1len, int arr2[], size_t arr2len) { int i; static int total[10]; ... 数组将在程序启动时分配并保持到程序终止。使这种方法不那么令人满意的原因是,您只有total个数组的单个实例,该数组在total的所有调用中共享。该功能不再是重入;如果sumarrays调用另一个调用sumarrays的函数,则第一次调用写入sumarrays的任何内容都会被第二次调用破坏(total库函数有此问题,这在过去引起了很多胃灼热)。您的代码显然没有这个问题,但需要注意一些事项。如果您不必,请不要声明strtok件事。

最后一个选项是static动态分配sumarrays的内存(如haccks&#39;和merlin2011&#39;答案)。这避免了重入问题,但现在你必须处理内存管理。 C不是您的母亲,并且不会在您之后进行清理,因此您使用totalmalloc分配的任何内存都必须与calloc 2一起发布

<小时/> 1。从逻辑上讲,无论如何;内存显然仍然存在,但它已经可供系统的其余部分使用,并且在程序返回free功能所花费的时间内被覆盖。

2.大多数平台将在程序退出时回收动态分配的内存,但少数(不可否认是较旧的,古怪的平台)可能不会。此外,对于长时间运行的程序(服务器,守护程序等),您必须非常小心地释放您分配但不再需要的任何内存,否则您最终会耗尽。

答案 4 :(得分:0)

我同意关于自动(堆栈)和堆内存的所有其他答案。所有好的方法,但堆栈上的 全局变量也是一个选项 。重要的是要注意,您选择使用堆栈内存,但它也是本地范围。当创建它们的函数返回时,本地范围的自动变量会死亡。但是,全局范围的变量(也使用堆栈存储器存储)在程序的持续时间内存在,因此提供了另一种方法来解决您的问题......

一行更改 将导致代码运行,将total(自动范围)的本地副本更改为全局:

int total[10];//Put this here,  outside of any function block in same file, i.e. (will give it global scope)
//note, commented this in function below

int *sumarrays(int arr1[], size_t arr1len, int arr2[], size_t arr2len) {
    int i;
    //int total[10];//move this to global scope


    for (i = 0; i < 10; i++) {
        total[i] = *(arr1 + i) + *(arr2 + i);

    }
    for (i = 0; i < 10; i++) {
        printf("%d\t", total[i]);
    }

    printf("\n");
    return total;
}

使用此方法 ,全局变量范围可让您的返回成功。在程序退出之前,数组total会将其保留在堆栈中。