加入收藏 | 设为首页 | 会员中心 | 我要投稿 孝感站长网 (https://www.0712zz.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 编程要点 > 语言 > 正文

C 语言编程中的五个常见错误及对应解决计划

发布时间:2021-10-19 12:38:14 所属栏目:语言 来源:互联网
导读:即使是最好的程序员也无法完全避免错误。这些错误可能会引入安全漏洞、导致程序崩溃或产生意外操作,具体影响要取决于程序的运行逻辑。 C 语言有时名声不太好,因为它不像近期的编程语言(比如 Rust)那样具有内存安全性。但是通过额外的代码,一些最常见和严
即使是最好的程序员也无法完全避免错误。这些错误可能会引入安全漏洞、导致程序崩溃或产生意外操作,具体影响要取决于程序的运行逻辑。
 
C 语言有时名声不太好,因为它不像近期的编程语言(比如 Rust)那样具有内存安全性。但是通过额外的代码,一些最常见和严重的 C 语言错误是可以避免的。下文讲解了可能影响应用程序的五个错误以及避免它们的方法:
 
1. 未初始化的变量
程序启动时,系统会为其分配一块内存以供存储数据。这意味着程序启动时,变量将获得内存中的一个随机值。
 
有些编程环境会在程序启动时特意将内存“清零”,因此每个变量都得以有初始的零值。程序中的变量都以零值作为初始值,听上去是很不错的。但是在 C 编程规范中,系统并不会初始化变量。
 
看一下这个使用了若干变量和两个数组的示例程序:
 
#include <stdio.h> 
#include <stdlib.h> 
int 
main() 
  int i, j, k; 
  int numbers[5]; 
  int *array; 
  puts("These variables are not initialized:"); 
  printf("  i = %dn", i); 
  printf("  j = %dn", j); 
  printf("  k = %dn", k); 
  puts("This array is not initialized:"); 
  for (i = 0; i < 5; i++) { 
    printf("  numbers[%d] = %dn", i, numbers[i]); 
  } 
  puts("malloc an array ..."); 
  array = malloc(sizeof(int) * 5); 
  if (array) { 
    puts("This malloc'ed array is not initialized:"); 
    for (i = 0; i < 5; i++) { 
      printf("  array[%d] = %dn", i, array[i]); 
    } 
    free(array); 
  } 
  /* done */ 
  puts("Ok"); 
  return 0; 
这个程序不会初始化变量,所以变量以系统内存中的随机值作为初始值。在我的 Linux 系统上编译和运行这个程序,会看到一些变量恰巧有“零”值,但其他变量并没有:
 
These variables are not initialized: 
  i = 0 
  j = 0 
  k = 32766 
This array is not initialized: 
  numbers[0] = 0 
  numbers[1] = 0 
  numbers[2] = 4199024 
  numbers[3] = 0 
  numbers[4] = 0 
malloc an array ... 
This malloc'ed array is not initialized: 
  array[0] = 0 
  array[1] = 0 
  array[2] = 0 
  array[3] = 0 
  array[4] = 0 
Ok 
很幸运,i 和 j 变量是从零值开始的,但 k 的起始值为 32766。在 numbers 数组中,大多数元素也恰好从零值开始,只有第三个元素的初始值为 4199024。
 
在不同的系统上编译相同的程序,可以进一步显示未初始化变量的危险性。不要误以为“全世界都在运行 Linux”,你的程序很可能某天在其他平台上运行。例如,下面是在 FreeDOS 上运行相同程序的结果:
 
These variables are not initialized: 
  i = 0 
  j = 1074 
  k = 3120 
This array is not initialized: 
  numbers[0] = 3106 
  numbers[1] = 1224 
  numbers[2] = 784 
  numbers[3] = 2926 
  numbers[4] = 1224 
malloc an array ... 
This malloc'ed array is not initialized: 
  array[0] = 3136 
  array[1] = 3136 
  array[2] = 14499 
  array[3] = -5886 
  array[4] = 219 
Ok 
永远都要记得初始化程序的变量。如果你想让变量将以零值作为初始值,请额外添加代码将零分配给该变量。预先编好这些额外的代码,这会有助于减少日后让人头疼的调试过程。
 
2. 数组越界
C 语言中,数组索引从零开始。这意味着对于长度为 10 的数组,索引是从 0 到 9;长度为 1000 的数组,索引则是从 0 到 999。
 
程序员有时会忘记这一点,他们从索引 1 开始引用数组,产生了“大小差一”off by one错误。在长度为 5 的数组中,程序员在索引“5”处使用的值,实际上并不是数组的第 5 个元素。相反,它是内存中的一些其他值,根本与此数组无关。
 
这是一个数组越界的示例程序。该程序使用了一个只含有 5 个元素的数组,但却引用了该范围之外的数组元素:
 
#include <stdio.h> 
#include <stdlib.h> 
int 
main() 
  int i; 
  int numbers[5]; 
  int *array; 
  /* test 1 */ 
  puts("This array has five elements (0 to 4)"); 
  /* initalize the array */ 
  for (i = 0; i < 5; i++) { 
    numbers[i] = i; 
  } 
  /* oops, this goes beyond the array bounds: */ 
  for (i = 0; i < 10; i++) { 
    printf("  numbers[%d] = %dn", i, numbers[i]); 
  } 
  /* test 2 */ 
  puts("malloc an array ..."); 
  array = malloc(sizeof(int) * 5); 
  if (array) { 
    puts("This malloc'ed array also has five elements (0 to 4)"); 
    /* initalize the array */ 
    for (i = 0; i < 5; i++) { 
      array[i] = i; 
    } 
    /* oops, this goes beyond the array bounds: */ 
    for (i = 0; i < 10; i++) { 
      printf("  array[%d] = %dn", i, array[i]); 
    } 
    free(array); 
  } 
  /* done */ 
  puts("Ok"); 
  return 0; 
可以看到,程序初始化了数组的所有值(从索引 0 到 4),然后从索引 0 开始读取,结尾是索引 9 而不是索引 4。前五个值是正确的,再后面的值会让你不知所以:
 
This array has five elements (0 to 4) 
  numbers[0] = 0 
  numbers[1] = 1 
  numbers[2] = 2 
  numbers[3] = 3 
  numbers[4] = 4 
  numbers[5] = 0 
  numbers[6] = 4198512 
  numbers[7] = 0 
  numbers[8] = 1326609712 
  numbers[9] = 32764 
malloc an array ... 
This malloc'ed array also has five elements (0 to 4) 
  array[0] = 0 
  array[1] = 1 
  array[2] = 2 
  array[3] = 3 
  array[4] = 4 
  array[5] = 0 
  array[6] = 133441 
  array[7] = 0 
  array[8] = 0 
  array[9] = 0 
Ok 
引用数组时,始终要记得追踪数组大小。将数组大小存储在变量中;不要对数组大小进行硬编码hard-code。否则,如果后期该标识符指向另一个不同大小的数组,却忘记更改硬编码的数组长度时,程序就可能会发生数组越界。

(编辑:孝感站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读