在Dev-c ++和gcc 4.8.2

时间:2015-05-27 05:27:46

标签: c

#include<stdio.h>
#include<stdlib.h>
#define max 10
void init_graph(int arr[max][max],int v);
void create_graph(int arr[max][max],int v);
void print_graph(int  arr[max][max],int v);
int main()
{
    int v,n;
    printf("Enter the number of vertices :");
    scanf("%d",&v);
    int arr[v][v];
    init_graph(arr,v);
    printf("v=%d after init\n",v);
    create_graph(arr,v);
    print_graph(arr,v);
    return 0;
}
void create_graph(int arr[max][max],int v)
{
    printf("v=%d \n",v);
    int e;
    printf("Enter the number of edges :");
    scanf("%d",&e);
    int i,src=0,dest=0;
    for(i=0;i<e;i++)
    {
        printf("Enter Edge :%d",i+1);
        scanf("%d %d",&src,&dest);
        if(src<=-1 || src>=v)
        {
            printf("Invalid source vertex \n");
            i--;
            continue;
        }
        if(dest<=-1 || dest >=v)
        {
            printf("Invalid dest vertex \n");
            i--;
            continue;
        }
        //*(*(arr+src)+dest)=1;
        //*(*(arr+dest)+src)=1;
        arr[src][dest]=1;
        arr[dest][src]=1;
    }

}

void init_graph(int arr[max][max],int v)
{
    int i,j;
    for(i=0;i<v;i++)
    {
        for(j=0;j<v;j++)
        {
            //*(*(arr+i)+j)=0;
            arr[i][j]=0;
        }
    }
    printf("V=%d init_graph\n",v);
}

void print_graph(int arr[max][max],int v)
{
    int i,j;
    for(i=0;i<v;i++)
    {
        for(j=0;j<v;j++)
        {
            //printf("%d ",*(*(arr+i)+j));
            printf("%d ",arr[i][j]);
        }
        printf("\n");
    }
}

当我在Dev-c ++和gcc 4.8.2中编译上述程序时,我得到了不同的输出。在这里,我尝试使用邻接矩阵表示来表示图形。

当v作为参数传递给init_graph(arr,v)时(在上面的程序中),即使我没有从函数返回任何值,v的值在函数之后变为零被称为。

它在Dev-c ++中正常工作但我在gcc.4.8.2中编译时得到了错误的答案。

enter image description here

Dev-c ++中输出的屏幕截图

这里v不会变为0

enter image description here

gcc 4.8.2

中输出的屏幕截图

这里v变为0。

3 个答案:

答案 0 :(得分:2)

由于方式&#34;阵列&#34;功能参数是&#34;调整&#34;对于C中的指针,create_graph函数确实接受指向长度为max的数组的指针。它相当于:

void create_graph(int (*arr)[max], int v)

这意味着当你在循环中每次迭代arr[i]时,采用10个整数的步长,到下一个长度为10的数组。但是你传递(在数组衰减之后)一个指向长度为v的数组的指针。如果vmax不同,那就是未定义的行为(UB)。在你的情况下,这会让你超出范围,(这会在一个定义良好的程序中导致UB本身。)

您只能使用指向长度为max的数组的指针或内部数组长度为max的数组数组来调用该函数(后者将衰减为指向数组的指针。)

请注意,您看到的与平台相关的行为类型通常表示代码中存在UB。

答案 1 :(得分:2)

您正在调用该函数:

void init_graph(int arr[10][10], int v);

但是你的代码是:

int arr[v][v];
init_graph(arr,v);

如果v不是10,则会导致未定义的行为。 C11标准条款是6.5.2.2/6:

  

如果促销后的参数类型与参数类型不兼容,则行为未定义。

维度X的数组仅与兼容,如果X == Y,则维度为Y的数组。 (请记住,由于array as function parameter syntax quirk,最里面的维度会“丢失”,因此最内层的维度可能会有所不同而不会破坏兼容性。)

要解决此问题,您应该在函数原型中包含数组维度中的大小:

void init_graph(int v, int arr[v][v]);

和其他功能类似。

答案 2 :(得分:1)

main()中,您将数组定义为[v][v],但init_graph()采用大小为[max][max]的数组。你需要使它们相同。我建议更改main(),因为所有其他函数也使用max作为数组大小。

v为5时,您的[5][5]数组将被列为25个连续的整数。但该函数认为数组的大小为[][10],行大小为10个整数。所以,当你写入超过[2][4](第25个元素)的任何元素时,你正在写出数组的末尾并破坏你的堆栈。这是因为main()中的数组被定义为局部变量,因此位于堆栈中。在您的情况下,堆栈还包含v的值,并且它被0覆盖。其他编译器工作的原因可能是因为它在数组之前将v放在内存中而不是之后,所以使用该编译器,它不会发生在clobber v

根据其他答案,使用不正确的参数调用函数会调用“未定义的行为”,但我发现这是一个懒惰的解释(“任何事情都可能发生”)。当人们说因为任何已编译的程序都是已知数量时,我讨厌它,你可以确切地确定“未定义”行为实际上是什么(只需用调试器逐步完成它)。一旦了解了正在发生的事情以及变量所在的位置,您就会开始直观地了解内存何时被破坏以及哪些代码可能对其负责。