for循环的一点杂乱分析(不完善)

一、问题引出

代码片段一,直接定义两个变量a,编译器报错

void main()
{
    int a;
    int a;
}

代码片段二,用for循环也是定义了两个变量a,编译器不报错

void main()
{
    for(int i=0;i<2;i++)
    {
        int a;
    }
}

不知道大家有没有对for循环有这样的理解:for就是自动帮我们书写了花括号里的代码内容。这样想就会无法理解代码片段2为什么不报错。

二、探讨问题

代码片段1中的错误很好解释,因为在同一作用域出现了变量重名,这会导致代码运行时无法准确的找到变量(地址),编译器就不会同意我们运行这样错误的代码。

我又提出这样的问题:

既然编译器在代码片段1中找出了错误,是因为我们声明了同样的变量名,那么代码片段2中编译器没有报错,是不是因为两个变量a不在同一作用域下呢?不在同一个作用域下变量名一样是不会报错的。

回答我上面的问题,不是o( ̄ヘ ̄o#)

在程序设计语言里面,循环是三种语言流程之一(顺序,分支,循环),这其中循环又是编程这件事中最具魅力的,它发挥了人在思维和计算机在计算方面的双方优势,体现了程序员的技巧和智慧,也体现了代码的简洁,优雅和优美。循环中最常用的应该是 for 循环,其他几种例如while,do while又基本上可以等效写成 for 循环。同时 for 循环又可以被等效改写为递归函数。本段摘自:

[IDA] 分析for循环的汇编代码 - hoodlum1980 - 博客园 (cnblogs.com)https://www.cnblogs.com/hoodlum1980/archive/2010/07/30/1789092.html

那么问题转变为理解函数的生命周期!

先提前解释一下,不想看细致的分析就直接看下面的简单结论就好了。

较为准确的结论:

在for(递归函数)中,这个整数类型变量a寿命只有一次for循环(一次函数调用或函数递归一次),即每次循环开始分配a的内存,本一次循环结束a的内存就被回收了,下次循环开始再重新分配一个内存,结束是回收内存,以此类推。

不准确的结论:

在for中这个int a寿命只有一次循环,即每次循环结束a就被回收了,下次循环再分配一个新的a

三、细致的理解

待完善

换一个难一点的来看

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>for循环(难死我了)</title>
</head>
<body>
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <button>4</button>

    <script>
        p = document.querySelectorAll('button');//let i=0  //情况1与情况3一样
        for(var i=0;i<4;i++){   // 换成let试试情况2     //var i=0是情况3
            p[i].onclick = function(){
                console.log(i);
            }
        }
    </script>

</body>
</html>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>for循环(难死我了)</title>
</head>
<body>
    <button>1</button>
    <button>2</button>
    <button>3</button>
    <button>4</button>

    <script>
        btn = document.querySelectorAll('button');//let i=0  //情况1与情况3一样
        /*---------------------------------demo1---------------------------------------*/

        // for(var i=0;i<4;i++){   // 换成let试试,情况2     //var i=0是情况3
        //     btn[i].onclick = function(){
        //         console.log(i);     
        //         // [native code] 意思已经很明确了:是 native 的代码实现的 built-in 函数,而不是 JavaScript 代码
        //         // 已被编译为特定于处理器的机器码的代码。
        //     }
        // }
        
        /*----------------------------------demo2--------------------------------------*/
        let i = 0;
        for(let p=0;p<1;p++){
            let i = 3;
            btn[i].onclick = function(){
                let i = 99;
                console.log(i);
            }
        }
    </script>

</body>
</html>

本案例中的个人解释:(勿喷)

借助作用域链的变量查找,变量生命周期,变量内存空间地址

情况① 直接使用变量值(代码中的参数是具体值,被编译为机器码,呈现[native code])

情况② 拿变量地址(代码中的参数是地址,被编译为机器码,也呈现[native code])

为什么采取两种方式来获取变量?

局部域(动态存储区)中的变量必然会在程序结束前被释放,而全局域(静态存储区)中的变量是在程序结束时才被释放。

试想一下,如果全采用情况①的方法,那么会出现,只拿到程序运行过程中间时刻变量的值,而设计全局变量(静态存储区变量)一般是为了拿到最后的数据。

如果采用情况②的方法,由于局部域变量(动态存储区变量)的生命周期,在执行完复合语句(花括号包括的语句)前后,局部变量被申请、赋值和释放,释放后该地址也就不再是属于那个局部变量的了,值很有可能变了。

四、补充 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值