zoukankan      html  css  js  c++  java
  • C06 变量和存储类型

    目录

    • 全局变量
    • 局部变量
    • 存储类型

      

    全局变量和局部变量

    变量的作用域

    • 作用域:某些事物起作用或有效的区域。
    • 变量的使用范围称为变量的作用域。
    • 变量的作用域决定了变量的可操作性和有效性。

    C语言变量的作用域

    局部变量

    • 在函数内部声明的变量
    • 形式参数是局部变量
    • 作用域仅限于定义的函数内,离开函数后无法再使用

    全局变量

    • 在函数的外部定义的变量
    • 不属于某一个函数,属于源程序
    • 作用域是由变量定义的位置至整个程序文件结束

    局部变量和全局变量的区别

     

    注:for循环参数列表中定义的变量作用域为函数范围。例如:

    局部变量和全局变量的应用

    示例1:局部变量与全局变量

    以上输出结果为?

    如何正确输出sum值?

      

    示例2:数组作为函数参数

     

     以上输出结果为?

    原因是?

    存储类型

    计算机内存管理

    程序在运行过程中,计算机将内存分为以下各个区域:

    bss段:bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。bss是英文Block Started by Symbol的简称。bss段属于静态内存分配。

    data段:数据段(data segment)通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

    code段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。   

    堆(heap):堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)。

    栈(stack):栈又称堆栈,是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的局部变量,static表示该变量存放在数据段中)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出(FIFO)特点,所以栈特别方便用来保存/恢复调用现场(即函数调用)。

    C语言变量存储类型

    内存结构

    Linux系统中,可执行文件加载进内存后以及相关进程在内存中的结构,如下图:

    代码区(程序区):存放CPU执行的机器指令,代码区是可共享,并且是只读的。

    数据区:存放已初始化的全局变量、静态变量(全局和局部)、常量数据。

    BSS区:存放的是未初始化的全局变量和静态变量。

    栈区:由编译器自动分配释放,存放函数的参数值、返回值和局部变量,在程序运行过程中实时分配和释放,栈区由操作系统自动管理,无须程序员手动管理。

    堆区:堆是由malloc()函数分配的内存块,使用free()函数来释放内存,堆的申请释放工作由程序员控制,容易产生内存泄漏。

    存储类型

    c语言中的存储类型有auto, extern, register, static 这四种,存储类型说明了该变量要在进程的哪一个段中分配内存空间,可以为变量分配内存存储空间的有数据区、BSS区、栈区、堆区。下面来一一举例看一下这几个存储类型:

    1.      auto存储类型

    auto只能用来标识局部变量的存储类型,对于局部变量,auto是默认的存储类型,不需要显示的指定。因此,auto标识的变量存储在栈区(或者堆区)中。

    示例:  

    #include <stdio.h> 
    
    int main() { 
        auto int i=1; //显式指定变量的存储类型 
        int j=2;  //默认及auto存储类型
        printf("i=%d	j=%d
    ",i,j); 
        return 0; 
    } 
    

    2.      extern存储类型

    extern用来声明在当前文件中引用在当前项目中的其它文件中定义的全局变量。如果全局变量未被初始化,那么将被存在BSS区中,且在编译时,自动将其值赋值为0,如果已经被初始化,那么就被存在数据区中。全局变量,不管是否被初始化,其生命周期都是整个程序运行过程中,为了节省内存空间,在当前文件中使用extern来声明其它文件中定义的全局变量时,就不会再为其分配内存空间。

    extern也可以在文件中声明所引用外部文件定义的函数。格式:ertern  返回值类型  函数名(形参列表)

    示例:

    /**file1.cpp*/
    #include <stdio.h>    
    
    int i=5; //定义全局变量,并初始化 
    
    void test() { 
        printf("in subfunction i=%d
    ",i); 
    } 
    
     
    
    /**file2.cpp*/
    
    #include <stdio.h>   
    
    extern i; //声明引用全局变量i
    extern void test();//申明引用外部文件定义的函数test   
    
    int main() { 
        printf("in main i=%d
    ",i); 
        test(); 
        return 0; 
    } 
    

      

    结果:    

    3. register存储类型

    声明为register的变量在由内存调入到CPU寄存器后,则常驻在CPU的寄存器中,因此访问register变量将在很大程度上提高效率,因为省去了变量由内存调入到寄存器过程中的好几个指令周期。

    只有局部变量才能声明为register存储类型。

    示例:

    #include <stdio.h> 
    
    int main() { 
        register int i,sum=0; 
        for(i=0;i<10;i++) 
             sum=sum+1; 
        printf("%d
    ",sum); 
        return 0; 
    } 
    

       

    4. static存储类型

    被声明为静态类型的变量,无论是全局的还是局部的,都存储在数据区中,其生命周期为整个程序,如果是静态局部变量,其作用域为一对{}内,如果是静态全局变量,其作用域为当前文件。静态变量如果没有被初始化,则自动初始化为0。静态变量只能够初始化一次。

    示例:

    #include <stdio.h> 
    
    int sum(int a) { 
        auto int c=0; 
        static int b=5; 
        c++; 
        b++; 
        printf("a=%d,	c=%d,	b=%d	",a,c,b); 
        return (a+b+c); 
    } 
    
    int main() { 
        int i; 
        int a=2; 
        for(i=0;i<5;i++) 
        printf("sum(a)=%d
    ",sum(a)); 
        return 0; 
    } 
    

    输出:

     

    6. 字符串常量

    字符串常量存储在数据区中,其生存期为整个程序运行时间,但作用域为当前文件。

    示例:

    #include <stdio.h>  
    
    char *a="hello";  
    
    void test() { 
        char *c="hello"; 
        if(a==c) 
            printf("yes,a==c
    "); 
        else 
            printf("no,a!=c
    "); 
    } 
    
    int main() { 
        char *b="hello"; 
        char *d="hello2"; 
        test();
        if(a==b) 
            printf("yes,a==b
    "); 
        else 
            printf("no,a!=b
    ");      
        if(a==d) 
            printf("yes,a==d
    "); 
        else 
            printf("no,a!=d
    "); 
        return 0; 
    } 
    

       

    输出:

     

  • 相关阅读:
    [Javascript] Data ownership, avoid accidently mutation
    [Next.js] Consume Next.js API routes with the SWR library on the client-side
    [ARIA] Read error message for the focused form field by using aria-describedby
    [ARIA] Group different DOM element in screen reader by using aria-labelledby
    [React] Handle HTTP Errors with React
    [Angular] Modify :before / :after value from Javascirpt
    [Javascript] Finding Sibling Elements
    [Javascript] Finding Parent Elements
    MAC之find与grep
    Android只播放gif动画
  • 原文地址:https://www.cnblogs.com/rask/p/10171664.html
Copyright © 2011-2022 走看看