今天来讲讲C++的变量知识。C++的基础类型与C一样,都有int,char,float,double,pointer,下面是未初始化时,各个基础类型的初始值。

数据类型 初始化默认值
int 0
char ‘\0’
float 0
double 0
pointer NULL

C++没有字符串基础类型,字符串则是由字符数组表示,这点跟C一致。不过C++标准库有String类的实现。另外C++不适合做web开发很大一部分与其比较弱的字符串处理有关,毕竟web开发很大一部分都是跟字符串打交道比如最好的语言PHP(滑稽)。

全局变量与局部变量

简单的理解就是写在所有函数外部的就是全局变量,写在函数内部的就是局部变量,包括main函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
int a; //全局变量
void call()
{
int c; //局部变量
}
int main()
{
int b; //局部变量
call();
return 0;
}

全局变量,一般情况下在被其他源文件include之后,可以直接使用,但前提是没有static关键字修饰。全局变量在本文件的哪个地方都能使用。

局部变量,通常包括被调用函数内部声明定义的变量以及形参,其声明周期在被调用函数结束后销毁。

静态变量

C++静态变量通常是指被static修饰的变量,这种变量在 程序运行之前就已经分配好内存,在程序结束时才释放。这中变量的内存被分配到全局静态区,由系统进行管控。除此之外,static关键字还有以下几种功能。

  • static修饰全局变量,会使得该全局变量 只能在本文件中使用 ,当其他源文件include了此文件后,不能使用该static修饰的全局变量。

  • static修饰局部变量,会使该局部变量只能限定在自己所在的作用域(即所在函数),这和其他局部变量一样,但是唯一不同的是由于静态变量是 程序结束时才会进行回收,因此回收阶段不在所在函数退出调用时,即 一次分配全程有效,所以下次调用该静态变量所在函数时,该变量的值不会重新申请内存以及重新初始化。

  • static修饰的类成员变量,能在该类 所有所属的对象中共享。static修饰的类成员方法,不需该类实例化 就才能使用,直接 类::静态方法 即可使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
static int a ; //静态全局变量
void call()
{
static int b = 0 ; //静态局部变量
cout << b << endl;
b++;
}
int main()
{
static int c ; //静态局部变量
call(); //输出0
call(); //输出1
return 0;
}

const修饰的变量

const原义是constant,意为永恒的,不变的。一看就觉得这个修饰词很强壮Rua!,这个const作用很大,可以修饰变量,修饰返回值,修饰参数,修饰函数。通常被它修饰过的多多少少代表着不会变化,不过具体情况具体分析。

修饰普通变量

被const修饰的普通变量就成为了C++中的常量,在声明一定要初始化。在代码里一旦修改了const修饰的变量会出现编译错误。另外,const修饰的位置可以在类型前面,也可以在类型后面,意义一致

1
2
const int a =3;
//等同于 int const a=3;

修饰返回值

被const修饰的函数返回值,要分两种情况讨论。第一种是,如果返回值是非指针应用类型,那么它跟没有const修饰的函数返回值一样,没有特别的。

1
2
3
4
const int call()
{
// ....
}

第二种情况是,如果返回值时指针类型,那么如果函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const修饰的同类型指针,否则会出现编译错误。

1
2
3
4
5
6
7
8
9
const char* call()
{
// .....
}
int main()
{
const char* str= call(); //str指针务必是const修饰的
}

修饰参数

对于非基础数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是 提高效率。例如将void Func(A a) 改为void Func(const A &a)。这样既免去了对象的复制(临时对象的构造、复制、析构消耗时间),又可以不改变原引用内容。

1
2
3
4
void call(const A &a)
{
// your code
}

对于基础数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &x)。基础数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。

修饰函数

在一个类成员函数中,如果被const修饰后,该成员函数 不能改变成员变量的内容,除非成员变量带有 mutable修饰符,否则会提示编译错误。另外,const修饰的位置在函数名(含参数)后。

1
2
3
4
5
6
7
8
9
10
11
12
class A
{
private:
int a;
mutable int b;
public:
void test() const
{
this->b = 3; //可以修改
// this->a =4; 不能修改
}
}

const char* , char const* , char* const 傻傻分不清

相信刚入门的小朋友肯定会对这几个变量的声明形式搞得头晕脑胀,下面就顺便说一下吧。

在此之前,先介绍一个声明指针变量的读法,有助于大家记忆。

1
char * p;

从右往做读,* 读作pointer to意为指向。即变量p为指向char类型的指针(p is a pointer to char)

指向常量的指针

1
2
3
4
5
const char * p = "123";
//char const * p = "123";
p = &test ; //p仍能指向别的 假设&test为字符串的首地址
*p = "111" ; //编译错误 不能改变指向的内容

因为const可以放在类型的前面或者后面,所以上面两个意思等价。同为 p is a pointer to const char,即变量p是一个 指向const的char 指针。等号右边的内容为const不能改变。

常量指针

1
2
3
4
5
char * const p = "123";
//char * p const = "123";
p = &test ; //编译错误 p不能再指向别的 假设&test为字符串的首地址
*p = "111" ; //无编译错误 可以改变指向的内容

上面两种等价,const修饰的是p变量而不是char,所以p is a const pointer to char,即为p是指向char的const指针。等号左边的变量p一旦指向了,就不能更改。

简单来理解就是const 修饰的对象不同,一个是修饰左值,一个修饰右值,* 就如一座大山,若const在 * 的左边,则修饰等号右边的值,若在 * 的右边,则修饰变量p,一旦初始化了就不能更改的指针。

指向常量的常量指针

看了我上面的解释,应该知道这个怎么写了吧?没错就是下面那样:

1
2
const char * const p ="123";
//char const * const p ="123"; //同上 等价

港真,这种变量真的没什么用….p因为常量指针,所以自身不能改变指向。p指向的内容是常量,所以p不能改变内容,所以感觉实用性不大,仅供学习参考。

总结

以上知识不是光看就能明白,还需要动手打一下验证一下!编程是一门实践性极强的技术。

参考

const 修饰函数参数,返回值,函数体

const char *, char const *, char * const的区别

C/C++中static关键字详解

指针常量与常量指针