C++中const笔记和其他

说实话,之前只是知道const是表示它修饰的东西不可变,但是书上有3个例子到刚才为止才记住了。那么哪3个例子?const char * Name,char * const Name,const char * const Name,除去第3个,前面2个我经常是记得乱七八糟。今天花了点时间来捋一捋。发现原来还有方法的。

怎么记?首先把这分成几部分:修饰符,指针类型,指针名称,并且把语句看出一个圆形队列。以第1个为例,分为const ,char * ,name。现在我们来套,第一个例子就是修饰符(const),指针类型(char *),指针名称(name),怎么记const修饰的东西呢?看它们的顺序,然后把const的位置值-1,如果为0就是说修饰的是指针名称,如果不为0则修饰的是位置值减1后的位置,因为第1个const对应的位置值为1,1-1=0,所以我们跑队列的后面,也就是修饰的是name。那么怎么理解name中内容不可变呢?我们这样理解,因为Name指向的是图中红色的内存空间,所以Name不可变就是内存空间中的值不可以变,但是因为划分内存空间不是Name的任务,所以给Name重新划分内存空间是允许的,也就是Name[3]='a',是非法的,但是Name="Hello";是合法的。同样的道理,char * const Name修饰的是前面一个,也就是char * 是指针,什么指针?它是一块连续的内存空间的开头,也就是说,char * const Name不允许变的是开头也就是首地址。至于你地址里面放的是什么东西,const不管,它只管首地址不变。因此修改存放的值是允许的,但是重新分配空间是不允许的。换句话说Name[3]='a',是合法的,但是Name="Hello"是非法。也许有人会问,Name="Hello"不也是赋值吗?不是的,这是重新分配内存。

       好了记住了东西,又有新的疑惑了,不小心写程序的时候写成了,char const * Name,那么const到底在这又修饰什么东西的呢,写代码就知道了。

#include <iostream.h>
//using namespace std;
main()
{
	const char *a = "chen";
	char * const b = "chea";
	char const *c = "chao";
	
	a ="chang";
	b[2]='e';
	c[3]='o';//如果报错说明const修饰的是指针
	c="Hello";//如果报错说明const修饰的是变量名
	cout<<c;
}


我们运行看看,我的VC6.0提示C[3]='0':出错了。(不怪我啊,这CSDN代码发表了才显示这一段没有了。现在VC已关了)。

我们再加点知识,下面这段代码是从贴吧看到的,直接转过来了。不知道原作者是谁。

 循环是程序最常见的结构,而程序运行所花费的时间相当一部分都是花在了各式各样的循环体上,就连评估算法的效率也是以循环为主要时间度量的,因此花点时间来了解对循环的优化还不算是无聊吧?:)

下面这6个例子很简单,说明了提高循环体效率的基本办法是降低循环体的复杂性,因此针对循环体的优化可以大幅度提高程序的效率。

======================================
(总结1) 尽量少用while循环,多用for循环
======================================

{>begin
T1 := GetTickCount;

c := 0;

i := 0;
while>begin
Inc(c);
Inc(i);
end;

T2 := GetTickCount;

Memo.Lines.Add(IntToStr(T2 - T1));
end;

Memo.Lines.Add('');
end;

进行10次while循环测试所花费的时间(毫秒):

1538
1665
1630
1702
1523
1585
1515
1685
1595
1510

{>begin
T1 := GetTickCount;

c := 0;

for>Inc(c);

T2 := GetTickCount;

Memo.Lines.Add(IntToStr(T2 - T1));
end;

Memo.Lines.Add('');
end;

进行10次for循环测试所花费的时间(毫秒):

605
645
605
605
628
615
610
670
640
625

我们可以看出while循环花费的时间比for循环多一倍不止,为什么会这样呢?原因就在于循环体的复杂性。我们来看看它们各自的汇编代码:

;>;=========循环体============
inc>;===========================

;>;=========循环体============
dec>;===========================

我们可以看到for的代码明显比while简捷,无论时钟周期和指令长度都比while有优势,所以当循环次数越大时效率差别表现就越明显。


================================
(总结2) 尽量把无关代码移出循环体
================================

一个for循环和一个if判断的代码你会怎么写呢?看看下面两个例子:

{ 逻辑判断在循环内部 }
procedure TMainForm.Btn03Click(Sender: TObject);
var
i,>begin
T1 := GetTickCount;

a := 999;
b := 1000;
c := 0;
Inc(a);

for>begin
if>
Memo.Lines.Add(IntToStr(T2 - T1));
end;

Memo.Lines.Add('');
end;

{ 逻辑判断在循环外部 }
procedure TMainForm.Btn04Click(Sender: TObject);
var
i,>begin
T1 := GetTickCount;

a := 999;
b := 1000;
c := 0;
Inc(a);

if>Dec(c);
end
else
begin
for>Inc(c);
end;

T2 := GetTickCount;

Memo.Lines.Add(IntToStr(T2 - T1));
end;

Memo.Lines.Add('');
end;

让我们来看看测试的结果:

内部比较循环10次测试(毫秒):

3890
3700
3625
3625
3710
3625
3620
3620
3620
3805

外部比较循环10次测试(毫秒):

1836
1805
1810
1810
1810
1810
1810
1810
1810
1810

可以发现,循环内部无判断的函数速度快了一倍。示例Btn03Click的函数比示例Btn04Click多执行了N-1次逻辑判断,并且由于前者老要进行逻辑判断,打断了循环的“流水线”作业,使得编译器不能对循环进行优化处理,从而降低了效率。所以如果循环体内有逻辑判断代码,并且循环次数很大,我们宜将逻辑判断移到循环体的外面。

==============================
(总结3) 大规模循环尽量是内循环
==============================

下面这两个循环表面看起来时间复杂度是一样的,但测试结果是这样的吗?我们来试试:

{ 小规模循环在内 }
procedure TMainForm.Btn05Click(Sender: TObject);
var
i, j,>begin
T1 := GetTickCount;

c := 0;

for>begin
for j := 0>
Memo.Lines.Add(IntToStr(T2 - T1));
end;

Memo.Lines.Add('');
end;

10次测试结果(毫秒):

4426
4540
4315
4320
4320
4320
4320
4320
4320
4315

{ 大规模循环在内 }
procedure TMainForm.Btn06Click(Sender: TObject);
var
i, j,>begin
T1 := GetTickCount;

c := 0;

for j := 0>Inc(c);
end;

T2 := GetTickCount;

Memo.Lines.Add(IntToStr(T2 - T1));
end;

Memo.Lines.Add('');
end;

10次测试结果(毫秒):

2427
2405
2410
2410
2410
2410
2405
2410
2410
2410

几乎快了一倍,差别如此之大,有点不相信自己的眼睛吧?原因就在于CPU跨切循环层是需要花费时间的。记住在多重循环中,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数,从而可以大幅度提高循环的效率。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值