Twistronics Blog

线程安全的抽象链表类库

March 25, 2014

所谓线程安全的是指,所编写的程序在多线程执行时,不会导致程序错误。为此,抽象链表库的代码必须仔细考虑多个线程同时访问时的同步问题。其基本原则是:(1)抽象链表库允许多个线程同时读取,但不允许同时写入;(2)抽象链表库的部分代码段必须是原子的,也就是说,这些代码段中的代码要么全部执行,要么全部不执行,不允许在执行其中代码的过程中被中断。

读写锁有三种状态,一次只能有一个线程可以占有写模式的读写锁,但是可以有多个线 程同时占有读模式的读写锁。当读写锁处于写加锁状态时,在这个锁被解锁之前,所有试图 对这个锁加锁的线程都会被阻塞。当读写锁处于读加锁状态时,所有试图以读模式对它进行 加锁的线程都可以得到访问权,但是如果线程希望以写模式对此锁进行加锁,它必须阻塞知 道所有的线程释放锁.

通常,当读写锁处于读模式锁住状态时,如果有另外线程试图以写模式加锁,读写锁通 常会阻塞随后的读模式锁请求,这样可以避免读模式锁长期占用,而等待的写模式锁请求长 期阻塞。

读写锁适用于对数据结构的读次数比写次数多得多的情况。因为,读模式锁定时可以共 享,以写模式锁住时意味着独占,所以读写锁又叫共享-独占锁。 读写锁的初始化和销毁函数如下:

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const
pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

上述函数成功则返回 0,出错则返回错误编号。同互斥量一样,在释放读写锁占用的内 存前,需要先通过 pthreadrwlockdestroy 对读写锁进行清理工作,释放由 init 分配的资源。 加锁函数如下:

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

上述函数成功则返回 0,出错则返回错误编号。上述三个函数分别实现获取读锁,获取 写锁和释放锁的操作。获取锁的两个函数是阻塞操作。其非阻塞的版本为:

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

上述函数成功则返回 0,出错则返回错误编号。非阻塞的获取锁操作,如果可以获取则返回 0,否则返回错误 EBUSY。

makefile

objects = main.cpp list.cpp point.cpp zylib.cpp zyrandom.cpp
a.out : $(objects) list.h point.h zylib.h zyrandom.h
	g++ -o a.out -lpthread $(objects)

main.cpp

#include <stdio.h>

#ifndef __POINT__
#include "point.h"
#endif

#ifndef __LIST__
#include "list.h"
#endif

#include "zyrandom.h"

int DoCompareObject( CADT e1, CADT e2 );
void DoDestroyObject( ADT e );
void DoPrintObject( ADT e, ADT tag );

int main()
{
    POINT pt;
    int i;
    LINKED_LIST list = LlCreate();
    Randomize();
    for( i = 0; i < 8; ++i )
    {
        pt = PtCreate( GenerateRandomNumber(10, 99), GenerateRandomNumber(10, 99) );
        LlInsert( list, pt, 0 );
    }
    pt = PtCreate( 6, 6 );
    LlInsert( list, pt, 1 );
    LlTraverse( list, DoPrintObject,(void*) "(%d,%d)" );
    printf( "NULL\n" );

    if( LlSearch( list, pt, DoCompareObject ) )
        printf( "Yes, %s exists.\n", PtTransformIntoString("(%d,%d)", pt) );
    else
        printf( "No, %s doesn't exist.\n", PtTransformIntoString("(%d,%d)", pt) );

    LlDelete( list, 1, DoDestroyObject );
    LlTraverse( list, DoPrintObject,(void*) "(%d,%d)" );
    printf( "NULL\n" );

    pt = PtCreate( 6, 6 );
    if( LlSearch( list, pt, DoCompareObject ) )
        printf( "Yes, %s exists.\n", PtTransformIntoString("(%d,%d)", pt) );
    else
        printf( "No, %s doesn't exist.\n", PtTransformIntoString("(%d,%d)", pt) );

    LlClear( list, DoDestroyObject );
    LlTraverse( list, DoPrintObject,(void*) "(%d,%d)" );
    printf( "NULL\n" );

    LlDestroy( list, DoDestroyObject );
    return 0;
}

int DoCompareObject( CADT e1, CADT e2 )
{
    return PtCompare( (POINT)e1, (POINT)e2 );
}

void DoDestroyObject( ADT e )
{
    DestroyObject( e );
}

void DoPrintObject( ADT e, ADT tag )
{
    printf( PtTransformIntoString( (CSTRING)tag, (POINT)e ) );
    printf( " -> " );
}

list.h

#ifndef __LIST__
#define __LIST__

#ifndef __ZYLIB__
#include "zylib.h"
#endif

typedef struct __LINKED_LIST * LINKED_LIST;

typedef int ( * COMPARE_OBJECT )( CADT e1, CADT e2 );
typedef void ( * DESTROY_OBJECT )( ADT e );
typedef void ( * MANIPULATE_OBJECT )( ADT e, ADT tag );

LINKED_LIST LlCreate();
void LlDestroy( LINKED_LIST list, DESTROY_OBJECT destroy );
void LlClear( LINKED_LIST list, DESTROY_OBJECT destroy );
void LlAppend( LINKED_LIST list, ADT object );
void LlInsert( LINKED_LIST list, ADT object, unsigned int pos );
void LlDelete( LINKED_LIST list, unsigned int pos, DESTROY_OBJECT destroy );
void LlTraverse( LINKED_LIST list, MANIPULATE_OBJECT manipulate, ADT tag );
BOOL LlSearch( LINKED_LIST list, ADT object, COMPARE_OBJECT compare );
unsigned int LlGetCount( LINKED_LIST list );
BOOL LlIsEmpty( LINKED_LIST list );

#endif

list.cpp

#include <stdio.h>

#ifndef __ZYLIB__
#include "zylib.h"
#endif

#ifndef __LIST__
#include "list.h"
#endif

typedef struct __NODE * NODE;
struct __LINKED_LIST{ unsigned int count; NODE head, tail; pthread_rwlock_t rwlock; };
struct __NODE{ ADT data; NODE next; };

LINKED_LIST LlCreate()
{
    LINKED_LIST p = NewObject( struct __LINKED_LIST );
    p->count = 0;
    p->head = NULL;
    p->tail = NULL;
    pthread_rwlock_init( &p->rwlock, NULL );
    return p;
}

void LlDestroy( LINKED_LIST list, DESTROY_OBJECT destroy )
{
    if( list ){LlClear( list, destroy ); pthread_rwlock_destroy(&list->rwlock); DestroyObject( list );  }
}

void LlClear( LINKED_LIST list, DESTROY_OBJECT destroy )
{
    if( !list )  PrintErrorMessage( FALSE, "LlClear: Parameter illegal." );

    pthread_rwlock_wrlock( &list->rwlock );

    while( list->head )
    {
        NODE t = list->head;
        list->head = t->next;
        if( destroy )  ( *destroy )( t->data );
        DestroyObject( t );
        list->count--;
    }
    list->tail = NULL;

    pthread_rwlock_unlock( &list->rwlock );
}

void LlAppend( LINKED_LIST list, ADT object )
{
    NODE t = NewObject( struct __NODE );
    if( !list || !object )  PrintErrorMessage( FALSE, "LlAppend: Parameter illegal." );

    t->data = object;
    t->next = NULL;

    pthread_rwlock_wrlock( &list->rwlock );

    if( !list->head )  // singly linked list with no elements
    {
        list->head = t;
        list->tail = t;
    }
    else
    {
        list->tail->next = t;
        list->tail = t;
    }
    list->count++;

    pthread_rwlock_unlock( &list->rwlock );
}

void LlInsert( LINKED_LIST list, ADT object, unsigned int pos )
{
    if( !list || !object )  PrintErrorMessage( FALSE, "LlInsert: Parameter illegal." );

    pthread_rwlock_wrlock( &list->rwlock );

    if( pos < list->count ){
        NODE t = NewObject( struct __NODE );
        t->data = object;
        t->next = NULL;
        if( pos == 0 ){
            t->next = list->head;
            list->head = t;
        }
        else{
            unsigned int i;
            NODE u = list->head;
            for( i = 0; i < pos - 1; ++i )  u = u->next;
            t->next = u->next;
            u->next = t;
        }
        list->count++;

    }
    else {
        NODE t = NewObject( struct __NODE );
        if( !list || !object )  PrintErrorMessage( FALSE, "LlAppend: Parameter illegal." );
        t->data = object;
        t->next = NULL;
        if( !list->head )  // singly linked list with no elements
        {
            list->head = t;
            list->tail = t;
        }
        else
        {
            list->tail->next = t;
            list->tail = t;
        }
        list->count++;
    }

    pthread_rwlock_unlock( &list->rwlock );
}

void LlDelete( LINKED_LIST list, unsigned int pos, DESTROY_OBJECT destroy )
{

    if( !list )  PrintErrorMessage( FALSE, "LlDelete: Parameter illegal." );

    pthread_rwlock_wrlock( &list->rwlock );

    if( list->count == 0 ) { pthread_rwlock_unlock( &list->rwlock ); return; }
    if( pos == 0 ){
        NODE t = list->head;
        list->head = t->next;
        if( !t->next )  list->tail = NULL;
        if( destroy )  ( *destroy )( t->data );
        DestroyObject( t );
        list->count--;
    }
    else if( pos < list->count ){
        unsigned int i;
        NODE u = list->head, t;
        for( i = 0; i < pos - 1; ++i )  u = u->next;
        t = u->next;
        u->next = t->next;
        if( !t->next )  list->tail = u;
        if( destroy )  ( *destroy )( t->data );
        DestroyObject( t );
        list->count--;
    }

    pthread_rwlock_unlock( &list->rwlock );
}

void LlTraverse( LINKED_LIST list, MANIPULATE_OBJECT manipulate, ADT tag )
{
    pthread_rwlock_rdlock( &list->rwlock );

    NODE t = list->head;
    if( !list )  PrintErrorMessage( FALSE, "LlTraverse: Parameter illegal." );
    while( t ){
        if( manipulate )  ( *manipulate )(t->data, tag );
        t = t->next;
    }

    pthread_rwlock_unlock( &list->rwlock );
}

BOOL LlSearch( LINKED_LIST list, ADT object, COMPARE_OBJECT compare )
{
    pthread_rwlock_rdlock( &list->rwlock );

    NODE t = list->head;
    if( !list || !object || !compare )  PrintErrorMessage( FALSE, "LlSearch: Parameter illegal." );
    while( t ){
        if( ( *compare )( t->data, object ) ) {

            pthread_rwlock_unlock( &list->rwlock );

            return TRUE;
        }
        t = t->next;
    }

    pthread_rwlock_unlock( &list->rwlock );
    return FALSE;
}

unsigned int LlGetCount( LINKED_LIST list )
{
    if( !list )  PrintErrorMessage( FALSE, "LlGetCount: Parameter illegal." );

    pthread_rwlock_rdlock( &list->rwlock );
    unsigned int temp_count = list->count;
    pthread_rwlock_unlock( &list->rwlock );
    return temp_count;
}

BOOL LlIsEmpty( LINKED_LIST list )
{
    if( !list )  PrintErrorMessage( FALSE, "LlIsEmpty: Parameter illegal." );

    pthread_rwlock_rdlock( &list->rwlock );
    bool temp = list->count == 0;
    pthread_rwlock_unlock( &list->rwlock );
    return temp;
}

point.h

#ifndef __POINT__
#define __POINT__

#ifndef __ZYLIB__
#include "zylib.h"
#endif

typedef struct __POINT * POINT;

POINT PtCreate( int x, int y );
void PtDestroy( POINT point );
void PtGetValue( POINT point, int * x, int * y );
void PtSetValue( POINT point, int x, int y );
BOOL PtCompare( POINT point1, POINT point2 );
STRING PtTransformIntoString( CSTRING format, POINT point );
void PtPrint( POINT point );

#endif

point.cpp

#include <stdio.h>

#ifndef __POINT__
#include "point.h"
#endif

#ifndef __ZYLIB__
#include "zylib.h"
#endif

struct __POINT{ int x, y; };

POINT PtCreate( int x, int y )
{
    POINT t = NewObject( struct __POINT );
    t->x = x;
    t->y = y;
    return t;
}

void PtDestroy( POINT point )
{
    if( point ){  DestroyObject( point );  }
}

void PtGetValue( POINT point, int * x, int * y )
{
    if( point ){  if( x )  *x = point->x;  if( y )  *y = point->y;  }
}

void PtSetValue( POINT point, int x, int y )
{
    if( point ){  point->x = x;  point->y = y;  }
}

BOOL PtCompare( POINT point1, POINT point2 )
{
    if( !point1 || !point2 )  PrintErrorMessage( FALSE, "PtCompare: Parameter(s) illegal." );
    return ( point1->x == point2->x ) && ( point1->y == point2->y );
}

STRING PtTransformIntoString( CSTRING format, POINT point )
{
    char buf[BUFSIZ];
    if( point ){
        sprintf( buf, format, point->x, point->y );
        return DuplicateString( buf );
    }
    else  return (char*) "NULL";
}

void PtPrint( POINT point )
{
    if( point )
        printf( "(%d,%d)", point->x, point->y );
    else
        printf( "NULL" );
}

zylib.h

#ifndef __ZYLIB__
#define __ZYLIB__

#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <pthread.h>


/*****************************************************************************/
/*  基本数据类型定义  */
/*****************************************************************************/
typedef bool BOOL;
#define TRUE true
#define FALSE false
/*  布尔类型  */

/*  抽象字符串类型  */
typedef char* STRING;
typedef const char* CSTRING;

/*  抽象数据类型  */
typedef void* ADT;
typedef const void * CADT;


/*****************************************************************************/
/*  宏与常量定义  */
/*****************************************************************************/

/*  无定义对象  */
extern const ADT undefined_object;

/*  索引下标不存在常量  */
extern const unsigned int inexistent_index;



/*****************************************************************************/
/*  时间处理  */
/*****************************************************************************/

/*  函数:STRING TimeToString(const struct tm* t)  */
/*  将时间数据转换为字符串。*/
/*  字符串的格式为:YYYY-MM-DD HH:MM:SS。*/
/*  使用方法:time_t t0; struct tm* t1; STRING s; t0 = time(NULL); t1 = localtime(&t0); s = TimeToString(t1);  */
STRING TimeToString(const struct tm* t);

/*  函数:STRING CurrentTimeToString()  */
/*  将当前时间转换为字符串。*/
/*  字符串的格式为:YYYY-MM-DD HH:MM:SS。*/
STRING CurrentTimeToString();



/*****************************************************************************/
/*  错误处理  */
/*****************************************************************************/

/*  函数:void PrintErrorMessage(CSTRING fmt, ...)  */
/*  错误处理。*/
/*  向标准错误流中输出错误信息,使用方式类似标准库函数printf()。*/
/*  on:TRUE表示程序继续运行,FALSE表示程序终止。*/
void PrintErrorMessage(BOOL on, CSTRING fmt, ...);

/*  函数:void PrintErrorMessageToFile(FILE* fp, CSTRING fmt, ...)  */
/*  错误处理。*/
/*  向文件中写入错误信息,使用方式类似标准库函数fprintf()。*/
/*  on:TRUE表示程序继续运行,FALSE表示程序终止。*/
void PrintErrorMessageToFile(FILE* fp, BOOL on, CSTRING fmt, ...);



/*****************************************************************************/
/*  动态内存分配与管理  */
/*****************************************************************************/

/*  宏:NewObject(T)  */
/*  创建目标数据对象,返回指向它的指针。*/
/*  使用方法:T* p; p = NewObject(T); */
#define NewObject(T)         (T*)malloc(sizeof(T))

/*  宏:CreateObjects(T, n)  */
/*  创建连续多个目标数据对象(数组),返回指向数组第一个元素的指针。*/
/*  使用方法:T* p; int n = 10; p = CreateObjects(T, n); */
#define CreateObjects(T, n)  (T*)malloc((n)*sizeof(T))

/*  宏:CreateObject(T, n)  */
/*  创建连续多个目标数据对象,返回指向第一个元素的指针。用于所创建的多个目标数据对象总是作为整体考察的场合,例如创建10个字符,但目标数据对象总是被作为字符串而不是数组处理。*/
/*  使用方法:char* p; int n = 10; p = CreateObject(char, n); */
#define CreateObject(T, n)   (T*)malloc((n)*sizeof(T))

/*  宏:DestroyObject(p)  */
/*  销毁指针所指向的目标数据对象。*/
/*  使用方法:T* p; ...; DestroyObject(p); */
#define DestroyObject(p)     free(p);  p = NULL

/*  宏:DestroyObjects(p)  */
/*  销毁指针所指向的目标数据对象。*/
/*  使用方法:T* p; ...; DestroyObjects(p); */
#define DestroyObjects(p)    free(p); p = NULL



/*****************************************************************************/
/*  字符串功能  */
/*****************************************************************************/

/*  函数:int GetIntegerFromKeyboard() */
/*  从键盘获取整数。*/
int GetIntegerFromKeyboard();

/*  函数:double GetRealFromKeyboard() */
/*  从键盘获取浮点数。*/
double GetRealFromKeyboard();

/*  函数:STRING GetStringFromKeyboard() */
/*  从键盘获取字符串。*/
/*  使用方法:STRING s; s = GetStringFromKeyboard(); ...; DestroyObject(s); */
STRING GetStringFromKeyboard();

/*  函数:STRING GetLineFromFile(FILE* fp) */
/*  从文件中获取一行信息(以'\n'分隔或到文件结尾)。*/
/*  使用方法:STRING s; FILE* fp; fp = fopen(...); s = GetLineFromFile(fp); ...; DestroyObject(s); */
STRING GetLineFromFile( FILE* fp );

/*  函数:STRING DuplicateString( STRING s ) */
/*  拷贝字符串。*/
STRING DuplicateString( STRING s );

/*  函数:STRING ConcatenateString( STRING s1, STRING s2 ) */
/*  合并两个字符串,并返回结果。*/
STRING ConcatenateString( STRING s1, STRING s2 );

/*  函数:int CompareString( STRING s1, STRING s2 ) */
/*  字符串比较。若按照字典顺序,s1在s2之前,返回-1,s1与s2相等,返回0;否则返回1。*/
int CompareString( STRING s1, STRING s2 );

/*  函数:BOOL IsStringEqual( STRING s1, STRING s2 ) */
/*  判断两个字符串是否相等,大小写敏感。*/
BOOL IsStringEqual( STRING s1, STRING s2 );

/*  函数:BOOL IsStringEqualWithoutCase( STRING s1, STRING s2 ) */
/*  判断两个字符串是否相等,忽略大小写。*/
BOOL IsStringEqualWithoutCase( STRING s1, STRING s2 );

/*  函数:unsigned int GetStringLength( STRING s ) */
/*  获取字符串的长度。*/
unsigned int GetStringLength( STRING s );

/*  函数:char GetIthChar( STRING s, unsigned int pos ) */
/*  获取字符串的第pos个字符,pos从0开始编号。*/
/*  使用方法:字符串的首字符使用0作为参数。*/
char GetIthChar( STRING s, unsigned int pos );

/*  函数:STRING GetSubString( STRING s, unsigned int pos, unsigned int length ) */
/*  获取字符串的子串,子串位置从pos处开始,最多包含n个字符。*/
/*  如果pos不在字符串长度范围0~GetStringLength(s)-1内,则返回空字符串,否则返回从pos位置开始的n个字符,若超出字符串长度,则只截至到字符串尾部。*/
STRING GetSubString( STRING s, unsigned int pos, unsigned int n );

/*  函数:STRING TransformStringIntoUpperCase( STRING s ) */
/*  将字符串的全部字符转换为大写字母。*/
STRING TransformStringIntoUpperCase( STRING s );

/*  函数:STRING TransformStringIntoLowerCase( STRING s ) */
/*  将字符串的全部字符转换为小写字母。*/
STRING TransformStringIntoLowerCase( STRING s );

/*  函数:STRING TransformCharIntoString( char c ) */
/*  将一个字符转换为字符串。*/
STRING TransformCharIntoString( char c );

/*  函数:STRING TransformIntegerIntoString( int n ) */
/*  将整数转换为字符串。*/
STRING TransformIntegerIntoString( int n );

/*  函数:int TransformStringIntoInteger( STRING s ) */
/*  将字符串转换为整数。*/
int TransformStringIntoInteger( STRING s );

/*  函数:STRING TransformRealIntoString( double d ) */
/*  将浮点数转换为字符串。*/
STRING TransformRealIntoString( double d );

/*  函数:double TransformStringIntoReal( STRING s ) */
/*  将字符串转换为浮点数。*/
double TransformStringIntoReal( STRING s );

/*  函数:unsigned int FindCharFirst( char key, STRING s ) */
/*  查找字符串s中的指定字符key。返回其第一次查找到的索引下标。若不存在,则返回inexistent_index。*/
unsigned int FindCharFirst( char key, STRING s );

/*  函数:unsigned int FindCharNext( char key, STRING s, int pos ) */
/*  从指定位置pos开始,查找字符串s中的指定字符key。返回从此位置开始首个查找到的索引下标。若不存在,则返回inexistent_index。*/
unsigned int FindCharNext( char key, STRING s, unsigned int pos );

/*  函数:unsigned int FindSubStringFirst( STRING key, STRING s ) */
/*  查找字符串s中的指定子串key。返回其第一次查找到的索引下标。若不存在,则返回inexistent_index。*/
unsigned int FindSubStringFirst( STRING key, STRING s );

/*  函数:unsigned int FindSubStringNext( STRING key, STRING s, int pos ) */
/*  从指定位置pos开始,查找字符串s中的指定子串key。返回从此位置开始首个查找到的索引下标。若不存在,则返回inexistent_index。*/
unsigned int FindSubStringNext( STRING key, STRING s, unsigned int pos );

#endif

zylib.cpp

#include <stddef.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#ifndef __ZYLIB__
#include "zylib.h"
#endif



/*****************************************************************************/
/*  宏与常量定义  */
/*****************************************************************************/

extern const ADT undefined_object = (void*) &undefined_object;

extern const unsigned int inexistent_index = 0xFFFFFFFF;



/*****************************************************************************/
/*  时间处理  */
/*****************************************************************************/

STRING TimeToString(const struct tm* t)
{
    STRING _s;
    _s = CreateObject(char, 20);
    if(!strftime(_s, 20, "%Y-%m-%d %H:%M:%S", t))
    {
        DestroyObject(_s);
        return NULL;
    }
    return _s;
}

STRING CurrentTimeToString()
{
    time_t _t0 = time(NULL);
    struct tm* _t1 = localtime(&_t0);
    return TimeToString(_t1);
}



/*****************************************************************************/
/*  错误处理  */
/*****************************************************************************/

#define EXITCODE (-1)

void PrintErrorMessage(BOOL on, CSTRING fmt, ...)
{
    va_list _args;
    STRING _s;
    if(fmt)
    {
        _s = CurrentTimeToString();
        va_start(_args, fmt);
        fprintf(stderr, "[");
        fprintf(stderr, _s);
        fprintf(stderr, "] ");
        vfprintf(stderr, fmt, _args);
        fprintf(stderr, "\n");
        va_end(_args);
    }
    if(!on)
        exit(EXITCODE);
}


void PrintErrorMessageToFile(FILE* fp, BOOL on, CSTRING fmt, ...)
{
    va_list _args;
    STRING _s;
    if(fp && fmt)
    {
        _s = CurrentTimeToString();
        va_start(_args, fmt);
        fprintf(fp, "[");
        fprintf(fp, _s);
        fprintf(fp, "] ");
        vfprintf(fp, fmt, _args);
        fprintf(fp, "\n");
        va_end(_args);
    }
    if(!on)
        exit(EXITCODE);
}



/*****************************************************************************/
/*  动态内存分配与管理  */
/*****************************************************************************/



/*****************************************************************************/
/*  字符串功能  */
/*****************************************************************************/

int GetIntegerFromKeyboard()
{
    STRING _s;
    int _n;
    char _junk;
    while(TRUE)
    {
        _s = GetStringFromKeyboard();
        switch(sscanf(_s, " %d %c", &_n, &_junk))
        {
            case 1:
                DestroyObject(_s);
                return _n;
            case 2:
                printf("Unexpected character '%c'.\n", _junk);
                break;
            default:
                printf("Please input an integer.\n");
                break;
        }
        DestroyObject(_s);
        printf("Retry: ");
    }
}

double GetRealFromKeyboard()
{
    STRING _s;
    double _d;
    char _junk;
    while(TRUE)
    {
        _s = GetStringFromKeyboard();
        switch(sscanf(_s, " %lf %c", &_d, &_junk))
        {
            case 1:
                DestroyObject(_s);
                return _d;
            case 2:
                printf("Unexpected character '%c'.\n", _junk);
                break;
            default:
                printf("Please input an real number.\n");
                break;
        }
        DestroyObject(_s);
        printf("Retry: ");
    }
}

STRING GetStringFromKeyboard()
{
    fflush(stdin);
    return GetLineFromFile(stdin);
}

STRING GetLineFromFile(FILE* fp)
{
    STRING _s, _t;
    int _n, _c, _size;
    _n = 0;
    _size = BUFSIZ;
    _s = CreateObject(char, _size);
    while((_c = getc(fp)) != '\n' && _c != EOF)
    {
        if(_n >= _size - 1)
        {
            _size <<= 1;
            _t = CreateObject(char, _size);
            strncpy(_t, _s, _n);
            DestroyObject(_s);
            _s = _t;
        }
        _s[_n++] = (char)_c;
    }
    if(_n == 0 && _c == EOF)
    {
        DestroyObject(_s);
        return NULL;
    }
    _s[_n] = '\0';
    _t = CreateObject(char, _n + 1);
    strcpy(_t, _s);
    DestroyObject(_s);
    return _t;
}

STRING DuplicateString(STRING s)
{
    STRING _s;
    unsigned int _n, _i;
    _n = strlen(s);
    _s = CreateObject(char, _n + 1);
    /* while( *_s++ = *s++ ); */
    for(_i=0; _i<_n; _i++)
        _s[_i] = s[_i];
    _s[_n] = '\0';
    return _s;
}

STRING ConcatenateString( STRING s1, STRING s2 )
{
    STRING _s;
    unsigned int _n1, _n2;
    if( !s1 || !s2 )
        PrintErrorMessage( FALSE, "ConcatenateString: Illegal string parameter(s).\n" );
    _n1 = strlen( s1 );
    _n2 = strlen( s2 );
    _s = CreateObject( char, _n1 + _n2 + 1 );
    strcpy( _s, s1 );
    strcpy( _s + _n1, s2 );
    return _s;
}

int CompareString( STRING s1, STRING s2 )
{
    if( !s1 || !s2 )
        PrintErrorMessage( FALSE, "CompareString: Illegal string parameter(s).\n" );
    return strcmp( s1, s2 );
}

BOOL IsStringEqual(STRING s1, STRING s2)
{
    BOOL _r;
    if(!s1 || !s2)
        PrintErrorMessage(FALSE, "IsStringEqual: Illegal string parameter(s).\n");
    _r = strcmp(s1, s2) == 0;
    return _r;
}

BOOL IsStringEqualWithoutCase(STRING s1, STRING s2)
{
    STRING _s1, _s2;
    BOOL _r;
    if(!s1 || !s2)
        PrintErrorMessage(FALSE, "IsStringEqualWithoutCase: Illegal string parameter(s).\n");
    _s1 = DuplicateString(s1);
    TransformStringIntoUpperCase(_s1);
    _s2 = DuplicateString(s2);
    TransformStringIntoUpperCase(_s2);
    _r = strcmp(_s1, _s2) == 0;
    DestroyObject(_s1);
    DestroyObject(_s2);
    return _r;
}

unsigned int GetStringLength( STRING s )
{
    if(!s)
        PrintErrorMessage(FALSE, "GetStringLength: Illegal string parameter(s).\n");
    return strlen(s);
}

char GetIthChar(STRING s, unsigned int pos)
{
    unsigned int _n;
    if(!s)
        PrintErrorMessage(FALSE, "GetIthChar: Illegal string parameter(s).\n");
    _n = strlen(s);
    if(pos >= _n)
        PrintErrorMessage(FALSE, "GetIthChar: Index %d out of range.\n", pos );
    else
        return s[pos];
}

STRING GetSubString( STRING s, unsigned int pos, unsigned int n )
{
    unsigned int _n;
    if(!s)
        PrintErrorMessage(FALSE, "GetSubString: Illegal string parameter.\n");
    _n = strlen( s );
    if( pos >= _n )
        PrintErrorMessage(FALSE, "GetSubString: Index %d out of range.\n", pos );
    else
    {
        unsigned int _m = n < _n - pos ? n : _n - pos;
        STRING _s = CreateObject( char, _m + 1 );
        unsigned int _i;
        for( _i = 0; _i < _m; _i++ )
            _s[_i] = s[pos + _i];
        _s[_m] = '\0';
        return _s;
    }
}

STRING TransformStringIntoUpperCase(STRING s)
{
    unsigned int _n, _i = 0;
    if(!s)
        PrintErrorMessage(FALSE, "TransformStringIntoUpperCase: Illegal string parameter.\n");
    _n = strlen(s);
    for(_i=0; _i<_n; _i++)
        s[_i] = toupper(s[_i]);
    return s;
}


STRING TransformStringIntoLowerCase(STRING s)
{
    unsigned int _n, _i = 0;
    if(!s)
        PrintErrorMessage(FALSE, "TransformStringIntoLowerCase: Illegal string parameter.\n");
    _n = strlen(s);
    for(_i=0; _i<_n; _i++)
        s[_i] = tolower(s[_i]);
    return s;
}

STRING TransformCharIntoString( char c )
{
    STRING _s = CreateObject( char, 2 );
    _s[0] = c;
    _s[1] = '\0';
    return _s;
}

STRING TransformIntegerIntoString( int n )
{
    char _s[BUFSIZ];
    sprintf( _s, "%d", n );
    return DuplicateString(_s);
}

int TransformStringIntoInteger( STRING s )
{
    int _n;
    char _junk;
    if(!s)
        PrintErrorMessage(FALSE, "TransformStringIntoInteger: Illegal string parameter.\n");
    if( sscanf( s, " %d %c", &_n, &_junk ) != 1 )
        PrintErrorMessage(FALSE, "TransformStringIntoInteger: %s is not a number.\n", s );
    return _n;
}

STRING TransformRealIntoString( double d )
{
    char _s[BUFSIZ];
    sprintf( _s, "%G", d );
    return DuplicateString(_s);
}

double TransformStringIntoReal( STRING s )
{
    double _d;
    char _junk;
    if(!s)
        PrintErrorMessage(FALSE, "TransformStringIntoReal: Illegal string parameter.\n");
    if( sscanf( s, " %lg %c", &_d, &_junk ) != 1 )
        PrintErrorMessage(FALSE, "TransformStringIntoReal: %s is not a real number.\n", s );
    return _d;
}

unsigned int FindCharFirst( char key, STRING s )
{
    unsigned int _i;
    if(!s)
        PrintErrorMessage(FALSE, "FindCharFirst: Illegal string parameter.\n");
    for( _i = 0; s[_i] != '\0'; _i++ )
    {
        if( s[_i] == key )
            return _i;
    }
    return inexistent_index;
}

unsigned int FindCharNext( char key, STRING s, unsigned int pos )
{
    unsigned int _i;
    if(!s)
        PrintErrorMessage(FALSE, "FindCharNext: Illegal string parameter.\n");
    if( pos >= strlen(s) )
        return inexistent_index;
    for( _i = pos; s[_i] != '\0'; _i++ )
    {
        if( s[_i] == key )
            return _i;
    }
    return inexistent_index;
}

unsigned int FindSubStringFirst( STRING key, STRING s )
{
    STRING _s;
    if( !s || !key )
        PrintErrorMessage(FALSE, "FindSubStringFirst: Illegal string parameter.\n");
    _s = strstr( s, key );
    if( !_s )
        return inexistent_index;
    else
        return _s - s;
}

unsigned int FindSubStringNext( STRING key, STRING s, unsigned int pos )
{
    STRING _s;
    if( !s || !key )
        PrintErrorMessage(FALSE, "FindSubStringNext: Illegal string parameter.\n");
    if( pos >= strlen(s) )
        return inexistent_index;
    _s = strstr( s + pos, key );
    if( !_s )
        return inexistent_index;
    else
        return _s - s;
}

zyrandom.h

#ifndef __ZYRANDOM__
#define __ZYRANDOM__

#ifndef __ZYLIB__
#include "zylib.h"
#endif



/*****************************************************************************/
/*  随机数功能  */
/*****************************************************************************/

/*
   函数名称:Randomize
   函数功能:初始化伪随机数发生器
   参    数:无
   返 回 值:无
   使用说明:在每次程序执行前,调用此函数初始化伪随机数库。注意,此函数只应执行一次
   */
void Randomize();

/*
   函数名称:GenerateRandomNumber
   函数功能:随机生成介于low和high之间(闭区间)的整数
   参    数:low和high分别表示区间下界和上界;确保low不大于high,否则程序终止执行
   返 回 值:伪随机数
   */
int GenerateRandomNumber(int low, int high);

/*
   函数名称:GenerateRandomReal
   函数功能:随机生成介于low和high之间(闭区间)的浮点数
   参    数:low和high分别表示区间下界和上界;确保low不大于high,否则程序终止执行
   返 回 值:伪随机数
   */
double GenerateRandomReal(double low, double high);


#endif

zyrandom.cpp

#include <stdlib.h>
#include <time.h>

#ifndef __ZYRANDOM__
#include "zyrandom.h"
#endif

#ifndef __ZYLIB__
#include "zylib.h"
#endif



/*****************************************************************************/
/*  随机数功能  */
/*****************************************************************************/

void Randomize()
{
    srand((int)time(NULL));
}

int GenerateRandomNumber(int low, int high)
{
    double _d;
    if( low > high )
        PrintErrorMessage( FALSE, "GenerateRandomNumber: Make sure low <= high.\n" );
    _d = (double)rand() / ((double)RAND_MAX + 1.0);
    return (low + (int)(_d * (high - low + 1)));
}

double GenerateRandomReal(double low, double high)
{
    double _d;
    if( low > high )
        PrintErrorMessage( FALSE, "GenerateRandomReal: Make sure low <= high.\n" );
    _d = (double)rand() / ((double)RAND_MAX + 1.0);
    return (low + _d * (high - low));
}