前言
经常有小伙伴在编写程序时因为变量未进行初始化而导致bug的出现。
在平时编写程序时你是否在定义变量时有初始化的良好习惯?如果没有,那么你知道不同存储类型的变量默认的初始值是什么吗?如果变量在定义时没有初始化,你是否遇到由此引起的程序bug?那么今天我们来聊一聊在C编程当中变量的初始化。
变量存储类型
C语言当中变量的存储类型总共分为四类:分别为自动变量(auto)、静态变量(static)、外部变量(extern)以及寄存器变量(register)。
- auto:函数中所有的非静态局部变量都属于自动变量。
- static:在变量前加上 static 关键字的变量。
- extern:把全局变量在其他源文件中声明成 extern 变量,可以扩展该全局变量的作用域至声明的那个文件,其本质作用就是对全局变量作用域的扩展。
- register:一般经常被使用的的变量可以设置成寄存器变量,会被存储在寄存器中,计算速度远快于存在内存中的非 register 变量。
变量初始化与未初始化的区别
- 测试代码
#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,被认为是未初始化,其值随机。
int *pnVar = NULL;
int nTest = 0;
pnVar = malloc(5*sizeof(int));
if (pnVar)
{
memset(pnVar, 0, 5*sizeof(int)); // 要进行初始化
}
- 数组可以显示地用一组数初始化
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] = {'