如何从函数返回定义的类型(数组)?

时间:2015-08-21 18:39:24

标签: c arrays function return typedef

当我尝试从函数返回类型verylongint的值时,我收到错误。什么是正确的返回方式? verylongint是long long int类型的数组,在第5行中定义。 返回一个非常长的函数应该是string2verylongint(char * n)。编译器的输出低于源代码。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SIZE 63

typedef long long verylongint[63];

char* verylongint2string(verylongint n);
verylongint string2verylongint(char* n);

main(){
    verylongint n;
    int i;
    for(i=0; i<SIZE; i++)n[i]=0; //initialize
    n[0]= 999999999999999999;
    n[1]= 999999999999999999;
    n[2]= 2323232311;
    printf("%s\n", verylongint2string(n));

    verylongint m;
    m = string2verylongint("123999999999999999999999999999999999999999999999999999999");

    printf("%s\n", verylongint2string(m));
}

verylongint string2verylongint(char* n){
    char m[18]; // first long long element, which is not zero, as string
    sscanf(n, "%[^9]", m);
    long long n1; // as long long
    sscanf(m, "%lld", &n1);
    int length= strlen(n)-strlen(m); // length of string without the first element
    int i;
    verylongint k; //return value
    for(i=0; i<SIZE; i++)k[i]=0; //initialize
    for(i=0; i<length/18; i++){ // length/18 is the number of elements (without 1st)
        k[i]=999999999999999999;
    }   
    k[i] = n1;

    printf("%s\n", verylongint2string(k));

    return k;
}

char* verylongint2string(verylongint n){
    char* string = (char*) malloc(18*63*sizeof(char));//18 is the length of the biggest number
                            //63 is the length of the long-array
    int i=SIZE;
    while(n[--i]==0);
    //string=n[i];
    sprintf(string, "%lld", n[i]); //first number, which is not zero
    while(--i>=0){ //adding the biggest number
        strcat(string,"999999999999999999"); //the biggest number(one char smaller than lld)
    }

    return string;
}

输出:

user@user-VirtualBox:~/Documents$ gcc verylongint.c -o vli
verylongint.c:9:13: error: ‘string2verylongint’ declared as function returning an array
 verylongint string2verylongint(char* n);
             ^
verylongint.c: In function ‘main’:
verylongint.c:21:4: error: incompatible types when assigning to type ‘verylongint’ from type ‘int’
  m = string2verylongint("123999999999999999999999999999999999999999999999999999999");
    ^
verylongint.c: At top level:
verylongint.c:26:13: error: ‘string2verylongint’ declared as function returning an array
 verylongint string2verylongint(char* n){
             ^
verylongint.c: In function ‘string2verylongint’:
verylongint.c:42:2: warning: return makes integer from pointer without a cast [enabled by default]
  return k;
  ^
verylongint.c:42:2: warning: function returns address of local variable [-Wreturn-local-addr]

2 个答案:

答案 0 :(得分:0)

如评论中所述,数组不能是函数的返回值。您需要将数组作为参数传入。由于传入函数的数组会衰减为指向第一个元素的指针,因此对函数中数组的更改将反映在调用者中。

另外,verylongint2string为其结果分配缓冲区但从未在任何地方释放,导致内存泄漏。考虑到你如何使用它,你可以使用固定长度的静态变量,虽然这意味着你不能在同一个语句中调用它两次,或者在多线程应用程序中使用它而不调用未定义的行为。 / p>

答案 1 :(得分:0)

C语言暴露了一种非常奇怪的数组行为。 你可以找到大量关于数组衰减到标准的标准的引用特殊行为是在某些情况下等等。那些评论来自阅读(在某些情况下误解标准)从70年代开始就没有生活过C语言的开发。 C作为汇编程序和高级语言之间的中间语言而诞生,目的是编写OS代码块,其中复杂数据结构并排请求访问HW寄存器,处理hw I / O等

那时保留一个存储区来容纳一些相同类型的变量称为数组。那么如何使用这样的数据呢?很简单,您可以使用内存区域基地址访问所有阵列数据。 但这偶然是数组第一个元素的地址。从那时起,我们可以说对数组名称的任何引用都等同于对第一个元素的地址的引用:

array => &array[0];

这背后的真正原因是汇编程序(低级)端编译器生成的代码如下:

array db 10 dup (0)

对于代码中对数组的任何引用:

lea eax, array

它是数组的基址。

除了语言的规范之外,将数组名称与其第一个元素的地址相关联是一个实用的规则。

但是指针变量也包含一个地址,所以如果我们得到一个地址,它应该来自一个数组还是一个指针,我们可以应用相同的模式来访问数据:

movsx eax, byte ptr [eax+4]    //read in eax, extendid the sign, the 5th element of the array pointed by eax

发出的代码只有很小的差异。假设我们有:

int a[10];
int *p = a;
foo(a[3], p[3]);

将编译为:

a DW 10 DUP(?)   //An array of 10 ints uninitialized
p DW a           //a pointer initialized to a address
....
lea eax, p    //Get the address of the pointer
mov eax, DWORD PTR [eax]    //Get the base address of array memory
mov eax, DWORD PTR [eax+0xC]  //0xC is the offset of the 3rd element (3 * 4bytes)
push eax      //Push second parameter
lea eax, a    //Get the address of the array
mov eax, DWORD PTR [eax+0xC]  //0xC is the offset of the 3rd element (3 * 4bytes)
push eax      //Push first parameter (C pushes parameters right to left)
call foo

正如你所看到的,唯一的区别是使用指针我们必须从中读取数组基地址,而使用数组时,汇编程序会给我们正确的数据地址。

然后对数据的访问完全相同。这是因为在许多情况下,C中的指针和数组的行为几乎相同。实际规则再一次成为语言规则......

当时,当记忆被计入 K ilo B ytes(而不是GB!)来移动大块内存时,这是无稽之谈。从这里得到另一条规则:数组必须仅通过引用传递给函数,并且此作业由编译器自动生成。 最后函数永远不会返回数组

现在回到你的代码有2个错误:你不能从函数返回一个数组,而你不必返回局部变量因为它们只存在于函数范围内当函数返回给出垃圾和UB(未定义行为)时结束。

但是你可以使用指针从动态内存创建一个数组,并返回这个指针:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SIZE 63

typedef long long verylongint[63];

char *verylongint2string(verylongint *n);
verylongint *string2verylongint(char *n);

int main(int argc, char *argv[])
{
    verylongint n;
    int i;
    for (i = 0; i < SIZE; i++)
        n[i] = 0;   //initialize
    n[0] = 999999999999999999;
    n[1] = 999999999999999999;
    n[2] = 2323232311;
    printf("%s\n", verylongint2string(&n));

    verylongint *m;    //m now is a pointer to the array
    m = string2verylongint("123999999999999999999999999999999999999999999999999999999");

    printf("%s\n", verylongint2string(m));
}

verylongint *string2verylongint(char *n)
{
    char m[18]; // first long long element, which is not zero, as string
    sscanf(n, "%[^9]", m);
    long long n1;   // as long long
    sscanf(m, "%lld", &n1);
    int length = strlen(n) - strlen(m); // length of string without the first element
    int i;
    verylongint *k = malloc(sizeof(verylongint));   //return value
    for (i = 0; i < SIZE; i++)
        (*k)[i] = 0;    //initialize
    for (i = 0; i < length / 18; i++)
    {   // length/18 is the number of elements (without 1st)
        (*k)[i] = 999999999999999999;
    }
    (*k)[i] = n1;

    printf("%s\n", verylongint2string(k));

    return k;
}

char *verylongint2string(verylongint *n)
{
    char *string = (char *)malloc(18 * 63 * sizeof(char));  //18 is the length of the biggest number
    //63 is the length of the long-array
    int i = SIZE;
    while (n[--i] == 0) ;
    //string=n[i];
    sprintf(string, "%lld", (*n)[i]);   //first number, which is not zero
    while (--i >= 0)
    {   //adding the biggest number
        strcat(string, "999999999999999999");   //the biggest number(one char smaller than lld)
    }

    return string;
}

享受。