身为一名程序员,或多或少都会了解一点 C 语言,我如今还清楚地记得,大一刚接触 C 语言时被它所支配的恐惧。C 语言无比强大,被称为「高级汇编语言」足以见得它的威力,也能够看出它常常与计算机底层打交道;它的指针部分更为精彩(也是最难的部分),那么咱们就跳过它最难的部分,检查一下你对 C 语言掌握的程度。程序员
下面是一个函数 sum_elements( ),它的做用是对给定的数组中全部元素求和并返回其值,按照代码中给定的值去执行,你认为会获得什么结果呢?数组
1#include<stdio.h>
2
3// 一个有 bug 的函数
4float sum_elements(float a[], unsigned length) {
5 int i;
6 float result;
7
8 result = 0;
9 for (i = 0; i <= length - 1; i++)
10 result += a[i];
11
12 return result;
13}
14
15void main()
16{
17 float a[1] = { 0.1 };
18 float sum;
19
20 sum = sum_elements(a, 0);
21 printf("%f\n", sum);
22}
复制代码
当咱们让 length = 0 时,想要获得的结果是 0.000000,可是运行时你会发现该程序会报出内存访问异常错误。你知道是什么缘由出现这个错误吗?这就是检验你功底是否扎实的时候了,先仔细看看代码,好好想想再继续往下看。app
... ...函数
怎么样,知道是什么缘由致使这段代码出现了咱们预料以外的错误了吗?这里的 bug 是无符号整数(unsigned)致使的。ui
在 C 语言中,无符号整数是 4 个字节,1 个字节为 8 位,十进制数 0 用二进制表示为 0000 0000 0000 0000 0000 0000 0000 0000,计算机作减法是经过补码进行,补码为源码除符号位外各位取反再加一。-1 的补码为 1111 1111 1111 1111 1111 1111 1111 1111,计算 length - 1 (0 - 1) 就是求 length 与 -1 的补码之和,获得的结果为 1111 1111 1111 1111 1111 1111 1111 1111,由于以前定义形参的时候将 length 定义为无符号整数,因此 C 语言将计算结果按照无符号整数解释,获得的十进制数字为 4294967295(2^32 - 1)而不是咱们想要的 -1,循环时 i 初值被赋为 0 ,一直小于这个数,因此循环会不断地进行,代码将试图访问数组 a 的非法元素,致使内存访问异常。spa
这个程序表面上一切正常,很符合正常人思路,数组下标不能为负数,所以形参 length 用无符号整数表示;中止条件 i <= length - 1 看上去也十分天然。可是将这两个条件组合在一块儿,意料以外的事情就发生了。C 语言确实很强大,可是若是咱们的计算机基础知识不扎实,极可能出现各类奇奇怪怪的 bug。原来我一直以为学那些枯燥无味的计算机基础知识没用,可是越往前走愈加觉计算机基础知识很重要。书到用时方恨少,出了 bug 找不到。指针
如今这个 bug 的缘由已经找到了,如何修改这个 bug 使得该程序可以顺利执行呢?一种方法是修改循环条件,改为 i < length ;另外一种方法是将形参 length 定义为 int 类型。code