为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C
有只小跳蛙 2019-10-26 12:51:58
我(可能是从老师那里)听说,应该在程序/函数之上声明所有变量,并且在声明中声明新变量可能会引起问题。但是后来我读了《 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);}根据程序/机器,这会引起麻烦吗?
查看完整描述

3 回答

?
智慧大石

TA贡献1946条经验 获得超3个赞

我也经常听到把变量放在函数顶部是最好的处理方法,但是我非常不同意。我更喜欢将变量限制在尽可能小的范围内,这样变量被滥用的机会就更少了,因此,在程序的每一行中填满我的思维空间的东西也就更少了。


尽管所有版本的C都允许词法块作用域,但是您可以在其中声明变量取决于目标C语言版本:


从C99开始或C ++

诸如gcc和clang之类的现代C编译器支持C99和C11标准,这些标准允许您在可能进行语句的任何地方声明变量。变量的范围从声明的点开始到块的末尾(下一个大括号)。


if( x < 10 ){

   printf("%d", 17);  // z is not in scope in this line

   int z = 42;

   printf("%d", z);   // z is in scope in this line

}

您还可以在for循环初始化程序中声明变量。该变量仅在循环内部存在。


for(int i=0; i<10; i++){

    printf("%d", i);

}

ANSI C(C90)

如果您以较早的ANSI C标准为目标,则仅限于在括号1之后立即声明变量。


但这并不意味着您必须在函数顶部声明所有变量。在C语言中,您可以将大括号分隔的块放在语句可以到达的任何位置(不仅在诸如if或之后for),并且可以使用它引入新的变量作用域。以下是以前的C99示例的ANSI C版本:


if( x < 10 ){

   printf("%d", 17);  // z is not in scope in this line


   {

       int z = 42;

       printf("%d", z);   // z is in scope in this line

   }

}


{int i; for(i=0; i<10; i++){

    printf("%d", i);

}}

1请注意,如果您使用的是gcc,则需要传递该--pedantic标志以使其实际上执行C90标准,并抱怨变量声明在错误的位置。如果只使用-std=c90它,它将使gcc接受C90的超集,该超集还允许更灵活的C99变量声明。


查看完整回答
反对 回复 2019-10-26
?
不负相思意

TA贡献1777条经验 获得超10个赞

missingno介绍了ANSI C允许的内容,但是他没有说明为什么您的老师告诉您在函数顶部声明变量。在奇怪的地方声明变量会使您的代码更难阅读,并且可能导致错误。


以下面的代码为例。


#include <stdio.h>


int main() {

    int i, j;

    i = 20;

    j = 30;


    printf("(1) i: %d, j: %d\n", i, j);


    {

        int i;

        i = 88;

        j = 99;

        printf("(2) i: %d, j: %d\n", i, j);

    }


    printf("(3) i: %d, j: %d\n", i, j);


    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的此功能,则确实会使代码混乱且难以理解。


查看完整回答
反对 回复 2019-10-26
?
ITMISS

TA贡献1871条经验 获得超8个赞

帖子显示以下代码:


//C99

printf("%d", 17);

int z=42;

printf("%d", z);


//ANSI C

printf("%d", 17);

{

    int z=42;

    printf("%d", z);

}

我认为这意味着它们是等效的。他们不是。如果将int z放置在此代码段的底部,则会对第一个z定义(而不对第二个z定义)引起重新定义错误。


但是,以下几行:


//C99

for(int i=0; i<10; i++){}

确实有效。显示了此C99规则的微妙之处。


就个人而言,我热情地避免使用此C99功能。


如这些示例所示,它缩小变量范围的说法是错误的。根据新规则,在扫描完整个块之前,您不能安全地声明变量,而以前,您只需要了解每个块顶部的情况。


查看完整回答
反对 回复 2019-10-26
  • 3 回答
  • 0 关注
  • 526 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信