最近, 探究了 "C" 中一些常被忽略, 或者说不被强调的问题, 虽然对编程可能没有多大的影响, 但探究一下, 知道其中的缘由总还是有助于理解 "C" 语言的, 探究结果如下:
问题一: 预防野指针的方法???
答:
(一)野指针 (并非 NULL 指针) 意思是未初始化的指针看似没指向任何地方, 但是其实默认了是指向某个未知地点的, 这个地点可能是系统的某个重要的代码, 所以一旦对这个无知指针的某个行为改动了它所指向的系统代码, 那系统就会出现问题, 为避免使用无效地址访问内存, 一般在申请指针变量时, 将指针变量赋 0 值, 在以后的程序设计中, 要使用这个指针前, 先判断是否是 0 值, 如果是, 则报错, 如果使用某指针完毕, 确保其他部分程序误使用指针时, 也可以将这个使用完的指针再次赋 0 值(NULL), 任何使用与内存操作相关的函数必须指定长度信息.
比如:
- int p=NULL;
- ...
- if ( p==NULL ) printf("指针异常 \ n");
(二)野指针由来: 局部指针变量没有初始化; 指针所指向的变量在指针之前被销毁; 使用已经释放过的指针; 进行了错误指针运算; 进行了错误的强制类型转换.
问题二: getchar()的返回值为什么是 int???
答:
C 语言中有个重要的库函数 getchar(), 可从终端获得一个字符的 ASCII 码值. 在终端输入字符时并非输入一个字符就会返回, 而是在遇到回车换行前, 所有输入的字符都会缓冲在键盘缓冲器中, 直到回车换行一次性将所有字符按序依次赋给相应的变量, 在这里一定要注意最后一个字符即'\n', 该字符也会赋给一个相应的变量.
从字面上看, 给函数返回的类型应该是 char 型, 但在示例中, 却将返回内容赋值给了 int 型变量, 示例代码如下:
(getchar()除了返回正常的字符外, 还会返回输入结束符 EOF(end of file))
- #include <stdio.h>
- / 将输入复制到输出 /
- int main(void)
- {
- int c; / 这里如果用 char c 在一些环境下会死循环出错 /
- while ((c = getchar()) != EOF){
- putchar(c);
- }
在 Andrew Koenig 的著作《C 陷阱与缺陷》中是这样解释的:
"getchar 函数在一般情况下返回的是标准输入文件中的下一个字符, 当没有输入时返回 EOF(一个在头文件 stdio.h 中被定义的值, 不同于任何一个字符)."
由于 EOF 不同于任何一个字符, 如果程序中的 getchar 如果返回的是 char 类型, 而不是 int 类型, 就意味着返回值无法容下所有可能的字符, 特别是, 可能无法容下 EOF. 另外, Koenig 还指出, 如果将 getchar 的返回值赋值后还要参与判断, 那么也应该使用 int 型的变量.
问题三: 递归实现二分查找???
答:(一)什么是递归? 程序调用自身的编程技巧称为递归 ( recursion). 递归做为一种算法在程序设计语言中广泛应用. 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法, 它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解, 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算, 大大地减少了程序的代码量. 递归的能力在于用有限的语句来定义对象的无限集合. 一般来说, 递归需要有边界条件, 递归前进段和递归返回段. 当边界条件不满足时, 递归前进; 当边界条件满足时, 递归返回.(二) 递归实现二分查找, 代码如下:
- // 递归实现二分查找(建立在有序数列的基础上)
- int bin_search(int arr[], int left, int right, int x){
- int mid = 0 ;
- while (left <= right){
- mid = left + (right - left) / 2;
- if (arr[mid]> x){
- return bin_search(arr, left, mid-1, x);
- }
- else if (arr[mid] < x){
- return bin_search(arr, mid+1, right, x);
- }
- else{
- return mid;
- }
- }
- return -1;
- }
问题四: typedef define const 三者的区别???
答:
一,#define
- #define 并不是定义全局变量, 而是宏定义. 也就是说并不是真正意义上的定义变量, 而是用来做文本替换,#define 不只是可以为类型取别名, 还可以定义常量, 变量, 编译开关等.
- #define 没有作用域的限制, 只要是之前预定义过的宏, 在以后的程序中都可以使用, 而 typedef 有自己的作用域.
例如:#define MAX 100
当程序开始运行时, 编译器会先将代码中的 MAX 全部替换为 100, 然后再进行编译. 由此可得,#define 并不是在编译过程中进行, 而是在预编译阶段进行.
二, const
关键字 const 用来定义常量, 如果一个常量被 const 修饰, 那么他的值就不能被改变. 与 #define 相比, const 有以下优点:
1. 预编译指令只是对值进行简单的替换, 不能进行类型检查.
2. 可以保护被修饰的东西, 防止意外修改.
3. 编译器通常不为普通 const 常量分配存储空间, 而是保存于符号表中, 这使得它成为一个编译期间的常量, 没有存储与读内存的操作, 使得它的效率更高.
三, typedef
typedef 作用是为一种数据类型定义一个新名字, 数据类型包括内部数据类型 (int,char 等) 和自定义的数据类型(struct 等). 由此可见, typedef 不只是简单的宏替换, 而且可以用作同时声明指针型的多个对象. 它在自己的作用域内给一个已经存在的类型一个别名, 但不能在一个函数定义里面使用 typedef.
typedef 另一个功能是定义机器无关的类型. 如定义一个 REAL 的浮点类型, 在目标机器上它可以获得最高的精度: typedef long double REAL, 在不支持 long double 的机器上, 看起来是这样的, typedef double REAL, 在不支持 double 的机器上, 是这样的, typedef float REAL.
来源: http://www.bubuko.com/infodetail-3004577.html