明明白白c++ 初始化

前言

如果你做过c/c++的开发,如果你参加过c/c++的面试,那么初始化这个问题无疑是必考的题目。
开始的时候,我也很奇怪,初始化这个东西有什么好讲的,简单的说不就是没有给初值么,等看到很多错误,调试很多代码,吃了亏,上了当之后,才明白别人再怎么强调初始化的重要性都不为过。
java这点很好,必须初始化,否则编译不过。正向有个老师说的java就像是一个被保护好的孩子,你一旦有点问题就阻止你,但是c/c++就不是了,给你自由,出问题你自己负责。

一内置变量初始化

1 基本变量

这里主要讲内置变量int, float ,long ,double,bool等
首先说初始化的概念:
在定义变量的时候,给变量赋予初值,叫做初始化的变量,否则就叫未初始化的变量。

没有被初始化的变量他们的值是什么?
如果是局部变量,则是随机值,如果是全局变量则为0.
未初始化只有一个好处,如果初始化变量位于代码段中,会占用一定的空间。但是未初始化的坏处几乎是全部。
个人建议,如果你没有pclint等检查工具检查你的代码,最好给局部变量赋予初值,防止出现一些莫名其妙的错误,查问题耽误太多时间。
(ps,pclint检测的时候,如果你初始化了,但是却没有用这个变量,则会报错)
举个例子:
#include<iostream>
using namespace std;

int main()
{
   int sum;  
   for (int i =0 ;i<10;i++)
         sum += i;
    cout<<sum<<endl;
}

我电脑里面运行的结果是2281105。而不是你想要的55.
你可能会说这个很简单,但是现实中编程序,开始有一堆的变量,我记不太清,c89的时候c语言必须所有的变量都在开头的时候声明,这样会导致,你声明了一堆变量,有些你要初始化,有些你不初始化,就会很麻烦
关键在于很多crash由于没有初始化导致的,比较麻烦的事情是,由于是随机值,有些环境是ok,有些环境出问题,而且还不是必现的,查问题相当困难。


另外讲一下 c++ primer里面比较蛋疼的一句话。
“初始化不是赋值”。
初始化有两种情况:
int a = 1;     //赋值初始化
int a(1);     // 直接初始化
赋值是什么?
a = 2;
你可以理解为定义a的时候的=号和其他时候的=不一样。这个在复杂类里面才能看出来区别,这里看不出来。
直接初始化比赋值初始化效率高一些。

2 常量

常量必须初始化,因为常量不能被修改。
const int a  = 5; // ok
int b;// 错误,没初始化
a = 3;//错误,被修改

这里加一句,书上看到的,虽然和初始化没关系。就是有const限定符的函数外定义的变量,默认是只能在这个文件中访问的,别的文件中访问需要加extern.
a.cpp里面
const int a =3;
int b;     // 相当于extern int  b =0;
const int c =4;// 如果b文件中用到,需要声明为 extern const int c = 4;
b.cpp 里面
int b;//编译的时候会报错,重复定义,修改为extern
const int a = 3;// ok
extern const int c;//错误,该声明没有定义。
(ps 我会在后面的声明和定义里面讲一下这个内容)

3 引用

引用必须初始化,引用指向的对象不能变,但是对象的内容可以变。
int a = 3;
int b = 4;
int &c  =a;
int &d;// 编译会报错,引用必须初始化,
c = b;
这个时候a,b,c的值是多少呢?都是4。
c = 5;
这个时候呢?a = 5, b= 4,c =5;
所以上面的那句c = b;相当于c = 4,也就是a =4;后面对c的所有操作都是改变a的值。c不会指向其他对象了。



4枚举
枚举是常量
enum test
{
a,
b,
c
};
这个时候a = 0, b = 1 ,c =2, 枚举成员的第一个默认初始化为0,
enum test
{
c=1,
d,
e=5,
f
};
这个时候d =2, f =6,没有初始化的默认为它前面的那个值+1;

5 数组

int a[5];//这些值都是随机值
int b[5] ={1,2,3,4,5};//全部都初始化了
int c[5]={1,2};//相当于{1,2,0,0,0}
int d[100] ={0};//相当于将数组全部初始化为0

6 字符串
字符串是c语言的特性,它是一种特殊的产物;举个例子
char *p = "abcd";
这个和
char p[]="abcd";
char p[5]={'a','b','c','d','\0'};
效果是一模一样的,char *p = "abcd";这句话很特殊,编译的时候会报警告,说不建议这么写,但是实际上这么写也没有问题。

int a =5;
int *b =&a;
char p = 'a';
char *q = &p;

你会发现如果用printf打印,是没有问题的,因为你已经指定好了类型。但是如果用cout;
cout<<b<<endl;
cout<<q<<endl;

这个时候b打印出来会是个地址,而q这个时候,cout就会把它当成一个字符串,就会打印直到遇到'\0',而这个时候输出的结果就要看a的值,你可以试试改变a的值,则每次打印的结果不一样。

7 指针

指针没有初始化,就是野指针,指向一个随机的地址,破坏性很大。指针一定要初始化。

二类的初始化


1 类成员变量初始化

可以参考这篇文章写得很详细http://blog.csdn.net/jenghau/article/details/4752735
类成员的初始化,不能再定义的时候初始化,要在构造函数里面初始化。
class A{
public:
     A();
private:
      int data;
      static int st_data;
      const int const_data = 10;
};
简单总结一下:
1.1普通变量,两种初始化方式:
第一,初始化列表
A::A():data(0)
{
}
第二,赋值
A:A()
{
    data = 0;
}
如果不初始化,则遵守上面的规则,内置类型随机值,类的话调用构造函数。
1.2 静态变量

int A::st_data = 0;//类外初始化
它是所有类共享的,和对象没有关系

1.3 const 常量
创建的时候初始化,见上面的例子
1.4 引用变量
在初始化列表里面初始化
class B{
public:
   B();
   B(A a);
private:
    A &m_a;
}

B::B(A a):m_a(&a)
{
}

5 const static的
 short 类型的在类定义初始化
 float在构造函数中初始化。

2 类对象初始化

局部对象没有初始化,它的值是多少,开始我想这个问题的时候,总和上面的内置类型的变量弄混淆,如果是自定义的类对象变量,它的值一般为空。
例如
string a;//输出之后a就是空的。
为什么呢?和上面的似乎有些矛盾,其实并不矛盾。上面的是基本类型。
类呢,本身有个默认构造函数,它会初始化对象。
受上面的例子的毒害,我一直认为,模式构造函数如果不声明,它会将类中的元素给初始化为0或者空值,但是实际情况并非如此,看下面的例子。
 
#include<iostream>
#include<string>
using namespace std;

class A
{
public:
   int data;
friend ostream& operator<<(ostream&,const A&);       //同理
};

ostream& operator<<(ostream&,const A& a)
{
    cout<<a.data<<endl;
}

int main()
{
  A a;
  cout<<a.data<<endl;
  cout<<a;

}

我这里的输出是
2281060
2281060
不过和编译有关系,有的时候也能碰巧为0,怎么验证这个值是随机值呢,你改变一下代码的顺序,或者在class A里面随便加几个不用的变量等等,就会发现输出结果发生变化了。

但是如果我们自己写构造函数,必须先在类里面声明一下。
A::A()
{
   data = 0;  
}  
那么上面的结果就一定是0了。
可见string 的默认构造函数在标准库就将里面的char* 初始化为了0
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值