C语言 串 顺序结构 实现
2013-11-01 23:15 wid 阅读(1250) 评论(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 或程序缺陷, 请留言反馈, 谢谢。