注:本篇博客的内容和列子都来源于书籍《c和指针》,是lc整理成篇的,推荐大家读读这本书。
所谓抽象数据类型,是指模块具有功能说明和接口说明,前者说明模块所执行的任务,后者定义模块的使用。但是,模块的用户并不需要知道模块实现的任何细节,而且除了那些定义好的接口之外,用户不能以任何方式访问模块,这个定义觉得是不是和面向对象语言的类的定义类似呢,c没提供类这种结构,c实现抽象数据类型的武器其实是static关键字。
c语言有三种链接属性,即external(外部),internal(内部)和none(无)。没有链接属性的标识符(none)总是被当作单独的实体,也就是说该标识符的多个声明被当作独立不同的实体。属于Internal链接属性的标志符在同一个源文件内的所有声明中都指同一个实体,但位于不同源文件的多个声明则分属不同的实体,最后,属性external链接属性的标识符不论声明多少次,位于几个源文件都表示同一个实体。
关键字static和extern用于在声明中修改标识符的链接属性,如果某个声明在正常情况下具有external链接属性,在它前面加上static关键字可以使它的链接属性变为internal。
一般而言,函数参数,函数局部变量(没有extern属性修饰)的变量都具有none的链接属性;全局变量,函数声明,函数定义如果没有static修饰,则具有external链接属性,如果有static属性修饰,则具有Internal链接属性。
注意:1 static只对缺省链接属性为extern的声明才有改变链接属性的效果,如下列f。
2 为一个变量指定extern属性,就可以访问在任何位置定义的这个实体,如下列k。
3 当extern关键字用于源文件中一个标识符的第1次声明时,它指定该标识符具有extern属性,如下列b。
int a;
static int b;
int c(int d)
{
int e;
static int f;//f为none连接属性
extern int k;//k本来是none链接属性,现在指定了extern属性,就有extern链接属性
extern int b;//b第二次声明为extern,不修改b的链接属性,b仍为intern链接属性
}
static关键字的作用介绍清楚了,下面写一个demo,看看怎么实现抽象数据类型,怎么实现信息隐藏,头文件addrlist.h里面声明了接口lookup_address,lookup_phone,外面可以调用,但addrlist.c文件里面的find_entry函数,外面是不能调用的,因为该函数具有static属性,即不是external链接属性。
/*
** Declarations for the address list module.
*/
/*
** Data characteristics
**
** Maximum lengths of the various data (includes space for the
** terminating NUL byte), and maximum number of addresses.
*/
#define NAME_LENGTH 30 /* longest name allowed */
#define ADDR_LENGTH 100 /* longest address allowed */
#define PHONE_LENGTH 11 /* longest phone # allowed */
#define MAX_ADDRESSES 1000 /* # of addresses allowed */
/*
** Interface functions
**
** Given a name, find the corresponding address.
*/
char const *
lookup_address( char const *name );
/*
** Given a name, find the corresponding phone number.
*/
char const *
lookup_phone( char const *name );
/*
** Abstract data type to maintain an address list.
*/
#include "addrlist.h"
#include <stdio.h>
/*
** The three parts to each address are kept in corresponding
** elements of these three arrays.
*/
static char name[MAX_ADDRESSES][NAME_LENGTH];
static char address[MAX_ADDRESSES][ADDR_LENGTH];
static char phone[MAX_ADDRESSES][PHONE_LENGTH];
/*
** This routine locates a name in the array and returns the
** subscript of the location found. If the name does not exist,
** -1 is returned.
*/
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;
}
/*
** Given a name, look up and return the corresponding address.
** If the name was not found, return a NULL pointer instead.
*/
char const *
lookup_address( char const *name )
{
int entry;
entry = find_entry( name );
if( entry == -1 )
return NULL;
else
return address[ entry ];
}
/*
** Given a name, look up and return the corresponding phone
** number. If the name was not found, return a NULL pointer
** instead.
*/
char const *
lookup_phone( char const *name )
{
int entry;
entry = find_entry( name );
if( entry == -1 )
return NULL;
else
return phone[ entry ];
}