- ADT和黑盒
C语言可以用于设计和实现抽象数据类型(ADT,abstract data type),因为它可以限制函数和数据定义的作用域。这个技巧也被称为黑盒(black box)设计。抽象数据类型的基本想法是很简单的——模块具有功能说明和接口说明,前者说明模块设计所执行的任务,后者定义模块的使用。但是,模块的用户并不需要知道模块实现的任何细节,而且除了那些定义好的接口之外,用户不能以任何方式访问模块。限制对模块的访问是通过static关键字的合理使用实现的,它可以限制对那些并非接口的函数和数据的访问。例如:
//地址列表模块的声明
//数据特征
//各种数据的最大长度(包括结尾的NUL字节)和地址的最大数量
#define NAME_LENGTH 30 //允许出现的最长名字
#define ADDR_LENGTH 100 //允许出现的最长地址
#define PHONE_LENGTH 11 //允许出现的最长电话号码
#define MAX_ADDRESSES 1000 //允许出现的最多地址个数
//接口函数
//给出一个名字,查找对应的地址
char const*
lookup_address(char const* name);
//给出一个名字,查找对应的电话号码
char const*
lookup_phone(char const* name);
//addrlist.h
//地址列表模块 头文件
//用于维护一个地址列表的抽象数据类型
#include "aderliti.h"
#include <stdio.h>
//每个地址的三个部分,分别保存于三个数组的对应元素中
static char name[MAX_ADDRESSES][NAME_LENGTH];
static char address[MAX_ADDRESSES][ADDR_LENGTH];
static char phone[MAX_ADDRESSES][PHONE_LENGTH];
//这个函数在数组中查找一个名字并返回查找到的位置下标
//如果这个名字在数组中并不存在,函数返回-1
static int
find_entry(char const *name_to_find)
{
int entry;
for(entry=0;entry<MAX_ADDRESSES;entry+=1)
if(strcmp(name_to_find,name[entry])==0)
return entry;
return -1;
}
//在这个例子里,接口是函数lookup_address和lookup_phone,但是用户不能直接访问和模块实现有关的数据,如数组或辅助函数find_entry,因为这些内容被声明为static。
- 递归
C语言通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。
#include <stdio.h>
void binary_to_ascii(unsigned int value)
{
unsigned int quotient;
quotient=value/10;
if (quotient != 0)
{
binary_to_ascii(quotient);
}
putchar(value%10+'0');
}
//1.将参数值除以10
//2.如果quotient的值为非零,调用binary_to_ascii打印quotient当前值的各位数字。
//3.接着,打印步骤1中除法运算的余数。
一旦理解了递归,阅读递归函数最容易的方法不是纠缠于它的执行工程,而是相信递归函数会顺利完成它的任务。如果每个步骤正确无误,限制条件设置正确,并且每次调用之后更接近限制条件,那么递归函数总是能够正确地完成任务。