C-04\IDE基础知识和分支,循环语句
一、浮点数特性及比较方法
浮点数在多参数传参的时候默认是会进行精度转换,由float转换到double,浮点数是一个近视值,不能进行直接等于比较,一般可以用区间法比较但是会存在精度丢失的问题。
浮点数区间比较法:
例:比较浮点数 f1 和 f2 可以写成 abs(f1-f2) < 0.0001(其中精度由自己控制)
浮点相关算法设计的时候因为浮点数精度丢失的问题会存在当进行N次计算或比较后实际误差远远大于预计精度的问题。因此在设计算法的时候尽量要着重注意
常见解决办法有浮点精度补偿法(涉及专业数学问题),无限接近法。
无限接近法:经典应用,浮点数开平方根。
float f1 = 3.14f, up = f1, n = 0.0f, fcur = 0.0001f;
n = up / 2.0;
while(abs((n*n)-f1) > fcur)
{
if((n*n)-f1 > fcur)
{
up = n;
n = up / 2.0;
}
else
{
up = up - n;
n = up / 2.0;
}
}
二、IDE环境常用快捷键使用(VC++6.0)
| 快捷键 | 作用 |
|---|---|
F7 |
编译和链接 |
Ctrl+F7 |
只编译不链接 |
Alt+0 |
工作空间(窗口) |
Alt+2 |
输出空间(窗口) |
F10 |
单步步过,在没有编译的情况下会先执行编译,每次执行一行 |
F11 |
单步步入 |
F5 |
调试运行(遇断点停) |
F9 |
设置/取消断点 |
Ctrl+F5 |
非调试运行(遇断点不停) |
Shift+F11 |
回到上层调用处 |
Alt+F8 |
显示反汇编窗口,不同的编译器可能会出现相同的机器码解释成不同的汇编指令,但结果一致 |
F7实际作法就是将每个.cpp编译生成.obj,然后将多个.obj联合链接成一个.exe可执行文件
三、IDE环境常用区域分布
一般常用的窗口有:
内存窗口:查看进程内存,支持直接拖拽变量和地址直接定位
堆栈窗口:显示当前代码调用关联,用来查看代码关联性
寄存器窗口:显示上次计算残留值,用来观察指令对寄存器的影响
监视窗口:显示被监视变量或表达式的结果,该窗口会对表达式求值。如果是单步执行则每次单步都会求值一次,所以在监视窗口不能放影响左值的表达式
四、分支语句的区别和应用场景
在C语言中分支语句有:
if //属于单分支语句 用于条件判断,例:if(a>b)
if else //属于双分支语句 用于条件选择判断,例:if(a>b){xx}else{oo}
if else if //属于多分支语句 用于分支选择判断,可预知输入集且指定分步规律(手动调整优先级,将输入集多的区间调整到最先判断)
switch case //属于多分支语句 用于分支选择判断
if else if能做区间比较,swithc case不能switch case能得到编译器更好的优化,适用于数据分布均等,没有优先级的情况- 以上的判断语句中条件判断部分永远是判断表达式最后一个值,例:
int i = 0 if(i=1)返回真
五、Switch case 语句的内存分布情况和编译器优化原理
在VC编译器中当switch case的case 数量大于3且各个case之间的差值不大于12(此值不固定,不同编译器可能不同)的时候编译器会启动优化,在内存中创建一个表用来顺序保存各case块的首地址,不存在该序号块的时候用default块地址填充,没有default的时候用swtich尾部地址填充。在访问的时候对case值做线性平衡(最小值不等于0的时候,正数减去最小值,负数加上最小值的正数),访问对应case的时候直接用查表的方式来取得case块的首地址跳过去
例:如果一个switch有case1,2,3,5,6,8时候,表从0下表开始:default,case1,case2,case3,default,case5,case6,default,case8
访问时的伪代码:
mov eax,case值
sub eax,1
mov ebx,[eax * 4 + 表首地址]
jmp ebx
六、循环语句的种类和特点
循环语句有: while, do...while, for
特点:
- while: 先判断后执行,可能循环体一次都不会执行。例:先给钱后吃饭
- do...while: 先执行后判断,循环体至少执行一次。例:先吃饭后给钱
- for: 是先初始化,再判断,再执行,执行完再处理
for 循环分:1初值部分,2终值部分,3循环体,4步长部分,5跳到第2步继续
七、goto模拟三种循环
do...while循环:
int n = 1;
int nSum = 0;
do
{
nSum = nSum + n;
n++;
}while(n <= 100);
DO_BEGIN:
nSum = nSum + n;
n++;
if(n <= 100)
{
goto DO_BEGIN;
}
while循环:
int n = 1;
int nSum = 0;
while(n <= 100)
{
nSum = nSum + n;
n++;
}
WHILE_BEGIN:
if(n > 100)
{
goto WHILE_END;
}
nSum = nSum + n;
n++;
goto WHILE_BEGIN;
WHILE_END:
for循环:
for循环三个部分都有的情况
// for循环三个部分都有的情况
for(int n = 1, int nSum = 0; n <= 100; n++)
{
nSum = nSum + n;
}
FOR_INIT:
int n = 1;
int nSum = 0;
goto FOR_CMP;
FOR_STEP:
n++;
FOR_CMP:
if(n > 100)
{
goto FOR_END;
}
nSum = nSum + n;
goto FOR_STEP;
FOR_END:
for循环没有初始化部分的情况
// for循环没有初始化部分的情况
int n = 1;
int nSum = 0;
for(; n <= 100; n++)
{
nSum = nSum + n;
}
FOR_INIT:
goto FOR_CMP;
FOR_STEP:
n++;
FOR_CMP:
if(n > 100)
{
goto FOR_END;
}
nSum = nSum + n;
goto FOR_STEP;
FOR_END:
for循环没有初始化与步长部分的情况
// for循环没有初始化与步长部分的情况,下面这种情况就和while循环一样
int n = 1;
int nSum = 0;
for(; n <= 100;)
{
nSum = nSum + n;
n++;
}
FOR_CMP:
if(n > 100)
{
goto FOR_END;
}
nSum = nSum + n;
n++;
goto FOR_CMP;
FOR_END:
for循环没有判断部分的情况
// for循环没有判断部分的情况
for(int n = 1, int nSum = 0;; n++)
{
if( n > 100)
{
break;
}
nSum = nSum + n;
}
FOR_INIT:
int n = 1;
int nSum = 0;
goto FOR_STRIUCT;
FOR_STEP:
n++;
FOR_STRIUCT: //此处是循环体内的判断
if(n > 100)
{
goto FOR_END;
}
nSum = nSum + n;
goto FOR_STEP;
FOR_END:
总结
-
由此可知
do...while效率最高,正常情况下for循环效率最低。开优化后编译器会将for,while循环转换为do...while循环,提高效率。 -
编译选项
/ZI或/Zi与/O2不能同时有,两个是冲突选项(经过实验,手动编译同时有这两个编译选项,也能编译通过,但是还不知道采用的是那个编译选项) -
汇编语言是流水线模式,也就是循环体的内容是紧接着循环体上面的内容的,而汇编只有满足条件跳转的语义,所以
while,for的判断条件与汇编层面是相反的。例:while(a>b){xx},则在汇编中判断就为if(a <= b) goto WHILE_END {xx}
八、附加知识
- 三角形任意两边之和大于第三边
- C语言符合
ASNI标准,代码具有可移植性,非exe文件 - 内存中包含了程序的数据部分代码部分(机器码相关数据)
- 编写代码时最好把制表符(Tab键)的制表符号替换成空格(4个),这样方便跨环境看源码。如果直接使用Tab键,因为不同的编辑器对
Tab键的解释是不一样的,从而导致从一个编辑器复制到另一个编辑器发生 布局混乱 - if()后面只有一条语句也用括号括起来,防止语句使用宏,不利于调试
- 一行只写一条语句,利于调试且好看
浙公网安备 33010602011771号