• 【原创】浅谈指针(十二)关于static(上)


    0.前言

    这个系列基本上是一月一更到两月一更
    今天写一篇关于static的,内含大量干货,做好准备

    1.基础知识的回顾

    1.1.内存的种类

    一般来说,我们之前已经讲过的变量(或者说是内存)可以大体分为这样几种:

    • 全局变量
    • 局部变量,也称为自动变量
    • 使用malloc分配的区域
    • 常量、字符串字面量

    这里回顾一下,在C++中,使用const声明的常量是不可改变的,也就是在编译期就确定下来了。因此,即使使用指针更改也不会实际修改到它的值。对于全局变量,const出的值和字符串字面量(即使用""括起来的字符串),存在常量区,强制改变会使得程序异常退出。

    1.2.作用域和生命周期

    对于全局变量,它由始至终都是存在的,作用域是全部。
    局部变量的作用域和声明周期仅存在一个函数中,当函数返回,它就会从栈中销毁。
    使用malloc分配的内存区域,它的生命周期一直到调用free为止。
    对于字符串字面量和常量,它的作用域和声明周期与全局变量和局部变量类似。

    2.static的相关用法

    2.1.静态变量的定义

    我们把使用static修饰的变量和全局变量统称为静态变量。
    静态变量,顾名思义,就是可以贯穿整个程序运行的时间内的变量。

    2.2.static的地址

    我们来写一段代码,进行一个实验:

    #include<iostream>
    #include<windows.h>
    using namespace std;
    int a;//全局变量
    static int b;//全局static变量
    void f(void){
        static int c;//定义在函数内的static变量
        printf("c..%p\n",&c);
    }
    int main(){
        printf("a..%p\n",&a);
        printf("b..%p\n",&b);
        f();
        return 0;
    }
    
    

    (注:今天我换了一台电脑进行编辑,使用的是codeblocks来编辑,编译器我设置的是VC)
    输出的结果如下

    可以看到,static修饰的变量,与全局变量的地址是接近的,可以证明它是在全局存储区。

    2.3.函数体内的static

    还是以例子来说明,这样比较好理解。假如我们写一个将数字转为字符串的函数:

    #include<iostream>
    #include<windows.h>
    using namespace std;
    char *toint(int x){
        char s[1000];
        sprintf(s,"%d",x);
        return s;
    }
    int main(){
        char s[1000],t[1000];
        strcpy(s,toint(8));
        strcpy(t,toint(10));
        printf("%s\n%s\n",s,t);
        return 0;
    }
    
    

    使用sprintf函数,进行字符串间的转换。
    这段代码,乍一看似乎没有问题,而且在我的环境还可以正常运行:(部分环境会Segmentation Fault,就更加能说明这个问题)

    但是我们仔细看看,画面下方报出了一行警告:

    (看我选中的一条,上面一条似乎是环境没有配置到位,先不管了)

    这是因为,其中的s数组是局部变量,或者说是自动变量,保存在栈中,在函数返回之后,这个地址就不能再使用了,因为这个数组已经销毁了,s地址所在的地方是“无人区”,访问时就有可能访问到不该访问的数据,进而出错。

    对于这一类的问题,解决方法有使用malloc和new来分配内存,这样可以在free之前多次使用:

    char *toint(int x){
        char *s=new char [1000];
        sprintf(s,"%d",x);
        return s;
    }
    
    

    这一次没有报错。

    事实上,还可以使用静态变量来解决(不过静态变量主要的用途不在这里),这样这个内存就不会在返回的时候被释放。

    char *toint(int x){
        static char s[1000];
        sprintf(s,"%d",x);
        return s;
    }
    

    同样没有报错。

    3.static的更多特性与用途

    3.1.在函数退出后,static变量的值保持不变

    #include<iostream>
    #include<windows.h>
    using namespace std;
    void f(){
        static int Count;
        printf("%d\n",Count);
        Count++;
    }
    int main(){
        for(int i=0;i<10;i++){
            f();
        }
    }
    
    

    由于static的变量一直在同一个存储区,因此可以发现,退出函数时,static变量的值保持不变,输出结果为:

    3.2.多文件中的使用

    static的变量,只能在当前的文件内进行访问。

    //a.cpp
    static int x;
    
    int main(){
      x=100;
      cout<<x<<endl;
      f();
    }
    
    //b.cpp
    extern int x;
    void f(){
      cout<<x<<endl;
    }
    

    在b.cpp中,无法访问a.cpp中的x变量,因为x是使用static修饰的(即使使用了extern进行声明)

    包括函数也可以使用static进行修饰:

    static int f();
    

    关于更多的内容,敬请期待:
    【原创】浅谈指针(十三)关于static(下)

    (预计5月发布)

  • 相关阅读:
    docker容器
    拓展了个新业务枚举类型,资损了
    Java Web 33道面试题汇总
    Codeforces Round 895 div3 | JorbanS
    另辟蹊径者 PoseiSwap:背靠潜力叙事,构建 DeFi 理想国
    Python中ndarray对象和list(列表)的相互转换
    微服务网关 —— SpringCloud Gateway
    纯文本邮件发送:java
    树形结构 一篇文章梳理
    表内容的操作(增删查改)【MySQL】
  • 原文地址:https://www.cnblogs.com/jisuanjizhishizatan/p/16169376.html