【C++】switch case内部的变量定义问题

📣🥳🥳🥳📣

✨Hello! 如果这篇【文章】对你有帮助😄,希望可以给博主点个赞👍鼓励一下😘

📣🥳🥳🥳📣



🤔 问题背景

关于switch语句,我们知道其执行流程有可能会跨过某些case标签。如果程序跳转到了某个特定的case,则switch结构中该case标签之前的部分会被忽略掉。但是,如果说被略过的代码中包含有某些变量的定义,那会发生什么?

《C++ Primer 5th》163页给出的原文答案是👇

”如果在某处一个带有初值的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳到后一处的行为是非法行为“。

如果翻回去看P163的例子,会发现例子也有一点点"难以理解"。但其实只需要搞清楚【变量定义】、【变量初始化】以及【变量作用域】这几个概念就可以理顺头绪了。

🌟 问题思考

下面用一个个例子来说明

1️⃣

int main() {
    switch (2) {
        case 1:
            int x;
            break;
        case 2:
            x = 2;  
            cout << "x=" << x << endl;
            break;
    }
    return 0;
}

对于上面这个例子,程序正常编译,且能正常运行并打印出x=2
【原因在于】:在处理switch case语句中,C++11标准的编译器会在执行case跳转前为变量分配空间。也就是说,编译阶段时,变量x就已经被成功定义并且获得了对应的内存空间,因此后续令x=2的语句也就没有什么问题。

通过这个例子我们得知,【变量定义】在编译阶段就已完成,case 1只是对变量x进行了【变量定义】, 但没有执行【变量初始化】操作

2️⃣

int main() {
    switch (2) {
        case 1:
            int x = 1;  //note:crosses initialization of 'int x'
            break;
        case 2:
            x = 2;  //即使把这句删掉也一样
            cout << "x=" << x << endl;
            break;
    }
    return 0;
}

由于switch大括号内所有case同属一个【作用域】,C++11标准下规定switch语句不能出现这样的写法,因为【变量初始化】语句是一个确确实实在程序运行时才会被调用的语句,是可以被case跳转屏蔽掉的语句。
因此,如果允许了上面这种写法,执行case 2x=2便会出现【变量x尚未被定义】的报错,而编译器提前把这一错误给扼杀在这里。

int main() {
    switch (2) {
        case 1: {  //case 1单独的局部作用域
            int x = 1;  //可以认为case 1下的语句藏在了一个独立的作用域,'与外面的世界无关'
            break;
            }
        case 2:
            x = 2;  //error:'x' was not declared in this scope
            cout << "x=" << x << endl;
            break;
    }
    return 0;
}

【因此根本原因就是】:int x是【变量定义】操作,int x = 1是【变量初始化】操作(当然初始化时刻之前变量也被定义,但对一语句来说如果出现初始化操作则优先定位为初始化语句)。在C++11的标准下,【变量定义】操作在编译阶段就会执行分配内存,而涉及【变量初始化】操作的语句则必须等到程序运行时才会调用执行。

这时候再来看下下面这个例子👇

int main() {
    switch (2) {
        case 1:   
            int x = 1;  //note:crosses initialization of 'int x'
            break;
        case 2:
            int x = 2;  //error:redeclaration of 'int x'
            cout << "x=" << x << endl;
            break;
    }
    return 0;
}

结合此前的例子可以很好理解。修改的方法同样是只需要加一对大括号{}👇

int main() {
    switch (2) {
        case 1: {
            int x = 1;  
            break;
        }
        case 2:  //此时case 1中的x便和case 2中的x没有关联
            int x = 2;  
            cout << "x=" << x << endl;  //正常打印出x=2
            break;
    }
    return 0;
} 

但若将{}放在case 2,那肯定还会提示crosses initialization of 'int x'👇

int main() {
    switch (2) {
        case 1: 
            int x = 1;  
            break;
        case 2: {
            int x = 2;  //note:crosses initialization of 'int x'
            cout << "x=" << x << endl;  
            break;
        }
    }
    return 0;
} 

【总结】:因此对于switch语句的使用,如果确实有需要在内部定义变量的场景,最好的方法就是在编程的时候,将整个switch语句中都用到的变量在switch外定义好,到了switch内部,则可以针对某个case需要单独使用某些变量的情况,用{}作用域符号来明确此case语句的作用域

3️⃣
最后,就可以来看看《C++ Primer 5th》P160中的这些例子👇
在这里插入图片描述
结合1️⃣2️⃣显然就可以很好理解了。但需额外解释一下string file_name,虽然该变量看起来没被初始化,但正如文中所说,它被【隐式初始化】了,这是因为string这个类类型中定义了【隐式初始化】的方法。


✨如有问题欢迎在底下评论留言或私信!

如果这篇【文章】对你有帮助😄,希望可以给博主【点个赞👍】鼓励一下😘

❤️Thanks for your encouragement❤️

  • 20
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

John Chen1223

点赞是美意!打赏是鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值