#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中编译时得到了错误的答案。
Dev-c ++中输出的屏幕截图
这里v不会变为0
gcc 4.8.2
中输出的屏幕截图这里v变为0。
答案 0 :(得分:2)
由于方式&#34;阵列&#34;功能参数是&#34;调整&#34;对于C中的指针,create_graph
函数确实接受指向长度为max
的数组的指针。它相当于:
void create_graph(int (*arr)[max], int v)
这意味着当你在循环中每次迭代arr[i]
时,采用10个整数的步长,到下一个长度为10的数组。但是你传递(在数组衰减之后)一个指向长度为v
的数组的指针。如果v
与max
不同,那就是未定义的行为(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
。
根据其他答案,使用不正确的参数调用函数会调用“未定义的行为”,但我发现这是一个懒惰的解释(“任何事情都可能发生”)。当人们说因为任何已编译的程序都是已知数量时,我讨厌它,你可以确切地确定“未定义”行为实际上是什么(只需用调试器逐步完成它)。一旦了解了正在发生的事情以及变量所在的位置,您就会开始直观地了解内存何时被破坏以及哪些代码可能对其负责。