变量存储相关(待完善)

内容概要

  一、局部变量、全局变量与作用域

  二、生存周期和存储类型

  三、衔接属性

 

1、局部变量、全局变量与作用域

  作用域规定了元素作用的范围,这样让程序变得更有序

  c语言作用域有4中,分别为

    代码块作用域

    文件作用域

    原型作用域

    函数作用域

 

  -代码块作用域

    与python不同,python中代码块是通过缩进区分的;而c语言是通过大括号进行区分

    c语言中在不同代码块定义的变量是互不影响的

#include <stdio.h>

int main(void){
    int i = 10;
    {
        int i = 20;
        
        {
            int i = 30;
            printf("i1:%d\n",i);
        }
        
        {
            int i = 40;
            printf("i2:%d\n",i);
        }
        
        printf("i3:%d\n",i);
        
    }
    printf("i4:%d\n",i);
    
    return 0;
}

    这种区分也体现在for循环中,注意()定义的i也属于下一个代码块

 

#include <stdio.h>

int main(void){
    
    int i = 100;
    printf("start : %d\n",i);
    
    for(int i = 10; i<20; i++){
        printf("%d\n",i);
    }
    
    printf("end : %d\n",i);
    
    return 0;
}

    -代码块变量查询顺序

      与python中变量查询顺序B(内置),G(全局),E(外部),L(局部)类似,  **这里忘了**

      c语言中变量查询也是按照从内往外,不走同级的规律查找的

#include <stdio.h>

int main(void){
    //代码块1
    int i = 10;
    {
        //代码块2
        int i = 20;
        
        {
            //代码块3
            int i = 30;
        }
        
        {
            //代码块4,与代码块3同级
            printf("i2:%d\n",i);  //打印结果为20
        }
        
    }
    
    return 0;
}

 

    -局部变量(局部变量就可以只是指代码块作用域下的变量)

      可以将局部变量理解为定义在函数体的变量,这样的变量其它的函数无法访问

#include <stdio.h>

int number(void);

int number(void){
    int i = 10;
    return i;
}

int main(void){
    int i;
    number();
    printf("%d\n",i);
    
    return 0;
}

 

    -全局变量,如果想要变量能被每一个函数访问,那么就使用全局变量,全局变量在函数外定义

#include <stdio.h>

int Global_a; //默认初始化为0;全局变量命名最好为首字母大写

void a(void);
void b(void);
void c(void);

void a(void){
    Global_a++;
}

void b(void){
    Global_a++;
}

void c(void){
    Global_a++;
}

int main(void){

    a();
    b();
    c();
    c();
    
    printf("%d\n",Global_a);
    
    return 0;
}

    覆盖全局变量

#include <stdio.h>

int Global_a; //

void a(void);
void b(void);
void c(void);

void a(void){
    Global_a++;
}

void b(void){
    Global_a++;
}

void c(void){
    Global_a++;
}

int main(void){

    a();
    b();
    c();
    c();
    
    int Global_a = 10; //按照循序查找,优先查找语句所在代码块,如果存在变量,则忽略全局变量
    printf("%d\n",Global_a);
    
    return 0;
}

 

    -文件作用域

      全局变量所在的作用域就是全局作用域,它能被所有文件中其它元素访问

    在python中内置命名空间、全局命名空间、局部命名空间其实并非是包含嵌套关系;

    而是在内存中有不同的划分,只是彼此又有关联;

    但为了方便理解,就理解为包含关系了。

    c语言不知道是不是这样 **有空去详细了解一下**

 

    -原型作用域

      原型作用域使用的少,这个作用域适用于函数原型中的参数名

 

    -函数作用域

      函数作用域只适用于goto语句的标签,作用是将goto标签限制在同一个函数中,以防出现重名标签的情况

 

2、生存周期和存储类型

  c语言只有两种生存周期

    -静态存储期

      静态存储期指的是从程序执行到程序结束位置,都占用着内存空间

      一般具有文件作用域的元素都具有静态存储期

 

    -自动存储期

      自动存储器指的是在所在代码块结束之后,自动释放内存空间

      一般具有代码块作用域的元素具有自动存储器

 

  存储类型

    对于存储类型,我是这样子理解的——内存中数据不是随机存放的,而是经过区域划分的,定义auto类型,就是告诉编译器,我要将这个变量存放到哪个内存区域中

    不同的内存区域对应着不同的生存期,用户权限,作用域等等 **这部分是要核实的**

 

    static和extern在代码块作用域和文件作用域下有不同功能

 

    -auto存储类型

       定义在函数内的变量默认的存储类型就是auto,auto存储类型的数据具有自动存储期、代码块作用域、None链接属性

int main(void){
    int i = 10;
    // 等价于auto int i =10;
    return 0;
}

 

    -register存储类型

      使用register修饰的变量称为寄存器变量,寄存器变量有可能存储于寄存器中,寄存器可以理解为存储空间非常小的内存,寄存器是用于存放那些频繁被cpu使用或者是即将被cpu使用的值,

      cpu与寄存器之间交互数据几乎没有延迟。

      但由于寄存器空间非常小,一般只有一个值,也有可能因为空间不够,或者编译器觉得有更好的变量应该被存放于寄存器。你所定义的寄存器变量实际不会存储与寄存器中。

 

      与auto存储类型数据一样,register存储类型具有自动存储期、代码块作用域、None链接属性

      不同的是,你无法通过&取值运算符来操作register变量   **实操在dev c++下可以取址,还能改值**

#include <stdio.h>

int main(void){
    
    register int i = 20;
    int *pi = &i;
    
    *pi = 10;
    
    printf("i: %d\n",*pi);
    
    return 0;
}

    -static存储类型

      使用static修饰一个代码块作用域下变量,将它改变为静态局部变量。拥有代码块作用域,静态存储类型,None链接属性

#include <stdio.h>

int add(void);

int add(void){
    
    static int count = 0;
    
    printf("%d\n",count);
    
    count++;
}

int main(void){
    
    for(int i=0; i<10; i++){
        add();  //调用函数之后变量count并没有被回收
    }
    
    return 0;
}

      对比

#include <stdio.h>

int add(void);

int add(void){
    
    int count = 0;
    
    printf("%d\n",count);
    
    count++;
}

int main(void){
    
    for(int i=0; i<10; i++){
        add();
    }
    
    return 0;
}

      尝试访问这个静态局部变量

#include <stdio.h>

void add(void);

void add(void){
    
    static int count = 0;
    
    printf("%d\n",count);
    
    count++;
}

int main(void){
    
    for(int i=0; i<10; i++){
        add();
    }
    
    printf("%d\n",count); //[Error] 'count' was not declared in this scope变量未定义
    return 0;
}

    -extern存储类型

      extern可以修饰变量的声明,使得变量可以在其它文件作用域下定义

 

        同时编译运行两个文件

        a.c

int i = 10;

        b.c

#include <stdio.h>

int main(void){
    extern int i;  //声明了变量i,将它的链接属性设置为external,这样它就可以访问其它文件下的文件作用域的同名变量了
    
    printf("i: %d\n",i);
    
    return 0;
}

        将b.c稍加修改之后  **待实操**

#include <stdio.h>

int main(void){
    extern int i;
    i = 10;
    printf("i: %d\n",i);
    
    return 0;
}

        使用extern的函数依旧无法使用其它代码块下的变量定义

#include <stdio.h>

int main(void){
    {
        int i = 10;
    }
    {
        extern int i;
        printf("i:%d\n",i);
    }
    return 0;
}

    -typeof存储类型

      **待补充**

 

3、链接属性

  链接属性说明了

    链接属性,分为3种

      -external链接属性

        在文件作用域下定义的变量或者函数默认的链接属性就是external属性

#include <stdio.h>

int i = 10;
// 等价于extern int i = 10;

        拥有external链接属性的变量或函数可以被来自不同文件作用域访问,当然本文件也可以

 

      -internal链接属性

        拥有internal链接属性的变量只能被本文件其它元素访问,拒绝来自其它文件作用域的访问

          a.c

static int i = 20;  //在文件作用域下使用static将变量链接属性改为internal

          b.c

#include <stdio.h>

int main(void){
    extern int i;
    
    printf("int main i: %d",i);  //将不能访问到a.c文件下的i,这样的目的是为了保护变量
    
    return 0;
}

      -none空链接属性

        拒绝所有除非下层代码块作用下元素的访问

 

***待补充***

posted @ 2021-03-15 19:21  口乞厂几  阅读(79)  评论(0)    收藏  举报