【原创】浅谈指针(十二)关于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月发布)

posted @ 2022-04-24 18:06  计算机知识杂谈  阅读(333)  评论(0编辑  收藏  举报