#include<stdio.h>
int main() {
int i;
goto l;
for(i = 0; i < 5; i++) {
l:printf("Hi\n");
}
return 0;
}
上面的代码给出了三次输出Hi。我不知道它是怎么发生的,请你说出来。如果我减少5到3的值,那么只有Hi打印一次。
答案 0 :(得分:2)
您正在进行比较i < 5
并在i
循环中递增for
而不首先初始化导致未定义的行为(此时 i
的值是一个随机的垃圾值)
如果你试试这个
#include<stdio.h>
int main()
{
int i = 0;
goto l;
for(i = 0 ; i < 5 ; i++)
l: printf("Hi\n");
return 0;
}
它将定义行为,此程序将打印Hi
5次。
要看看发生了什么,请尝试
#include<stdio.h>
int main()
{
int i = 4;
goto l;
for(i = 0 ; i < 5 ; i++)
l: printf("Hi\n");
return 0;
}
和Hi
只会打印一次,因为一旦您输入for
循环,i == 4
。
所以基本上你正在跳这一行
for(i = 0 ; i < 5 ; i++)
由于上述原因,未能初始化i
并因此导致未定义的行为。
使用goto
并不总是坏事,但是当它用于控制程序流程时,很难遵循代码并理解它的作用,而且通常不需要那,但它在某些情况下确实有用,例如考虑这种情况
FILE *file;
int *x;
int *y;
file = fopen("/path/to/some/file", "r");
if (file == NULL)
return IO_ERROR_CODE;
x = malloc(SomeSize * sizeof(int));
if (x == NULL)
{
fclose(file);
return MEMORY_EXHAUST_ERROR_CODE;
}
y = malloc(SomeSize * sizeof(int));
if (y == NULL)
{
free(x);
fclose(file);
return MEMORY_EXHAUST_ERROR_CODE;
}
return SUCESS_CODE;
所以你必须在每个函数出口点添加越来越多的代码,但你可以这样做
FILE *file = NULL;
int *x = NULL;
int *y = NULL;
file = fopen("/path/to/some/file", "r");
if (file == NULL)
return SOME_ERROR_CODE;
x = malloc(SomeSize * sizeof(int));
if (x == NULL)
goto abort;
y = malloc(SomeSize * sizeof(int));
if (y == NULL)
goto abort;
return SUCCESS_CODE;
abort:
if (x != NULL)
free(x);
if (y != NULL)
free(y);
if (file != NULL)
fclose(file);
return MEMORY_EXHAUST_ERROR_CODE;
当然,在您的示例中,绝对没有理由使用goto
。
答案 1 :(得分:2)
您的代码展示Undefined Behavior。这是因为当程序的执行到达goto
语句时,程序的执行会跳转到for
循环的主体内部,从而跳过for
循环的初始化部分。因此,i
未初始化,并且包含&#34;垃圾值&#34;。
作为旁注:Using goto
s are considered to be bad practice因为它使您的代码更难以阅读/维护。