代码改变世界

C语言 串 顺序结构 实现

2013-11-01 23:15  wid  阅读(1252)  评论(0编辑  收藏  举报

一个能够自动扩容的顺序结构的串 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 指向一条以 `\0` 结束的字符串
 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] = '\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] = '\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] = '\0';
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] = '\0';
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     ///重置 `\0` 位置
329     pStr->str[ pStr->len - nLen ] = '\0';
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\n\n", StrLength(s1), IsEmpty( s1 ) );
418 
419     ///测试 ClearString
420     ClearString( s1 );
421     printf( "ClearString s1...\n" );
422     printf( "s1 length = %d, IsEmpty = %d\n\n", StrLength(s1), IsEmpty( s1 ) );
423 
424     ///测试 StrCopy、ToCString
425     StrCopy( s1, s2 );
426     printf( "测试StrCopy(s1, s2), s1=%s\n\n", ToCString(s1) );
427 
428     ///测试 StrCat
429     StrCat( s1, s2 );
430     printf( "测试StrCat( s1, s2 ), s1=%s\n\n", 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\"\n\n", ToCString(s3), ToCString(sub) );
437 
438     ///测试 IndexStr
439     int nPos = IndexStr( s3, sub, 0 );
440     printf( "测试 IndexStr, 源串\"%s\", 子串:\"%s\", 子串在源串的位置:%d\n\n", 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\n\n", ToCString(src), ToCString(s3) );
446 
447     ///测试 ReplaceStr
448     ArrString *plc = CreateString( "#####" );
449     int n = ReplaceStr( s3, src, plc );
450     printf( "将串s3中\"AAA\"替换为\"#####\": %s, 共替换了%d次\n\n", ToCString(s3), n );
451 
452     ///测试 EraseStr
453     EraseStr( s3, 2, 7 );
454     printf( "擦除串s3中位置2至7的内容:%s\n\n", ToCString(s3) );
455 
456     ///测试 StrCompare
457     printf( "\n测试 StrCompare:\n" );
458     ArrString *s4 = CreateString( "Hello!" );
459     ArrString *s5 = CreateString( "Hi~" );
460     n = StrCompare( s4, s5 );
461     if( n > 0 )
462         printf( "%s > %s\n", ToCString(s4), ToCString(s5) );
463     if( n < 0 )
464         printf( "%s < %s\n", ToCString(s4), ToCString(s5) );
465     if( n == 0 )
466         printf( "%s == %s\n", 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 或程序缺陷, 请留言反馈, 谢谢。