在C语言中返回整型数组

3

我有这段代码:

 1 #include <stdio.h>                                                               
 2 #include <string.h>                                                              
 3 #define LENGTH(a) sizeof(a)/sizeof(a[0]);                                        
 4                                                                                  
 5 int *getNbits(int, int, char *);                                                 
 6                                                                                  
 7 int main() {                                                                     
 8    char ins[] = "00001111000011110000111100001111";                              
 9    int *x = getNbits(0, 32, ins);                                                
 10                                                                                  
 11    for (int i = 0; i < LENGTH(x) ; i++){                                                
 12                                                                                  
 13       printf("%d", *(x + i));                                                        
 14    }                                                                             
 15    return 0;                                                                     
 16 }                                                                                
 17                                                                                  
 18 int* getNbits(int start, int offset, char instr[33]) {                           
 19                                                                                  
 20    int result[offset - 1];                                                       
 21    for (int i = 0; i < offset; i++) {                                            
 22        result[i] = instr[i + start] == '1' ? 1 : 0;   //- '0';                   
 23    }                                                                             
 24    return result;                                                                
 25 }         

基本上,getNbits()会获取一个由字符组成的数组(这些字符是0或1),并返回一个由整数组成的数组,每个元素都是0或1。
如果我尝试在for循环中创建数组“result”时将其打印出来(使用printf(“%d”,result [i])),它将返回000011110000.....。
但是我遇到了返回类型的问题,它给了我一个警告:函数返回局部变量的地址。而且main中的for循环只会打印垃圾值。

在您的getNbits函数中,int result只存在于getNbits调用的持续时间内。它是在堆栈上分配的数组。当函数返回时,该堆栈空间将被释放,并且调用代码将不再可用。您可能会运气好,仍然保留了堆栈的那一部分,但这是一种竞争条件,某些时候该堆栈区域将被其他代码覆盖。 - Marc B
#define LENGTH(a) sizeof(a)/sizeof(a[0]) - BLUEPIXY
1
@MarcB:“你可能会走运,仍然保留了栈的那一部分未被触及” - 那将是明显的不幸。 - Ed S.
那我应该使用malloc()在堆中获取数组,以便在方法调用后能够检索数组吗? - Daniel Hernandez
是的。而且 LENGTH(x) 是一个错误,不能用于指针(不是数组)。 - BLUEPIXY
2
不需要使用 malloc,您可以从调用函数声明一个本地数组并将其传递给被调用函数。 - phuclv
3个回答

3

result变量仅局限于getNbits函数。这意味着它可能会在函数返回后被解除分配。

不要将局部变量的地址作为指针返回,因为它可能会被解除分配。

相反地,请使用此方式分配整数:

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

然后从getNbits返回retVal
查看此URL: http://ww2.cs.mu.oz.au/~mgiuca/253/malloc.html 注意:如果您在上面使用malloc,则必须在不再需要分配的内存后使用free释放它:
/* When the array is no longer needed */ 
free(x);

在释放内存时,变量名为x,因为这是从调用getNbits分配的lvalue。不要从getNbits中调用free


非常感谢!我发现malloc的信息非常有用。它甚至使用类似于我的代码作为糟糕编码的明确示例。 - Daniel Hernandez
没问题;如果还有什么我可以帮忙的,请告诉我。 - A B
malloc的结果强制转换是不好的做法(请参见https://dev59.com/dHRB5IYBdhLWcg3wgHWr),您应该从答案中删除它。 - Henrik
更新以删除类型转换;malloc将返回指向void的指针,因此类型转换将被隐含。 - A B
为什么要调用malloc?让调用者根据需要自动、静态或动态地分配数组即可。 - Rob11311
1
这是正确的;我使用了malloc,因为在这个问题的代码中,getNBits的定义假定返回值是一个新分配的数组。 - A B

2
int* getNbits(int start, int offset, char instr[33]) {                           
   int result[offset - 1];                                                       
   for (int i = 0; i < offset; i++) {                                            
      result[i] = instr[i + start] == '1' ? 1 : 0;   //- '0';                   
   }                                                                             
   return result;     
}

整型数组result默认在堆栈上被声明,这意味着它的作用域(生命周期)仅限于getNbits()函数内部。将对此数组的引用传递到函数外部并不是一个好主意,因为数组原本所占用的堆栈空间将被用于其他目的。

通过在堆上分配数组可能会更好地完成相同的操作:

int* getNbits(int start, int offset, char instr[33]) {                           
   int *result = malloc(offset * sizeof(*result));  // As indicated by BLUEPIXY's comment
   if(NULL == result)
      {
      fprintf(stderr, "malloc() failed\n");
      goto CLEANUP;
      }

   for (int i = 0; i < offset; i++) {                                            
      result[i] = instr[i + start] == '1' ? 1 : 0;   //- '0';                   
   }    

CLEANUP:                                                                         
   return result;     
}

当然,在上述情况下,调用getNbits()的函数必须记得在不再需要返回的分配内存时调用free(),以将分配的内存返还给堆。


0

在主函数中分配数组,即在调用结果数组的地方,可以使代码更简单、更少出错。

int result[ sizeof ins];    /* Size known at compile time */

getNbits(0, 32, ins, result);  /* Pass arrays by reference */

void getNbits(int start, int offset, const char instr[], int result[]) {

这是在堆栈上使用自动存储,当例程返回时会自动回收。目前的代码中,printf在堆栈上分配的变量将覆盖result指向的值。

优点是通用化getNbits子程序,使其适用于更长版本的“ins”。当然,真正的程序会通过getNbits返回错误状态以捕获错误。

在函数中malloc内存并让调用者负责释放不是好的实践方法,它很可能会泄漏或在更复杂的程序中被多次释放,这些常常是难以追踪的错误。

传统代码通常定义结构体或数组,并将其作为静态存储从函数中传递,因此地址不在堆栈上。这种方法可行,但不是线程安全的,而且必须复制存储在数据结构中的任何值。

如果您编写了一个动态构建数据结构的库函数,那么请与一个清理例程配对,而不是将实现细节泄漏到调用者的程序中!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接