为什么变量在递归调用中获得相同的地址?

时间:2015-05-04 07:51:39

标签: c arrays pointers recursion

/* Calculating minimum and maximum element out of a list of elements using Recursion
Input: A list of numbers
Output: Minimum and Maximum number 
*/

#include<stdio.h>

int a[8]={6,2,3,9,1,0,11,8},size=8;

int * minmax(int beg,int end)
{
    int res[2],*x,*y,mid;
    printf("%d %d %p:",beg,end,res);
    if(beg==end)
    {
        res[0]=a[beg];
        res[1]=a[beg];  
        return res;    
    }      
    if(end-beg==1)
    {
        if(a[beg]<=a[end])
        {    
            res[0]=a[beg];
            res[1]=a[end];
        }
        else
        {
            res[0]=a[end];
            res[1]=a[beg];
        }
        printf("%d %d",res[0],res[1]);
        printf("\n");
        return res;
    }
    printf("\n");
    mid=(beg+end)/2;    
    x=minmax(beg,mid);
    y=minmax(mid+1,end);         
    if(x[0]<=y[0])
        res[0]=x[0];
    else if(x[0]>y[0])
        res[0]=y[0];   
    if(x[1]<=y[1])
        res[1]=y[1];
    else if(x[1]>y[1])
        res[1]=x[1];
    printf("OUT: %d %d %d %d WIN: %d %d\n",x[0],y[0],x[1],y[1],res[0],res[1]);
    return res;      
}

int main()
{
    int i,j,min,max,*ans;
    ans=minmax(0,size-1);
    printf("Ans=%d %d",ans[0],ans[1]);
    return 0;
}

在上面的代码中,使用递归获取最小和最大元素,数组res在连续的递归调用中得到相同的地址,如下所示:

    0 7 0xbfa9cb08:
    0 3 0xbfa9cac8:
    0 1 0xbfa9ca88:2 6
    2 3 0xbfa9ca88:3 9 
    OUT: 3 3 9 9 WIN: 3 9
    4 7 0xbfa9cac8:
    4 5 0xbfa9ca88:0 1 
    6 7 0xbfa9ca88:8 11 
    OUT: 8 8 11 11 WIN: 8 11
    OUT: 8 8 11 11 WIN: 8 11
    Ans=8 11  

在函数调用minmax(0,1)minmax(2,3) res获取相同的地址,这就是它产生问题的原因。在minmax(4,5)minmax(6,7)

可以观察到类似的事情

为什么会发生这种情况,如何修改程序以获得最低和最高

3 个答案:

答案 0 :(得分:3)

您无法返回自动变量的地址。正如WhozCraig所述,它是undefined behavior。顺便说一句,如果您启用所有警告和调试信息(例如,如果使用GCC,则使用gcc -Wall -Wextra -g进行编译),您会收到警告。

您应该返回struct两个数字,例如声明为

struct myminmax_st {
   int mymin;
   int mymax;
};
struct myminmax_st minmax(int *arr, int beg, int end);

struct myminmax_st 
minmax(int *arr, int beg, int end)
{
   struct myminmax_st res = { INT_MIN, INT_MAX };
   if(beg==end) { 
       res.mymin = arr[beg];
       res.mymax = arr[end];
       return res;
   }

我留给你完成那个例程。您需要#include <limits.h>才能获得INT_MIN&amp; INT_MAX

请注意,在Linux / x86-64上,ABI指定返回带有两个整数的struct非常快:它们在两个寄存器中返回。 (这特定于具有两个标量字段的struct

您可以将生成的min和max的地址作为正式参数传递,如MiteshMS answer中所述(但在Linux / x86-64上可能会慢一点,因为这样你就可以通过内存)。 / p>

同样在C数组中衰减为指针,因此您无法返回数组(除非您将其打包在某些struct中);你可以返回一个指向某个数组的指针(通常是heap-allocatedmalloc)。在这种情况下 - 作为指针返回的堆分配数组 - 您需要一些记录的约定关于谁负责free -

答案 1 :(得分:1)

这是实现MaxMin算法的另一种方法,这里每次递归调用都会更新max和min变量。

这种方式使用数组或结构,类似于您最初编码的方式。

#include<stdio.h>
#include<stdlib.h>
void maxmin(int a[],int low,int high,int *min,int *max);
int a[8]={6,2,3,9,1,0,11,8}, n=8;

void main()
{
        int i,low,high,max,min;
        low=0;
        high=n-1;
        maxmin(a,low,high,&min,&max);
        printf("Minimum value is %d\n",min);
        printf("Maximum value is %d\n",max);
}

void maxmin(int a[],int low,int high,int *min,int *max)
{
    int mid,min1,max1,min2,max2;
    if(low==high)//For 1 element min and max will be same
    {
        *min=a[low];
        *max=a[high];
    }
    else if(low==high-1)//For two elements
    {
        if(a[low]>a[high])
        {
            *max=a[low];
            *min=a[high];
        }
        else
        {
            *max=a[high];
            *min=a[low];
        }
    }
    else//for more than 2 elements
    {
        mid=(low+high)/2;
        maxmin(a,low,mid,&min1,&max1);//Dividing
        maxmin(a,mid+1,high,&min2,&max2);
        if(min1<min2)//Combining
            *min=min1;
        else
            *min=min2;
        if(max1>max2)
            *max=max1;
        else
            *max=max2;
    }
}

我尝试以不同方式声明res []来搞乱你的代码。将它声明为一个结构将像Basile在另一个答案中指出的那样工作,但你可以使用上面的代码来坚持直观的基本指针。

答案 2 :(得分:-2)

C不允许返回指向自动数组的指针,因为它在函数末尾超出范围并在使用之前被释放。

在这种情况下(递归),你也不能使用静态变量,因为所有堆叠的调用都会使用相同的变量。

所以,你只剩2路了:

  • 让调用者分配数组并将其传递给被调用者:

    void minmax(int beg,int end, int *res)
    {
        int x[2], y[2],mid;
        ...
        mid=(beg+end)/2;    
        minmax(beg,mid, x);
        minmax(mid+1,end, y);         
        ...
        printf("OUT: %d %d %d %d WIN: %d %d\n",x[0],y[0],x[1],y[1],res[0],res[1]);
    }
    
    int main()
    {
        int i,j,min,max;
        int ans[2];
        minmax(0,size-1, ans);
        ...
    
  • 在callee中使用动态分配并传递动态分配数组的地址,但是必须在调用者中释放它

    int* minmax(int beg,int end)
    {
        int *res, *x, *y,mid;
        *res = calloc(2, sizeof(int));
        ...
        mid=(beg+end)/2;    
        x = minmax(beg,mid);
        y = minmax(mid+1,end);         
        ...
        printf("OUT: %d %d %d %d WIN: %d %d\n",x[0],y[0],x[1],y[1],res[0],res[1]);
        free(x);
        free(y);
        return res;
    }
    
    int main()
    {
        int i,j,min,max;
        int *ans;
        ans=minmax(0,size-1, ans);
        printf("Ans=%d %d",ans[0],ans[1]);
        free(ans);
        return 0;
    }
    

但是我忘记了Basile Starynkevitch给出的第三种方法:使用结构,因为你可以返回一个自动结构。