你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

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

[复制链接]
gaosmile 发布时间:2021-2-2 11:13
在敲代码的时候,我们会给变量一个初始值,以防止因为编译器的原因造成变量初始值的不确定性。对于数值类型的变量往往初始化为0,但对于其他类型的变量,如字符型、指针型等变量等该如何初始化呢?; Y/ R! ^  g7 f6 Y2 x. t: O5 A- L
" Y3 h2 c+ w8 x4 [. o# F! c$ h( G$ j
数值类变量初始化
% g/ M2 u. ~$ n
5 u# p% b& E0 n8 G( h* U
- l5 d- v9 T  i0 p3 I
整型、浮点型的变量可以在定义的同时进行初始化,一般都初始化为0。
: r- {0 G, T6 A, N* L, `1int    inum  = 0;7 I1 C- y7 s2 ]- l- s9 t
2float  fnum = 0.00f;
* n4 ~: Z  g* E4 v3double dnum = 0.00;

% S( K# g. J- h1 }. {: j) W8 f: c' ^$ ]$ d/ ^; w  f& w
7 U3 e8 w5 K1 E$ E
字符型变量初始化5 {  b; h2 n0 Z" _2 K$ X" W
字符型变量也可在定义的同时进行初始化,一般初始化为'\0'。
4 ?. {$ r" I$ d1char ch = '\0'; ( V7 R* g: m- v. I1 y
% Q8 L  F) f  S: g+ p# f8 Y+ @9 P

8 B" r* F( N4 X5 G$ H字符串初始化
$ @! v. g% `- n( R0 g字符串初始化的方法比较多,我这里简单介绍三种,因为字符串本质上是由一个个字符组成的字符数组,所以其初始化的最终目的,就是将字符数组里面的一个个字符都初始化为'\0'。
方法一:使用空的字符串""。
char str[10] = "";
6 Y2 _1 n- A  f
方法二:使用memset。
char str[10];
& H# U& x* ?, I6 A" Cmemset(str, 0, sizeof(str));
) n1 k# B% m. B3 g
方法三:写一个循环。
char str[10];  ^" b  g3 t* W4 [0 n7 {9 @  S' y
for(int i = 0; i < 10; i++)2 n0 D; ~+ M7 e
{
7 p4 N3 C, {5 G! h    str = '\0';
' W- H: N, L, m8 H0 W$ C% Z}
# }& ]: \. \! F0 f# L
这里比较推荐的是第二种初始化方法。也即使用memset进行初始化。
很多人对memset这个函数一知半解,只知道它可以初始化很多数据类型的变量,却不知道其原理是什么样的,这里做一下简要的说明:memset是按照字节进行填充的。: E6 }% y, p7 Y# N: p0 V, D
先看下面的一段代码:
int num;: T% ~' \, e' C- B
memset(&num, 0, sizeof(int));! W! g3 h# S) R  G2 W3 y
printf("step1=%d\n", num);
7 s  h% y& G% o! {memset(&num, 1, sizeof(int));
2 x7 C$ \& U) m% t9 q  Aprintf("step2=%d\n", num);) T) `6 X  D8 U; m
在讨论之前,我们先看一下运行结果
chenyc@DESKTOP-IU8FEL6:~/src$ gcc -o memset memset.c -g
9 ~, l0 q( [6 ^9 S: w; K/ R! @( xchenyc@DESKTOP-IU8FEL6:~/src$ ./memset
4 ^/ m, ?/ [" d' K4 `6 @step1 = 0; F: l1 D1 v9 p  @% R
step2 = 16843009
0 F: F, r* J* D0 ^. H& |chenyc@DESKTOP-IU8FEL6:~/src$
5 `. N* y0 ?3 y+ }
看到这个运行结果,是不是和你想象中的不一样呢?
6 @8 K: d+ X  k1 w) r9 xstep1 = 0 相信大家都好理解,可 step2 = 16843009 很多人就不能理解了。按照一般的惯性思维,不是应该 = 1 才对么?
+ X/ G3 x! s/ p2 s' b0 H: @2 q* m这就是我要说的,memset是按照字节进行填充的。# d% I: q+ ~$ r
我们知道,int 型是4个字节(每个字节有8位),按二进制表示出来就应该是:
00000000 00000000 00000000 00000000
, g& f6 B4 z, L  d$ r, e1 X
按照按字节填充的原则,step1 的结果就是将4个字节全部填充0,所以得到的结果仍然是0:
00000000 00000000 00000000 000000000 [) `  p8 q: p
而 step2 则是将每个字节都填充为1 (注意是每个字节,而不是每个byte位) ,所以相对应的结果就应该是:
00000001 00000001 00000001 00000001
3 J1 Y; t) x4 |; e
大家可以自己将上面那个二进制数转换成十进制看看,看看是不是16843009。
1 [5 k* \" o5 [" p所以严格来说,memset函数本身并不具有初始化的功能,而是一个单纯的按字节填充函数,只是人们在使用的过程中,扩展出了初始化的作用。
字符串初始化有一个小窍门,我们知道字符串本质上是字符数组,因此它具有两个特性,
  • 字符串在内存里是连续的,
  • 字符串遇'\0'结束。, N: `8 Z% H& X! N( z) z% T
    所以我们在初始化的时候,总是愿意给字符串本身长度加1的长度的内存进行初始化。

    * m! B2 z/ Y, ]' Z
char year[4+1];! [) g4 }0 b$ y2 p
memset(year, 0, sizeof(year));
: V+ `6 R; D' q' q$ T+ mstrcpy(year,"2018");

* f* E/ ^% P, }0 F
, f, \% V+ b& K' k1 }8 G
指针初始化

3 \3 e' |; A$ T' F一般来说,指针都是初始化为NULL。# F' a/ E3 m) @. J4 k3 f
int *pnum = NULL;* _$ N' I4 m0 Q, \
int num = 0;
0 {$ }( D7 p9 l* H- vpnum = #3 s1 u( U- c4 b& H% Q4 I0 d1 k' u
指针是个让人又爱又恨的东西,一般的整形、字符串等,初始化之后就可以直接拿来用了,可指针如果初始化为NULL后,没有给该指针重新分配内存,则会出现难以预料的错误(最最常见的就是操作空指针引起的段错误)。在动态内存管理中,由于变量的内存是分配在堆中的,所以一般用malloc、calloc等函数申请过动态内存,在使用完后需要及时释放,一般释放掉动态内存后要及时将指针置空,这也是很多人容易忽略的。

5 R7 T, m: k" W9 E" a( e' n0 {char *p = NULL;  , X# o/ V7 c% W; T6 k
p=(char *)malloc(100);  
! W7 s6 `7 ?7 x; T3 Q4 Rif(NULL == p)
# Y/ o3 Q1 s4 Q5 x7 c5 [{  $ e3 z3 R, E& i3 A/ G7 r1 i7 K! p/ Q
    printf("Memory Allocated at: %x\n",p);  7 z  r5 Z9 e) v5 D% o
}- k0 C: S5 S+ [) {  c
else
' h$ C: O  w; ^3 {, j{
1 h! B# `/ Q6 i' O* s    printf("Not Enough Memory!\n");  
5 A  a6 c* H3 t8 G) C$ l5 U9 Y& C}
1 n+ z6 _: e8 Ifree(p);  
9 R" ^, W8 i6 V$ S. Op = NULL;   //这一行给指针置空必不可少,否则很可能后面操作了这个野指针而不自知,从而导致出现严重的问题

3 X9 I- w: c/ S9 [% O$ R$ X
$ h* u# x: v$ a
很多人经常会犯的一个错误,我们知道,在指针作为实参进行参数传递时,该指针就已经退化成了数组,所以很多人就想到用memset来对该指针进行初始化:
0 B6 d5 d/ v( V, ^' {
void fun(char *pstr), d+ q4 Z# A- c) f% _
{
% U: K. Z5 F. d! I8 F, A0 |& @& {  memset(pstr, 0, sizeof(pstr));
: U. ?; z* l5 k  {" N+ G  ...3 x0 C$ Z, p9 f4 Z. u& K
}2 W1 }/ C& @1 n! f) x
这种写法是不正确的。我们姑且不管指针能不能用memset来进行初始化,指针首先保存的是一个4字节的地址,所以sizeof(pstr)永远只能 = 4,这样的初始化就毫无意义。

9 f: `  {6 f7 d9 `* P$ H: x
$ W) Z/ d+ b, ^4 o
1 p; B3 C5 u9 X1 i/ c2 r+ L" G6 J
结构体初始化
: R2 e5 T# \; V/ o' u  _结构体的初始化就比较简单了,基本也都是采用memset的方式。# s3 d/ {$ M2 a  ]; D& A) j
typedef struct student
1 _+ @4 {9 W5 t: t" Y' }/ h{

$ k5 H5 _& f7 O4 ^0 ^2 Q    int id;
/ i; T: p" z8 W$ D    char name[20];
6 K" {( ?  E) O* L! ^    char sex;( S7 S4 i- K& m# x  `% N' y
}STU;
* \' C  I: h2 @# E# l6 @5 G1 aSTU stu1;
1 ^2 K& J# }* Amemset((char *)&stu1, 0, sizeof(stu1));
* y3 J/ ?- j9 f, B
关于初始化结构体的长度问题,也即memset的第三个参数,一般来说,传入数据类型和变量名效果是一样的,上例中,下面写法是等价的效果:
7 a+ n9 {$ Q) x0 ~, c
memset((char *)&stu1, 0, sizeof(STU));
5 @' L% ~: p' C7 ?7 t: L$ X
但是对于结构体数组的初始化,长度就需要注意一下了,还是以上例来做说明:

, n( o. d% Q; C6 k. `: MSTU stus[10];
: c; J# [, L/ a7 {1 x6 w, h1 C( s5 mmemset((char *)&stus, 0, sizeof(stus)); //正确,数组本身在内存里就是连续的,sizeof取出的就是数组的字节长度
$ }2 u4 S  D& [: Q# t- K; Omemset((char *)&stus, 0, sizeof(STU));  //错误,只会初始化第一个STU结构体,后面还有9个STU元素并未初始化/ Z* f8 R2 c- x4 d" g4 L9 }4 c
memset((char *)&stus, 0, sizeof(STU)*10);  //正确,效果与第一个是一样的6 s# ]4 x* n4 T* j% ^; f0 O
有些人习惯将memset的第二个参数写成以下形式:memset((char *)&stu1, 0x00, sizeof(stu1));5 ~4 G  r  T1 N# |
只要理解了memset是按字节进行填充的,就知道这样写也是正确的,完全没有问题。
9 S4 z/ `% w/ f
* n2 @( r3 x. f* c3 E0 U5 H
赞 收藏 评论0 发布时间:2021-2-2 11:13

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版