在哪里可以和不能在C中声明新变量?

我(可能是从老师那里)听说,应该在程序/函数之上声明所有变量,并且在声明中声明新变量可能会引起问题。


但是后来我读了《 K&R》,我碰到了这句话:“变量的声明(包括初始化)可能会在左括号后面加上任何复合语句,而不仅仅是开始一个函数的语句。” 他举了一个例子:


if (n > 0){

    int i;

    for (i=0;i<n;i++)

    ...

}

我对这个概念有所了解,它甚至适用于数组。例如:


int main(){

    int x = 0 ;


    while (x<10){

        if (x>5){

            int y[x];

            y[0] = 10;

            printf("%d %d\n",y[0],y[4]);

        }

        x++;

    }

}

那么,什么时候才不允许我声明变量?例如,如果我的变量声明在右括号之后不正确怎么办?像这儿:


int main(){

    int x = 10;


    x++;

    printf("%d\n",x);


    int z = 6;

    printf("%d\n",z);

}

根据程序/机器,这会引起麻烦吗?


有只小跳蛙
浏览 527回答 3
3回答

智慧大石

我也经常听到把变量放在函数顶部是最好的处理方法,但是我非常不同意。我更喜欢将变量限制在尽可能小的范围内,这样变量被滥用的机会就更少了,因此,在程序的每一行中填满我的思维空间的东西也就更少了。尽管所有版本的C都允许词法块作用域,但是您可以在其中声明变量取决于目标C语言版本:从C99开始或C ++诸如gcc和clang之类的现代C编译器支持C99和C11标准,这些标准允许您在可能进行语句的任何地方声明变量。变量的范围从声明的点开始到块的末尾(下一个大括号)。if( x < 10 ){&nbsp; &nbsp;printf("%d", 17);&nbsp; // z is not in scope in this line&nbsp; &nbsp;int z = 42;&nbsp; &nbsp;printf("%d", z);&nbsp; &nbsp;// z is in scope in this line}您还可以在for循环初始化程序中声明变量。该变量仅在循环内部存在。for(int i=0; i<10; i++){&nbsp; &nbsp; printf("%d", i);}ANSI C(C90)如果您以较早的ANSI C标准为目标,则仅限于在括号1之后立即声明变量。但这并不意味着您必须在函数顶部声明所有变量。在C语言中,您可以将大括号分隔的块放在语句可以到达的任何位置(不仅在诸如if或之后for),并且可以使用它引入新的变量作用域。以下是以前的C99示例的ANSI C版本:if( x < 10 ){&nbsp; &nbsp;printf("%d", 17);&nbsp; // z is not in scope in this line&nbsp; &nbsp;{&nbsp; &nbsp; &nbsp; &nbsp;int z = 42;&nbsp; &nbsp; &nbsp; &nbsp;printf("%d", z);&nbsp; &nbsp;// z is in scope in this line&nbsp; &nbsp;}}{int i; for(i=0; i<10; i++){&nbsp; &nbsp; printf("%d", i);}}1请注意,如果您使用的是gcc,则需要传递该--pedantic标志以使其实际上执行C90标准,并抱怨变量声明在错误的位置。如果只使用-std=c90它,它将使gcc接受C90的超集,该超集还允许更灵活的C99变量声明。

不负相思意

missingno介绍了ANSI C允许的内容,但是他没有说明为什么您的老师告诉您在函数顶部声明变量。在奇怪的地方声明变量会使您的代码更难阅读,并且可能导致错误。以下面的代码为例。#include <stdio.h>int main() {&nbsp; &nbsp; int i, j;&nbsp; &nbsp; i = 20;&nbsp; &nbsp; j = 30;&nbsp; &nbsp; printf("(1) i: %d, j: %d\n", i, j);&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; int i;&nbsp; &nbsp; &nbsp; &nbsp; i = 88;&nbsp; &nbsp; &nbsp; &nbsp; j = 99;&nbsp; &nbsp; &nbsp; &nbsp; printf("(2) i: %d, j: %d\n", i, j);&nbsp; &nbsp; }&nbsp; &nbsp; printf("(3) i: %d, j: %d\n", i, j);&nbsp; &nbsp; return 0;}如您所见,我已经声明了i两次。好吧,更准确地说,我已经声明了两个变量,两个变量的名称均为i。您可能会认为这会导致错误,但是不会,因为两个i变量的作用域不同。当您查看此函数的输出时,可以更清楚地看到这一点。(1) i: 20, j: 30(2) i: 88, j: 99(3) i: 20, j: 99首先,我们分别为i和分配20和30 j。然后,在花括号内,我们指定88和99。那么,为什么要j保留其值,但又i回到20?这是由于两个不同的i变量。在花括号的内部集合之间,i值20 的变量是隐藏的并且不可访问,但是由于我们尚未声明new j,因此我们仍在使用j外部作用域。当我们离开内部一组花括号时,i保持值88消失,我们再次可以访问i具有值20的。有时候,这种行为是件好事,而有时却不是。但是应该清楚的是,如果不加选择地使用C的此功能,则确实会使代码混乱且难以理解。

ITMISS

帖子显示以下代码://C99printf("%d", 17);int z=42;printf("%d", z);//ANSI Cprintf("%d", 17);{&nbsp; &nbsp; int z=42;&nbsp; &nbsp; printf("%d", z);}我认为这意味着它们是等效的。他们不是。如果将int z放置在此代码段的底部,则会对第一个z定义(而不对第二个z定义)引起重新定义错误。但是,以下几行://C99for(int i=0; i<10; i++){}确实有效。显示了此C99规则的微妙之处。就个人而言,我热情地避免使用此C99功能。如这些示例所示,它缩小变量范围的说法是错误的。根据新规则,在扫描完整个块之前,您不能安全地声明变量,而以前,您只需要了解每个块顶部的情况。
打开App,查看更多内容
随时随地看视频慕课网APP