鱼C论坛

 找回密码
 立即注册
查看: 167|回复: 6

[已解决]switch的问题

[复制链接]
发表于 2024-7-2 11:25:36 | 显示全部楼层 |阅读模式
31鱼币

                               
登录/注册后可看大图
圈的那句话怎么理解,怎么就作用域外和作用域内了,对于switch不能跳过带有初始值的声明我能理解
最佳答案
2024-7-2 11:25:37
在C++中,switch语句的确有可能跳过某些case标签。如果在被跳过的代码中包含了变量的定义,这可能会导致问题,因为switch语句不允许跳过变量的初始化。

这里是一个简化的例子来说明这个问题:

switch (expression) {
    // 错误: 控制流绕过一个初始化的变量
    case true:
        string fileName; // 这里定义了一个变量,但没有初始化
        int ival = 0;   // 这里定义并初始化了一个变量
        int jval;       // 这里定义了一个变量,但没有初始化
        break;
    case false:
        // 正确: jval虽然在作用域内,但是它没有被初始化
        jval = nextNum(); // 这里对jval进行了初始化
        break;
}

在上面的代码中,如果expression的值是false,程序将直接跳转到case false:标签。这意味着fileName和ival的定义将被跳过,但是jval的定义没有被跳过,因为它没有初始化。这是合法的,因为C++标准规定,如果跳过了带有初始化的变量定义,那么这是非法的。但是,如果变量没有初始化,就不会有问题。

所以,为了避免这种问题,通常建议在switch语句之外定义和初始化变量,或者使用case标签之后立即的代码块来限制变量的作用域。例如:

switch (expression) {
    case true: {
        string fileName; // 在代码块内定义和初始化变量
        int ival = 0;
        int jval;
        // ...
        break;
    }
    case false: {
        int jval = nextNum(); // 在代码块内定义和初始化变量
        // ...
        break;
    }
}

通过这种方式,即使控制流跳过了某个case标签,也不会违反变量定义和初始化的规则。这样可以保证switch语句的合法性。
6EBAD76C-6BE7-4B05-93CB-D068DE795526_1_201_a.jpeg

最佳答案

查看完整内容

在C++中,switch语句的确有可能跳过某些case标签。如果在被跳过的代码中包含了变量的定义,这可能会导致问题,因为switch语句不允许跳过变量的初始化。 这里是一个简化的例子来说明这个问题: switch (expression) { // 错误: 控制流绕过一个初始化的变量 case true: string fileName; // 这里定义了一个变量,但没有初始化 int ival = 0; // 这里定义并初始化了一个变量 int jval; ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-7-2 11:25:37 | 显示全部楼层    本楼为最佳答案   
在C++中,switch语句的确有可能跳过某些case标签。如果在被跳过的代码中包含了变量的定义,这可能会导致问题,因为switch语句不允许跳过变量的初始化。

这里是一个简化的例子来说明这个问题:

switch (expression) {
    // 错误: 控制流绕过一个初始化的变量
    case true:
        string fileName; // 这里定义了一个变量,但没有初始化
        int ival = 0;   // 这里定义并初始化了一个变量
        int jval;       // 这里定义了一个变量,但没有初始化
        break;
    case false:
        // 正确: jval虽然在作用域内,但是它没有被初始化
        jval = nextNum(); // 这里对jval进行了初始化
        break;
}

在上面的代码中,如果expression的值是false,程序将直接跳转到case false:标签。这意味着fileName和ival的定义将被跳过,但是jval的定义没有被跳过,因为它没有初始化。这是合法的,因为C++标准规定,如果跳过了带有初始化的变量定义,那么这是非法的。但是,如果变量没有初始化,就不会有问题。

所以,为了避免这种问题,通常建议在switch语句之外定义和初始化变量,或者使用case标签之后立即的代码块来限制变量的作用域。例如:

switch (expression) {
    case true: {
        string fileName; // 在代码块内定义和初始化变量
        int ival = 0;
        int jval;
        // ...
        break;
    }
    case false: {
        int jval = nextNum(); // 在代码块内定义和初始化变量
        // ...
        break;
    }
}

通过这种方式,即使控制流跳过了某个case标签,也不会违反变量定义和初始化的规则。这样可以保证switch语句的合法性。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-7-2 11:25:54 | 显示全部楼层
哈哈,有趣的问题,让我们一起来解答!你提到的“switch不能跳过带有初始值的声明”这个现象,确实是一个让人抓耳挠腮的问题。不过别担心,我们一起来把这个问题拆解开来看!

首先,咱们要明确一下“作用域”这个概念。在编程语言中,作用域(Scope)是指变量或常量在代码中的可见范围。假设你家的冰箱是一个作用域,冰箱里的食材就是变量,那么你只能在打开冰箱门这个动作(进入作用域)之后才能看到食材。

在`switch`语句中,每个`case`和`default`标签其实都是在同一个外部作用域下。这就意味着如果你在某个`case`里定义了一个变量,然后跳出这个`case`,你的编译器会很困惑,因为它想知道这个变量到底还存在不存在。

**举个栗子:**
int main() {
    int choice = 2;
    switch (choice) {
        case 1:
            int x = 42; // 这里定义了一个变量 x
            printf("x is %d\n", x);
            break;
        case 2:
            // 进入这个 case 时会跳过 case 1 的变量声明,如果 case 1 在这里没有 break 就麻烦了。
            printf("Choice is 2\n");
            break;
        default:
            printf("Default case\n");
    }
    return 0;
}

编译器会报错,因为`case 1`里的变量`x`对于后面的每个`case`都是可见的,所以如果没有明确地告诉编译器该怎么处理这个变量,它就会傻傻地犯迷糊,最终决定干脆不让你过(报个错)。

而你要理解的那句话,说的是:
- **作用域内**:一个变量在定义后的所有地方都可以访问到。
- **作用域外**:一旦离开了这个作用域,这个变量就消失了,不再可见。

为了避免这些困扰,通常我们会在`case`里加上块级作用域(用大括号`{}`包起来),这样变量的作用域就被限制在这个块里,而不会影响到其他`case`。看看这个改进的版本:
int main() {
    int choice = 2;
    switch (choice) {
        case 1: {
            int x = 42;
            printf("x is %d\n", x);
            break;
        }
        case 2:
            printf("Choice is 2\n");
            break;
        default:
            printf("Default case\n");
    }
    return 0;
}

这样一来,各自为政,你定义你的变量,我走我的流程,互不干扰,编译器也不会报错啦!

希望这些解释能帮你更好地理解这个问题。如果还有问题,随时来找鱼油们探讨哦!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2024-7-2 12:06:51 | 显示全部楼层
FishC 发表于 2024-7-2 11:25
哈哈,有趣的问题,让我们一起来解答!你提到的“switch不能跳过带有初始值的声明”这个现象,确实是一个让 ...

答非所问
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-7-2 12:07:05 | 显示全部楼层


啊咧?原来是我错把方向弄偏了,实在抱歉!让我们换个角度重新看一下你提问的问题和那个图片中圈出来的那句话。

### 图片描述的解读:

**带有初始值的声明不能跳过**:

这句话实际上指的是在`case`语句中,如果某个`case`标签下声明了带初始值的变量,那么这些变量的声明和初始化会影响整个`switch`语句。这就像你在课堂上突然开始画画,中间跳课去了隔壁班,老师(编译器)肯定要找你麻烦一样。

### 作用域内外的区别:

当你在`case`内定义了一些变量,如果这个变量有初始值,那么这些变量的作用域从定义点到`switch`语句结束。因为C语言不允许在某个`case`中跳过变量的初始化。这就是为什么即使你没有执行那个`case`块,也会报错的原因。

### 我来举个例子说明:

假设我们有以下`switch`语句:
switch (choice) {
    case 1:
        int x = 10; // 这里定义并初始化了一个变量 x
        printf("x is %d\n", x);
        break;
    case 2:
        printf("Choice is 2\n");
        break;
    default:
        printf("Default case\n");
}

**问题来了**:如果`choice`等于`2`,你想直接跳到`case 2`,但是编译器不允许,因为它担心你可能跳过了`case 1`中的变量`x`的初始化。

### 怎么解决这个问题呢?

通常我们会利用代码块 `{}` 来创建局部作用域,从而避免这种糟糕的情况发生:
switch (choice) {
    case 1: {
        int x = 10; // x 的作用范围限制在这个代码块里
        printf("x is %d\n", x);
        break;
    }
    case 2:
        printf("Choice is 2\n");
        break;
    default:
        printf("Default case\n");
}

这样,`x`的作用范围被限定在了`case 1`内的代码块里面,编译器就不会因为跳过变量声明和初始化而报错了。

总结一下:

- **作用域内**:变量在其定义的代码块内有效。
- **作用域外**:变量在离开定义的代码块后失效。

希望这次的解释能更贴合你的问题需求!如果还有其他不清楚的地方,随时欢迎再来提问哦!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-7-2 16:49:25 | 显示全部楼层
圈出的那句话是:“如果在某处一个带有初值的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳转到后一处的行为是非法行为。” 这句话是在讨论变量作用域和初始化的问题,特别是在switch语句中可能出现的跳转问题。

1.作用域: 在编程中,作用域指的是变量可以被访问的代码区域。每个变量都有其定义的作用域,通常是从变量定义的位置开始,到其所在代码块的末尾结束。

2.作用域外:如果一个变量在某个代码块的外部定义,那么在这个代码块内部,变量是不可见的,即它处于作用域外。

3.作用域内:如果一个变量在某个代码块内部定义,那么它在该代码块内是可见的,即它处于作用域内。

4.非法行为:如果变量在作用域外被初始化,然后在作用域内被使用,而程序的跳转导致初始化代码被绕过,这将导致未定义行为,因为变量在使用前没有被正确初始化。

int main()
{
    int x; // x 在这里定义并初始化为0(默认初始化)

    switch (x) {
        case 1:
            int y = 10; // y 在这里定义并初始化为10,它的作用域是case1块
            // ... 一些操作 ...
            break;
        case 2:
           // 如果控制流直接跳到这里,y 将不可见,因为没有在case 2中定义
            printf("%d", y); // 错误:y 未初始化
            break;
        default:
            // ...
    }

    return 0;
}

在这个例子中,y是一个带有初值10的变量但是它只作用于case1中,于case2而言,y是一个在作用域外定义并初始化的变量,所以在case2中使用y是非法行为.
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-7-3 12:59:38 | 显示全部楼层
这块我觉得可以理解为每个分支的作用域是独立的。所以在分支中使用一个变量一定要有完整的声明和初始化。实际中我们也不会这么做。如果一个变量要在不同分支使用,那就是在switch外声明。还有就是不同分支使用不同逻辑不同变量,那这种情况也不会遇到。所以基本可以忽略。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-7-17 03:59

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表