• C语言 串 顺序结构 实现


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

      1 /**
      2 * @brief C语言 串 顺序结构 实现
      3 * @author wid
      4 * @date 2013-11-01
      5 *
      6 * @note 若代码存在 bug 或程序缺陷, 请留言反馈, 谢谢!
      7 */
      8 
      9 #include <stdio.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 
     13 #define TRUE 1
     14 #define FALSE 0
     15 #define NPOS -1
     16 
     17 typedef struct
     18 {
     19     char *str;
     20     int len;
     21     int size;
     22 }ArrString;     //串结构
     23 
     24 //字符串方法声明
     25 ArrString *CreateString( const char *szStr );        ///创建一个初始值为 szStr 的串
     26 void DestroyString( ArrString *pStr );               ///销毁串 pStr
     27 void ClearString( ArrString *pStr );                 ///置空串 pStr
     28 int IsEmpty( const ArrString *const pStr );          ///是否为空串
     29 int StrLength( const ArrString *const pStr );        ///获取串长度
     30 int StrCopy( ArrString *pDest, const ArrString *const pSrc );    ///将串 pSrc 复制到 pDest
     31 int StrCat( ArrString *pDest, ArrString *pSrc );     ///将串 pSrc 连接到 pDest 后
     32 int SubStr( ArrString *pStr, ArrString *pSub, int nPos, int nLen );      ///取子串
     33 int IndexStr( const ArrString *const pStr, const ArrString *const pSub, int nPos ); ///子串在串pStr中第一次出现的位置
     34 int InsertStr( ArrString *pDest, const ArrString *const pSrc, int nPos );           ///将 pSrc 插入到 pDest 的 nPos 处
     35 int EraseStr( ArrString *pStr, int nStart, int nEnd );                              ///擦除 nStart 至 nEnd 间的子串
     36 int ReplaceStr( ArrString *pStr, ArrString *pFind, ArrString *pReplace );           ///串替换
     37 int StrCompare( const ArrString *const pStr_a, const ArrString *const pStr_b );     ///串比较
     38 char *ToCString( const ArrString *const pStr );       ///转换为C风格字符串
     39 
     40 //字符串方法实现
     41 
     42 /**
     43 * @brief 创建一个初始值为 szStr 的串
     44 *
     45 * @param szStr 指向一条以 `` 结束的字符串
     46 *
     47 * @return 返回指向新建的串的指针
     48 */
     49 ArrString *CreateString( const char *szStr )
     50 {
     51     int nSrcLen = strlen( szStr );
     52 
     53     ArrString *pStr = (ArrString *)malloc( sizeof(ArrString) );
     54     pStr->str = (char *)malloc( nSrcLen + 1 );
     55     strcpy( pStr->str, szStr );
     56     pStr->len = nSrcLen;
     57     pStr->size = nSrcLen + 1;
     58 
     59     return pStr;
     60 }
     61 
     62 /**
     63 * @brief 销毁串 pStr
     64 *
     65 * @param pStr 指向待销毁的串
     66 */
     67 void DestroyString( ArrString *pStr )
     68 {
     69     free( pStr->str );
     70     free( pStr );
     71 }
     72 
     73 /**
     74 * @brief 置空串 pStr
     75 *
     76 * @param 指向待置空的串
     77 */
     78 void ClearString( ArrString *pStr )
     79 {
     80     pStr->str[0] = '';
     81     pStr->len = 0;
     82 }
     83 
     84 /**
     85 * @brief 检测是否为空串
     86 *
     87 * @param pStr 指向待检测的串
     88 *
     89 * @return 若串为空, 则返回TRUE, 否则返回 FALSE
     90 */
     91 int IsEmpty( const ArrString *const pStr )
     92 {
     93     return pStr->len == 0 ? TRUE : FALSE;
     94 }
     95 
     96 /**
     97 * @brief 获取串长度
     98 *
     99 * @param pStr 指向待获取长度的串
    100 *
    101 * @return 返回串当前长度
    102 */
    103 int StrLength( const ArrString *const pStr )
    104 {
    105     return pStr->len;
    106 }
    107 
    108 /**
    109 * @brief 将字符串 pSrc 复制到 pDest
    110 */
    111 int StrCopy( ArrString *pDest, const ArrString *const pSrc )
    112 {
    113     int nSrcLen =  strlen(pSrc->str);
    114 
    115     ///是否需要扩容
    116     if( nSrcLen + 1 > pDest->size )
    117     {   //需要扩容
    118         pDest->str = (char *)realloc( pDest->str, pSrc->size );
    119         pDest->size = pSrc->size;
    120     }
    121 
    122     char *dest = pDest->str;
    123     char *src = pSrc->str;
    124 
    125     ///复制串
    126     while( *dest++ = *src++ );
    127 
    128     pDest->len = pSrc->len;
    129 
    130     return pDest->len;
    131 }
    132 
    133 /**
    134 * @brief 串连接, 将串 pSrc 连接到 pDest 后
    135 *
    136 * @param pDest 指向目标串
    137 * @param pSrc 指向源串
    138 *
    139 * @return 返回连接后目标串的长度
    140 *
    141 * @note 执行串连接后 pSrc 串将被销毁
    142 */
    143 int StrCat( ArrString *pDest, ArrString *pSrc )
    144 {
    145     ///检测是否需要扩容
    146     if( pDest->size - (pDest->len + pSrc->len) < 1 )
    147     {   //需要扩容
    148         pDest->str = (char *)realloc( pDest->str, pDest->len + pSrc->len + 1 );
    149         pDest->size = pDest->len + pSrc->len + 1;
    150     }
    151 
    152     char *dest = &pDest->str[pDest->len];
    153     char *src = pSrc->str;
    154 
    155     ///连接串
    156     while( *dest++ = *src++ );
    157     pDest->len += pSrc->len;
    158 
    159     ///销毁 pSrc
    160     free( pSrc->str );
    161     free( pSrc );
    162     pSrc = NULL;
    163 
    164     return pDest->len;
    165 }
    166 
    167 /**
    168 * @brief 取子串
    169 *
    170 * @param pStr 指向源串
    171 * @param pSub 获取得到的子串
    172 * @param nPos 截取起始位置
    173 * @param nLen 截取的长度
    174 *
    175 * @return 成功得到子串返回 TRUE, 否则返回 FALSE
    176 *
    177 * @note 位置由 0 计起
    178 */
    179 int SubStr( ArrString *pStr, ArrString *pSub, int nPos, int nLen )
    180 {
    181     ///子串不存在
    182     if( nPos < 0 || nPos + nLen > pStr->len || nPos > pStr->len -1 )
    183     {
    184         pSub->len = 0;
    185         pSub->str[0] = '';
    186 
    187         return FALSE;
    188     }
    189 
    190     ///目标子串是否需要扩容
    191     if( pSub->size - nLen < 1 )
    192     {   //扩容
    193         pSub->str = realloc( pSub->str, nLen + 1 );
    194         pSub->size = nLen + 1;
    195     }
    196 
    197     int i = 0;
    198     for( i = 0; i < nLen; ++i )
    199     {
    200         pSub->str[i] = pStr->str[nPos + i];
    201     }
    202     pSub->str[i] = '';
    203     pSub->len = nLen;
    204 
    205     return TRUE;
    206 }
    207 
    208 /**
    209 * @brief 获取子串在目标串中第一次出现的位置
    210 *
    211 * @param pStr 指向目标串
    212 * @param pSub 指向待检测的子串
    213 * @param nPos 检测的起始位置
    214 *
    215 * @return 返回子串在目标串中第一次出现的位置
    216 *
    217 * @note 位置由 0 计起
    218 */
    219 int IndexStr( const ArrString *const pStr, const ArrString *const pSub, int nPos )
    220 {
    221     if( nPos < 0 || nPos > pStr->len - 1 )
    222         return NPOS;
    223 
    224     char *dest = &pStr->str[nPos];
    225     char *sub = pSub->str;
    226     int nSame = 0;
    227     int nCount = 0;
    228 
    229     ///传统匹配
    230     while( *dest )
    231     {
    232         ++nCount;
    233 
    234         if( *sub == *dest )
    235         {
    236             ++nSame;
    237             ++dest;
    238             ++sub;
    239             if( nSame == pSub->len )
    240                 return nPos + nCount - pSub->len;
    241         }
    242         else
    243         {
    244             sub = pSub->str;
    245             if( nSame == 0 )
    246                 ++dest;
    247             else
    248                 --nCount;
    249 
    250             nSame = 0;
    251         }
    252     }
    253 
    254     return NPOS;
    255 }
    256 
    257 /**
    258 * @brief 将 pSrc 插入到 pDest 的 nPos 处
    259 *
    260 * @param pDest 目标串
    261 * @param pSrc 源串
    262 * @param nPos 插入的位置
    263 *
    264 * @return 若成功插入, 则返回插入后目标串的长度, 否则返回 -1
    265 *
    266 * @note 位置由 0 计起
    267 */
    268 int InsertStr( ArrString *pDest, const ArrString *const pSrc, int nPos )
    269 {
    270     ///插入位置是否合法
    271     if( nPos < 0 || nPos > pDest->len - 1 )
    272         return -1;
    273 
    274     ///是否需要扩容
    275     if( (pDest->size - pDest->len - pSrc->len) < 1 )
    276     {   //需要扩容
    277         pDest->str = (char *)realloc( pDest->str, pDest->size + pSrc->len );
    278         pDest->size += pSrc->len;
    279     }
    280 
    281     ///从插入位置向后移动腾出空间
    282     int i = pDest->len + pSrc->len - 1;
    283     pDest->str[i + 1] = '';
    284     for( i; i > nPos; --i )
    285     {
    286         pDest->str[i] = pDest->str[i - pSrc->len];
    287     }
    288 
    289     ///将待插入的串插入
    290     for( i = 0; i < pSrc->len; ++i )
    291     {
    292         pDest->str[nPos + i] = pSrc->str[i];
    293     }
    294 
    295     pDest->len += pSrc->len;
    296 
    297     return pDest->len;
    298 }
    299 
    300 /**
    301 * @brief 擦除串 pStr 中位置 nStat 至 nEnd 间的子串
    302 *
    303 * @param pStr 指向待擦除子串的串
    304 * @param nStart 起始位置
    305 * @param nEnd 结束位置
    306 *
    307 * @return 成功则返回擦除后串的长度, 否则返回 -1
    308 *
    309 * @note 位置由 0 计起, 擦除范围为 [nStart, nEnd)
    310 */
    311 int EraseStr( ArrString *pStr, int nStart, int nEnd )
    312 {
    313     if( nStart > nEnd || 
    314         nStart < 0 ||
    315         nStart > pStr->len || 
    316         nEnd < 0 || 
    317         nEnd > pStr->len 
    318     ) return -1;
    319 
    320     int i = nStart, nLen = nEnd - nStart;
    321 
    322     ///执行擦除
    323     for( i; i < pStr->len - nLen; ++i )
    324     {
    325         pStr->str[i] = pStr->str[i + nLen];
    326     }
    327 
    328     ///重置 `` 位置
    329     pStr->str[ pStr->len - nLen ] = '';
    330 
    331     ///重置长度
    332     pStr->len -= nLen;
    333 
    334     return pStr->len;
    335 }
    336 
    337 /**
    338 * @brief 将串中的一部分子串用另一串替换
    339 *
    340 * @param pStr 指向被替换的串
    341 * @param pFind 待替换的串
    342 * @param pReplace 替换的内容
    343 *
    344 * @return 返回替换的次数
    345 */
    346 int ReplaceStr( ArrString *pStr, ArrString *pFind, ArrString *pReplace )
    347 {
    348     int nStart = 0, nEnd = 0, nCount = 0;
    349 
    350     while( TRUE )
    351     {
    352         nStart = IndexStr( pStr, pFind, nEnd );
    353         if( nStart != NPOS )
    354         {
    355             EraseStr( pStr, nStart, nStart + pFind->len + 1 );
    356             InsertStr( pStr, pReplace, nStart );
    357             nEnd = nStart + pReplace->len + 1;
    358             ++nCount;
    359 
    360         }
    361         else break;
    362     }
    363 
    364     return nCount;
    365 }
    366 
    367 /**
    368 * @brief 比较串 pStr_a 与 pStr_b 的大小
    369 *
    370 * @param pStr_a 目标串一
    371 * @param pStr_b 目标串二
    372 *
    373 * @return 若串一大于串二则返回正数, 相等返回 0, 小于串二则返回负数
    374 */
    375 int StrCompare( const ArrString *const pStr_a, const ArrString *const pStr_b )
    376 {
    377     char *sa = pStr_a->str;
    378     char *sb = pStr_b->str;
    379 
    380     while( *sa && *sb )
    381     {
    382         if( *sa != *sb )
    383             return *sa - *sb;
    384 
    385         ++sa;
    386         ++sb;
    387     }
    388 
    389     if( pStr_a->len == pStr_b->len  )
    390         return 0;
    391 
    392     return pStr_a->len > pStr_b->len ? 1 : -1;
    393 }
    394 
    395 /**
    396 * @brief 将串转换为C风格字符串
    397 *
    398 * @param 指向待转换的串
    399 *
    400 * @return 返回指向转换后C风格串的指针
    401 */
    402 char *ToCString( const ArrString *const pStr )
    403 {
    404     return pStr->str;
    405 }
    406 
    407 //测试
    408 
    409 int main()
    410 {
    411     ///测试 CreateString
    412     ArrString *s1 = CreateString( "Hello, " );
    413     ArrString *s2 = CreateString( "world!" );
    414 
    415     ///测试 IsEmpty、 StrLength
    416     if( IsEmpty( s1 ) != TRUE )
    417         printf( "s1 length = %d, IsEmpty = %d
    
    ", StrLength(s1), IsEmpty( s1 ) );
    418 
    419     ///测试 ClearString
    420     ClearString( s1 );
    421     printf( "ClearString s1...
    " );
    422     printf( "s1 length = %d, IsEmpty = %d
    
    ", StrLength(s1), IsEmpty( s1 ) );
    423 
    424     ///测试 StrCopy、ToCString
    425     StrCopy( s1, s2 );
    426     printf( "测试StrCopy(s1, s2), s1=%s
    
    ", ToCString(s1) );
    427 
    428     ///测试 StrCat
    429     StrCat( s1, s2 );
    430     printf( "测试StrCat( s1, s2 ), s1=%s
    
    ", ToCString(s1) );
    431 
    432     ///测试 SubString
    433     ArrString *s3 = CreateString( "Hello, world!" );
    434     ArrString *sub = CreateString( "" );
    435     SubStr( s3, sub, 5, 7 );
    436     printf( "测试 SubStr, 源串:"%s", 自位置3起, 长度为6, 子串为:"%s"
    
    ", ToCString(s3), ToCString(sub) );
    437 
    438     ///测试 IndexStr
    439     int nPos = IndexStr( s3, sub, 0 );
    440     printf( "测试 IndexStr, 源串"%s", 子串:"%s", 子串在源串的位置:%d
    
    ", ToCString(s3), ToCString(sub), nPos );
    441 
    442     ///测试 InsertStr
    443     ArrString *src = CreateString( "AAA" );
    444     InsertStr( s3, src, 2  );
    445     printf( "测试 InsertStr, 在串s3位置2处插入串"%s": %s
    
    ", ToCString(src), ToCString(s3) );
    446 
    447     ///测试 ReplaceStr
    448     ArrString *plc = CreateString( "#####" );
    449     int n = ReplaceStr( s3, src, plc );
    450     printf( "将串s3中"AAA"替换为"#####": %s, 共替换了%d次
    
    ", ToCString(s3), n );
    451 
    452     ///测试 EraseStr
    453     EraseStr( s3, 2, 7 );
    454     printf( "擦除串s3中位置2至7的内容:%s
    
    ", ToCString(s3) );
    455 
    456     ///测试 StrCompare
    457     printf( "
    测试 StrCompare:
    " );
    458     ArrString *s4 = CreateString( "Hello!" );
    459     ArrString *s5 = CreateString( "Hi~" );
    460     n = StrCompare( s4, s5 );
    461     if( n > 0 )
    462         printf( "%s > %s
    ", ToCString(s4), ToCString(s5) );
    463     if( n < 0 )
    464         printf( "%s < %s
    ", ToCString(s4), ToCString(s5) );
    465     if( n == 0 )
    466         printf( "%s == %s
    ", ToCString(s4), ToCString(s5) );
    467 
    468     ///销毁串
    469     DestroyString( s1 );
    470     DestroyString( s3 );
    471     DestroyString( s4 );
    472     DestroyString( s5 );
    473     DestroyString( sub );
    474     DestroyString( plc );
    475     DestroyString( src );
    476 
    477     return 0;
    478 }

    运行测试:

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

  • 相关阅读:
    彻底搞清分库分表(垂直分库,垂直分表,水平分库,水平分表)
    linux服务器上tcp有大量time_wait状态的解决方法和原因解释
    mysql,既可以自己的字段相乘,也可以乘固定的字段
    vscode 滚动设置字体大小
    nodejs 定时任务 node-schedule 库
    Node.js中的环境变量
    js 打印错误堆栈
    springboot 返回的json中忽略null属性值,不传递
    idea跳转到指定行列快捷键
    Spring boot + MyBatis返回map中null值处理
  • 原文地址:https://www.cnblogs.com/mr-wid/p/3403006.html
Copyright © 2020-2023  润新知