C语言 串 顺序结构 实现

时间:2022-07-05 22:44:03

一个能够自动扩容的顺序结构的串 ArrString (GCC编译)。

 /**
* @brief C语言 串 顺序结构 实现
* @author wid
* @date 2013-11-01
*
* @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!
*/ #include <stdio.h>
#include <stdlib.h>
#include <string.h> #define TRUE 1
#define FALSE 0
#define NPOS -1 typedef struct
{
char *str;
int len;
int size;
}ArrString; //串结构 //字符串方法声明
ArrString *CreateString( const char *szStr ); ///创建一个初始值为 szStr 的串
void DestroyString( ArrString *pStr ); ///销毁串 pStr
void ClearString( ArrString *pStr ); ///置空串 pStr
int IsEmpty( const ArrString *const pStr ); ///是否为空串
int StrLength( const ArrString *const pStr ); ///获取串长度
int StrCopy( ArrString *pDest, const ArrString *const pSrc ); ///将串 pSrc 复制到 pDest
int StrCat( ArrString *pDest, ArrString *pSrc ); ///将串 pSrc 连接到 pDest 后
int SubStr( ArrString *pStr, ArrString *pSub, int nPos, int nLen ); ///取子串
int IndexStr( const ArrString *const pStr, const ArrString *const pSub, int nPos ); ///子串在串pStr中第一次出现的位置
int InsertStr( ArrString *pDest, const ArrString *const pSrc, int nPos ); ///将 pSrc 插入到 pDest 的 nPos 处
int EraseStr( ArrString *pStr, int nStart, int nEnd ); ///擦除 nStart 至 nEnd 间的子串
int ReplaceStr( ArrString *pStr, ArrString *pFind, ArrString *pReplace ); ///串替换
int StrCompare( const ArrString *const pStr_a, const ArrString *const pStr_b ); ///串比较
char *ToCString( const ArrString *const pStr ); ///转换为C风格字符串 //字符串方法实现 /**
* @brief 创建一个初始值为 szStr 的串
*
* @param szStr 指向一条以 `\0` 结束的字符串
*
* @return 返回指向新建的串的指针
*/
ArrString *CreateString( const char *szStr )
{
int nSrcLen = strlen( szStr ); ArrString *pStr = (ArrString *)malloc( sizeof(ArrString) );
pStr->str = (char *)malloc( nSrcLen + );
strcpy( pStr->str, szStr );
pStr->len = nSrcLen;
pStr->size = nSrcLen + ; return pStr;
} /**
* @brief 销毁串 pStr
*
* @param pStr 指向待销毁的串
*/
void DestroyString( ArrString *pStr )
{
free( pStr->str );
free( pStr );
} /**
* @brief 置空串 pStr
*
* @param 指向待置空的串
*/
void ClearString( ArrString *pStr )
{
pStr->str[] = '\0';
pStr->len = ;
} /**
* @brief 检测是否为空串
*
* @param pStr 指向待检测的串
*
* @return 若串为空, 则返回TRUE, 否则返回 FALSE
*/
int IsEmpty( const ArrString *const pStr )
{
return pStr->len == ? TRUE : FALSE;
} /**
* @brief 获取串长度
*
* @param pStr 指向待获取长度的串
*
* @return 返回串当前长度
*/
int StrLength( const ArrString *const pStr )
{
return pStr->len;
} /**
* @brief 将字符串 pSrc 复制到 pDest
*/
int StrCopy( ArrString *pDest, const ArrString *const pSrc )
{
int nSrcLen = strlen(pSrc->str); ///是否需要扩容
if( nSrcLen + > pDest->size )
{ //需要扩容
pDest->str = (char *)realloc( pDest->str, pSrc->size );
pDest->size = pSrc->size;
} char *dest = pDest->str;
char *src = pSrc->str; ///复制串
while( *dest++ = *src++ ); pDest->len = pSrc->len; return pDest->len;
} /**
* @brief 串连接, 将串 pSrc 连接到 pDest 后
*
* @param pDest 指向目标串
* @param pSrc 指向源串
*
* @return 返回连接后目标串的长度
*
* @note 执行串连接后 pSrc 串将被销毁
*/
int StrCat( ArrString *pDest, ArrString *pSrc )
{
///检测是否需要扩容
if( pDest->size - (pDest->len + pSrc->len) < )
{ //需要扩容
pDest->str = (char *)realloc( pDest->str, pDest->len + pSrc->len + );
pDest->size = pDest->len + pSrc->len + ;
} char *dest = &pDest->str[pDest->len];
char *src = pSrc->str; ///连接串
while( *dest++ = *src++ );
pDest->len += pSrc->len; ///销毁 pSrc
free( pSrc->str );
free( pSrc );
pSrc = NULL; return pDest->len;
} /**
* @brief 取子串
*
* @param pStr 指向源串
* @param pSub 获取得到的子串
* @param nPos 截取起始位置
* @param nLen 截取的长度
*
* @return 成功得到子串返回 TRUE, 否则返回 FALSE
*
* @note 位置由 0 计起
*/
int SubStr( ArrString *pStr, ArrString *pSub, int nPos, int nLen )
{
///子串不存在
if( nPos < || nPos + nLen > pStr->len || nPos > pStr->len - )
{
pSub->len = ;
pSub->str[] = '\0'; return FALSE;
} ///目标子串是否需要扩容
if( pSub->size - nLen < )
{ //扩容
pSub->str = realloc( pSub->str, nLen + );
pSub->size = nLen + ;
} int i = ;
for( i = ; i < nLen; ++i )
{
pSub->str[i] = pStr->str[nPos + i];
}
pSub->str[i] = '\0';
pSub->len = nLen; return TRUE;
} /**
* @brief 获取子串在目标串中第一次出现的位置
*
* @param pStr 指向目标串
* @param pSub 指向待检测的子串
* @param nPos 检测的起始位置
*
* @return 返回子串在目标串中第一次出现的位置
*
* @note 位置由 0 计起
*/
int IndexStr( const ArrString *const pStr, const ArrString *const pSub, int nPos )
{
if( nPos < || nPos > pStr->len - )
return NPOS; char *dest = &pStr->str[nPos];
char *sub = pSub->str;
int nSame = ;
int nCount = ; ///传统匹配
while( *dest )
{
++nCount; if( *sub == *dest )
{
++nSame;
++dest;
++sub;
if( nSame == pSub->len )
return nPos + nCount - pSub->len;
}
else
{
sub = pSub->str;
if( nSame == )
++dest;
else
--nCount; nSame = ;
}
} return NPOS;
} /**
* @brief 将 pSrc 插入到 pDest 的 nPos 处
*
* @param pDest 目标串
* @param pSrc 源串
* @param nPos 插入的位置
*
* @return 若成功插入, 则返回插入后目标串的长度, 否则返回 -1
*
* @note 位置由 0 计起
*/
int InsertStr( ArrString *pDest, const ArrString *const pSrc, int nPos )
{
///插入位置是否合法
if( nPos < || nPos > pDest->len - )
return -; ///是否需要扩容
if( (pDest->size - pDest->len - pSrc->len) < )
{ //需要扩容
pDest->str = (char *)realloc( pDest->str, pDest->size + pSrc->len );
pDest->size += pSrc->len;
} ///从插入位置向后移动腾出空间
int i = pDest->len + pSrc->len - ;
pDest->str[i + ] = '\0';
for( i; i > nPos; --i )
{
pDest->str[i] = pDest->str[i - pSrc->len];
} ///将待插入的串插入
for( i = ; i < pSrc->len; ++i )
{
pDest->str[nPos + i] = pSrc->str[i];
} pDest->len += pSrc->len; return pDest->len;
} /**
* @brief 擦除串 pStr 中位置 nStat 至 nEnd 间的子串
*
* @param pStr 指向待擦除子串的串
* @param nStart 起始位置
* @param nEnd 结束位置
*
* @return 成功则返回擦除后串的长度, 否则返回 -1
*
* @note 位置由 0 计起, 擦除范围为 [nStart, nEnd)
*/
int EraseStr( ArrString *pStr, int nStart, int nEnd )
{
if( nStart > nEnd || \
nStart < ||
nStart > pStr->len || \
nEnd < || \
nEnd > pStr->len \
) return -; int i = nStart, nLen = nEnd - nStart; ///执行擦除
for( i; i < pStr->len - nLen; ++i )
{
pStr->str[i] = pStr->str[i + nLen];
} ///重置 `\0` 位置
pStr->str[ pStr->len - nLen ] = '\0'; ///重置长度
pStr->len -= nLen; return pStr->len;
} /**
* @brief 将串中的一部分子串用另一串替换
*
* @param pStr 指向被替换的串
* @param pFind 待替换的串
* @param pReplace 替换的内容
*
* @return 返回替换的次数
*/
int ReplaceStr( ArrString *pStr, ArrString *pFind, ArrString *pReplace )
{
int nStart = , nEnd = , nCount = ; while( TRUE )
{
nStart = IndexStr( pStr, pFind, nEnd );
if( nStart != NPOS )
{
EraseStr( pStr, nStart, nStart + pFind->len + );
InsertStr( pStr, pReplace, nStart );
nEnd = nStart + pReplace->len + ;
++nCount; }
else break;
} return nCount;
} /**
* @brief 比较串 pStr_a 与 pStr_b 的大小
*
* @param pStr_a 目标串一
* @param pStr_b 目标串二
*
* @return 若串一大于串二则返回正数, 相等返回 0, 小于串二则返回负数
*/
int StrCompare( const ArrString *const pStr_a, const ArrString *const pStr_b )
{
char *sa = pStr_a->str;
char *sb = pStr_b->str; while( *sa && *sb )
{
if( *sa != *sb )
return *sa - *sb; ++sa;
++sb;
} if( pStr_a->len == pStr_b->len )
return ; return pStr_a->len > pStr_b->len ? : -;
} /**
* @brief 将串转换为C风格字符串
*
* @param 指向待转换的串
*
* @return 返回指向转换后C风格串的指针
*/
char *ToCString( const ArrString *const pStr )
{
return pStr->str;
} //测试 int main()
{
///测试 CreateString
ArrString *s1 = CreateString( "Hello, " );
ArrString *s2 = CreateString( "world!" ); ///测试 IsEmpty、 StrLength
if( IsEmpty( s1 ) != TRUE )
printf( "s1 length = %d, IsEmpty = %d\n\n", StrLength(s1), IsEmpty( s1 ) ); ///测试 ClearString
ClearString( s1 );
printf( "ClearString s1...\n" );
printf( "s1 length = %d, IsEmpty = %d\n\n", StrLength(s1), IsEmpty( s1 ) ); ///测试 StrCopy、ToCString
StrCopy( s1, s2 );
printf( "测试StrCopy(s1, s2), s1=%s\n\n", ToCString(s1) ); ///测试 StrCat
StrCat( s1, s2 );
printf( "测试StrCat( s1, s2 ), s1=%s\n\n", ToCString(s1) ); ///测试 SubString
ArrString *s3 = CreateString( "Hello, world!" );
ArrString *sub = CreateString( "" );
SubStr( s3, sub, , );
printf( "测试 SubStr, 源串:\"%s\", 自位置3起, 长度为6, 子串为:\"%s\"\n\n", ToCString(s3), ToCString(sub) ); ///测试 IndexStr
int nPos = IndexStr( s3, sub, );
printf( "测试 IndexStr, 源串\"%s\", 子串:\"%s\", 子串在源串的位置:%d\n\n", ToCString(s3), ToCString(sub), nPos ); ///测试 InsertStr
ArrString *src = CreateString( "AAA" );
InsertStr( s3, src, );
printf( "测试 InsertStr, 在串s3位置2处插入串\"%s\": %s\n\n", ToCString(src), ToCString(s3) ); ///测试 ReplaceStr
ArrString *plc = CreateString( "#####" );
int n = ReplaceStr( s3, src, plc );
printf( "将串s3中\"AAA\"替换为\"#####\": %s, 共替换了%d次\n\n", ToCString(s3), n ); ///测试 EraseStr
EraseStr( s3, , );
printf( "擦除串s3中位置2至7的内容:%s\n\n", ToCString(s3) ); ///测试 StrCompare
printf( "\n测试 StrCompare:\n" );
ArrString *s4 = CreateString( "Hello!" );
ArrString *s5 = CreateString( "Hi~" );
n = StrCompare( s4, s5 );
if( n > )
printf( "%s > %s\n", ToCString(s4), ToCString(s5) );
if( n < )
printf( "%s < %s\n", ToCString(s4), ToCString(s5) );
if( n == )
printf( "%s == %s\n", ToCString(s4), ToCString(s5) ); ///销毁串
DestroyString( s1 );
DestroyString( s3 );
DestroyString( s4 );
DestroyString( s5 );
DestroyString( sub );
DestroyString( plc );
DestroyString( src ); return ;
}

运行测试:

C语言 串 顺序结构 实现

若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢。