C语言编程时,各种类型的变量该如何初始化?

关注+ 星标公众 ,不错过精彩内容

来源 | 网络、嵌入式ARM

在敲代码的时候,我们会给变量一个初始值,以防止因为 编译器 的原因造成变量初始值的不确定性。对于数值类型的变量往往初始化为0,但对于其他类型的变量,如 字符型、指针型 等变量等该如何初始化呢?

数值类变量初始化

整型、浮点型的变量可以在定义的同时进行初始化,一般都初始化为 0

1int    inum  = 0;
2float  fnum = 0.00f;
3double dnum = 0.00;

字符型变量初始化

字符型变量也可在定义的同时进行初始化,一般初始化为 '\0'

1char ch = '\0'; 

字符串初始化

字符串初始化的方法比较多,我这里简单介绍三种,因为字符串本质上是由一个个字符组成的字符数组,所以其初始化的最终目的, 就是将字符数组里面的一个个字符都初始化为 '\0'

方法一 :使用空的字符串
""

char str [ 10 ] = “” ;

方法二 :使用
memset

char str [ 10 ];

memset ( str , 0 , sizeof ( str ));

方法三 :写一个循环。

char str [ 10 ];

for ( int i = 0 ; i < 10 ; i ++ )

{

str [ i ] = ‘\0’ ;

}

这里比较推荐的是第二种初始化方法。也即使用 memset 进行初始化。

很多人对 memset 这个函数一知半解,只知道它可以初始化很多数据类型的变量,却不知道其原理是什么样的,这里做一下简要的说明: memset 是按照字节进行填充的。

先看下面的一段代码:

int num;

memset ( & num , 0 , sizeof ( int ));

printf ( “step1=%d\n” , num );

memset ( & num , 1 , sizeof ( int ));

printf ( “step2=%d\n” , num );

在讨论之前,我们先看一下运行结果

chenyc@DESKTOP-IU8FEL6:~/src$ gcc -o memset memset.c -g

chenyc@DESKTOP-IU8FEL6:~/src$ ./memset

step1 = 0

step2 = 16843009

chenyc@DESKTOP-IU8FEL6:~/src$

看到这个运行结果,是不是和你想象中的不一样呢?


step1 = 0
 相信大家都好理解,可 
step2 = 16843009
 很多人就不能理解了。按照一般的惯性思维,不是应该 
= 1

才对么?

这就是我要说的, memset是按照字节进行填充的。

我们知道,


int
 型是4个字节(每个字节有8位),按二进制表示出来就应该是:

00000000 00000000 00000000 00000000

按照按字节填充的原则,step1 的结果就是将4个字节全部填充0,所以得到的结果仍然是0:

00000000 00000000 00000000 00000000

而 step2 则是将每个字节都填充为1  (注意是每个字节,而不是每个byte位) ,所以相对应的结果就应该是:

00000001 00000001 00000001 00000001

大家可以自己将上面那个二进制数转换成十进制看看,看看是不是
16843009

所以严格来说,memset函数本身并不具有初始化的功能,而是一个单纯的按字节填充函数,只是人们在使用的过程中,扩展出了初始化的作用。

字符串初始化有一个小窍门,我们知道字符串本质上是字符数组,因此它具有两个特性,

  • 字符串在内存里是连续的,

  • 字符串遇
    '\0'

    结束。

    所以我们在初始化的时候,总是愿意给字符串本身长度加1的长度的内存进行初始化。

char year [ 4 + 1 ];

memset ( year , 0 , sizeof ( year ));

strcpy ( year , “2018” );

指针初始化

一般来说,指针都是初始化为 NULL

int * pnum = NULL ;

int num = 0 ;

pnum = & num ;

指针是个让人又爱又恨的东西,一般的整形、字符串等,初始化之后就可以直接拿来用了,可指针如果初始化为 NULL 后,没有给该指针重新分配内存,则会出现难以预料的错误(最最常见的就是操作空指针引起的段错误)。

在动态内存管理中,由于变量的内存是分配在堆中的,所以一般用 malloc calloc 等函数申请过动态内存,在使用完后需要及时释放,一般释放掉动态内存后要及时将指针置空,这也是很多人容易忽略的。

char * p = NULL ;

p = ( char * ) malloc ( 100 );

if ( NULL == p )

{

printf ( “Memory Allocated at: %x\n” , p );

}

else

{

printf ( “Not Enough Memory!\n” );

}

free ( p );

p = NULL ; //这一行给指针置空必不可少,否则很可能后面操作了这个野指针而不自知,从而导致出现严重的问题

很多人经常会犯的一个错误,我们知道,在指针作为实参进行参数传递时,该指针就已经退化成了数组,所以很多人就想到用 memset 来对该指针进行初始化:

void fun ( char * pstr )

{

memset ( pstr , 0 , sizeof ( pstr ));

}

这种写法是不正确的。我们姑且不管指针能不能用 memset 来进行初始化,指针首先保存的是一个4字节的地址,所以 sizeof(pstr) 永远只能  = 4 ,这样的初始化就毫无意义。

结构体初始化

结构体的初始化就比较简单了,基本也都是采用 memset 的方式。

typedef struct student

{

int id ;

char name [ 20 ];

char sex ;

} STU ;

STU stu1 ;

memset (( char * ) & stu1 , 0 , sizeof ( stu1 ));

关于初始化结构体的长度问题,也即 memset 的第三个参数,一般来说,传入数据类型和变量名效果是一样的,上例中,下面写法是等价的效果:

memset (( char * ) & stu1 , 0 , sizeof ( STU ));

但是对于结构体数组的初始化,长度就需要注意一下了,还是以上例来做说明:

STU stus [ 10 ];

memset (( char * ) & stus , 0 , sizeof ( stus )); //正确,数组本身在内存里就是连续的,sizeof取出的就是数组的字节长度

memset (( char * ) & stus , 0 , sizeof ( STU )); //错误,只会初始化第一个STU结构体,后面还有9个STU元素并未初始化

memset (( char * ) & stus , 0 , sizeof ( STU ) * 10 ); //正确,效果与第一个是一样的

有些人习惯将 memset 的第二个参数写成以下形式:

memset (( char * ) & stu1 , 0x00 , sizeof ( stu1 ));

只要理解了 memset 是按字节进行填充的,就知道这样写也是正确的,完全没有问题。

免责声明: 本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。

————  END   ————

欢迎关注我的公众号:

欢迎关注我的视频号:

点击“ 阅读原文 ”查看更多分享,欢迎 点分享、收藏、点赞、在看。