指针、引用、引用和函数参数、引用和const、const 和 #define、#define的特殊用途

一、const

•const可以限定一个变量的值不允许被改变,使用const在一定程度上可以提高程序的安全性和可靠性
•const int a = 10;
Ø变量a的值是不能被修改的,永远都是初值10
Øint const a = 10;跟上述写法是等价的
Ø
•void sum(const int a, const int b)
Ø上面的函数可以防止别人篡改形参的值
Ø
•可以看出,const可以用来定义一个常量。作用跟enum、#define类似
•下面的例子表示p是个常量,不能再给p赋值,不能让p再指向其他变量

int a = 10;

int * const p = &a;

 
•下面的例子表示*p是个常量,不能通过*p来修改变量a的值

int a = 10;

const int *p = &a;

 

•下面的例子可以防止test函数的形参a指针修改外面age变量的值

void test(const int * a);

 

int age = 10;

test(&age);

 

•下面的例子表示*p和p都是常量

int a = 10;

const int * const p = &a;

 

二、const习题

1)下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢?

typedef char * pStr;

char string[4] = "bbc";

const char *p1 = string;

const pStr p2 = string;

p1++;

p2++;

 

2)判断下列p1、p2的变量类型 和 常量性
Øint const * p1, p2;
Øint const * const p1,p2;
Øint * const p1,p2;
 

3)判断最后2句代码是否合理

3.1指针指向的变量的值不能变,指向可变

int x = 1;

int y = 2;

const int* px = &x;

px = &y;

*px = 3; 

 

3.2 指针指向的变量的值可以改变,指向不可变

int x = 1;

int y = 2;

int* const px = &x;

px = &y;

*px = 3; 

3.3指针指向的变量的值不可变,指向不可变

int x = 1;

int y = 2;

const int* const px = &x;

px = &y;

*px = 3; 

 

三、const 和 #define

•const和#define都能用来定义常量,可以造成一改全部跟着一起改的效果
•实际上,更推荐使用const或者enum来定义常量
Øconst推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点
Øconst可以节省空间,避免不必要的内存分配。举例:

#define PI1 3.14159 // 常量宏

const double PI2 = 3.14159; // 此时并未将Pi放入RAM中

double a = PI2; // 此时为PI2分配内存,以后不再分配!

double b = PI1; // 编译期间进行宏替换,分配内存

double c = PI2; // 没有内存分配

double d = PI1; // 再进行宏替换,又一次分配内存!

四、#define的副作用

•#define有时候会产生一些不好的副作用,比如下面的例子:

// MAX宏返回两个数值中的最大值

#define MAX(x, y) ((x) > (y) ? (x) : (y))

int a = 10;

int b = 6;

int c = MAX(++a, b);

cout << "c = " << c << ", a = " << a << endl;

 

这时候的输出结果是:c = 12, a = 12

 

如果将变量b的初值改为15,也就是int b = 15;

这时候的输出结果是:c = 15, a = 11

 五、#define的特殊用途

•#define还是有它无可取代的地方,比如
Ø传入一个参数,然后生成字符串

#define TO_STR(x) #x

cout << TO_STR(abcd) << endl;

 

Ø连接多个参数,合成一个完整的标识符

#define CONCAT(x, y) x##y

int myage = 20;

cout << CONCAT(my, age) << endl;

 

六、引用

•引用:其实就是给变量起一个别名
•引用的特点:
Ø引用没有独立的存储空间,跟被引用的变量共享存储空间
Ø对引用所做的改变,就是对所引用变量所做的改变
 
七、引用的定义
•引用的定义格式:类型 &引用名称 = 变量名; 
•比如下面的af就是变量a的一个引用

int a = 10;

// 引用必须在定义的时候就进行初始化

int &af = a;

// 引用af 和 变量a 的内存地址一致

cout << &af << ", " << &a << endl;

 

// 变量a的值被改为了20

af = 20;

cout << af << ", " << a << endl;

 

程序的输出结果是:

0x7fff5fbff89c, 0x7fff5fbff89c

20, 20

 

八、下面的例子表示bf、af同时引用着变量a

int a = 10;

int &af = a;

int &bf = af;

cout << &bf << ", " << &af << ", " << &a;

 

打印出来的内存地址是一致的

九、引用的使用注意

•在定义的时候就进行初始化。下面的是错误写法:

int &af;

 

•引用一旦在定义的时候确定好引用哪个变量,以后都不能再引用其他变量

int a = 10;

int &af = a;

 

int b = 20;

af = b;

 

最后一行代码af = b;并不代表af引用了变量b,而是将变量b的值赋值给了af引用,也就是将变量b的值给了a

十、const 与 引用

•称af为const引用

int a = 10;

const int &af = a;

 

•下面的代码是不能编译通过的。因为ref引用的类型和变量d的类型不匹配

double d = 1.78;

int &ref = d;

•但是将ref改为const引用,就能编译通过

double d = 1.78;

const int &ref = d;

编译能通过的原因是const int &ref = d;等价于下面2句:

int temp = d;

const int &ref = temp;

也就是说ref引用 跟 变量d 并不共享同一块存储空间

十一、引用 与 函数参数

•引用可以作为函数的形参,修改了引用形参,能影响外面实参变量的值
•如果要在函数内部修改外面实参的值,尽量使用引用作为形参,不要使用指针作为函数形参,原因如下:
Ø引用不占用额外的存储空间
Ø使用引用修改实参显得更自然、易懂
 
十二、引用 与 函数返回值
•用也可以作为函数的返回值,主要目的是:可以将函数调用放在赋值运算符(=)的左边

int ages[] = {20, 15, 36, 17, 28};

int & ages_index(int i)

{

    return ages[i];

}

// 相当于ages[0] = 30;

ages_index(0) = 30; 

十三、引用 与 函数返回值

•注意:不能返回对局部变量的引用

int & add(int a, int b)

{

    int sum = a + b;

    return sum;

}

 

int n = add(10, 20);

int &nf = add(10, 10);

cout << "n = " << n << endl;

cout << "nf = " << nf << endl;

 

上面的程序会造成nf引用的值是不确定的,并不是20

十四、引用 与 指针 的区别

•引用没有独立的存储空间,指针有自己独立的存储空间
•引用只能在定义时被初始化一次,之后不可变;而指针的值是可变的
•引用不能为空,指针可以为空
•“sizeof 引用”得到的是所引用变量的大小;”sizeof 指针”得到的是指针的大小
•引用和指针的自增++自减--运算含义不一样 
 

posted on 2013-12-21 11:37  林源  阅读(387)  评论(0编辑  收藏  举报

导航