聊一下C编程中变量的初始化

2023-02-28 13:24:17 浏览数 (2)

前言

经常有小伙伴在编写程序时因为变量未进行初始化而导致bug的出现。在平时编写程序时你是否在定义变量时有初始化的良好习惯?如果没有,那么你知道不同存储类型的变量默认的初始值是什么吗?如果变量在定义时没有初始化,你是否遇到由此引起的程序bug?那么今天我们来聊一聊在C编程当中变量的初始化。

变量存储类型

C语言当中变量的存储类型总共分为四类:分别为自动变量(auto)、静态变量(static)、外部变量(extern)以及寄存器变量(register)。

  • auto:函数中所有的非静态局部变量都属于自动变量。
  • static:在变量前加上 static 关键字的变量。
  • extern:把全局变量在其他源文件中声明成 extern 变量,可以扩展该全局变量的作用域至声明的那个文件,其本质作用就是对全局变量作用域的扩展。
  • register:一般经常被使用的的变量可以设置成寄存器变量,会被存储在寄存器中,计算速度远快于存在内存中的非 register 变量。

变量初始化与未初始化的区别

  • 测试代码
代码语言:javascript复制
#include <stdio.h>

int main(int argc, char const *argv[])
{
    int nVar1;
    int nVar2;
    int nVar3;

    printf("nVar1 = %d, nVar2 = %d, nVar3 = %dn", nVar1, nVar2, nVar3);


    return 0;
}
  • 输出结果
  • 在定义局部变量时如果不进行初始化,那么变量的值是系统随机分配的一个初始值,如果直接拿来使用可能发生未知的错误

真实案例

  • 创建socket返回0的问题

记得之前在做一个FTP上传文件相关的功能时,FTP控制连接和数据连接是自己代码实现的,发现在FTP上传完文件,在其他功能进行调用socket()函数创建socket描述符时,始终返回0.

  • 定位分析问题

经过查找,发现返回0意味着套接字创建成功,说明系统分配了可用的文件描述符为0。但是描述符0是被系统占用的,默认为标准输入,正常情况它应该是被占用的,所以在之前进行FTP相关操作时肯定有程序关闭了描述0,close(0),一旦它关闭,下一次调用函数分配一个文件描述符将返回fd的值为0,因为它是可用的(通过系统调用获取描述符时,系统会从没有占用的最小值开始返回)。按照这个思路查找程序进行全局搜索,果然发现定义静态变量时,功能操作开始时没有进行初始化,而进行清除socket的操作,导致close(0);

不同类型的变量的初始化

  • 全局变量会自动初始化为0,对于不同编译单位的全局变量,其初始化的顺序没有任何的保证,因此对不同编译单位里的全局变量,在它们的初始化顺序之间建立依赖性都是不明智的。此外也没办法捕捉到全局变量初始化抛出的异常,一般来说要减少全局变量的使用,特别是限制那些要求复杂初始化的全局变量。因此尽量不用全局变量
  • 局部变量如果变量是在局部域中定义的,或是通过动态分配的,则系统不会向它提供初始值0,被认为是未初始化,其值随机。
代码语言:javascript复制
    int *pnVar = NULL;
    int nTest = 0;

    pnVar = malloc(5*sizeof(int));
    if (pnVar)
    {
        memset(pnVar, 0, 5*sizeof(int)); // 要进行初始化
    }
  • 数组可以显示地用一组数初始化
代码语言:javascript复制
    const int aray_size=3;
    int ia[aray_size]={0,1,2};
    int a[5] ={0};      // 则a的各各元素都初始化为0

    // 如果指定的维数大于给定的元素的个数,没有被显示初始化的元素将置为0。也可以不指定维数值
    int ia[]={0,1,2};

    char buf[10] = {''};

总结

  • 在平时的编程中我们要养成良好的编程习惯,定义变量的同时进行初始化,这样会减少程序出现bug的几率。往往一个小的细节可能会引发一个大的问题。
  • 后续会结合C、C 在定义变量及变量初始化的问题进行详细对比分析

0 人点赞