一个能够自动扩容的顺序结构的串 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 ;
}

运行测试:

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

C语言 串 顺序结构 实现的更多相关文章

  1. C语言 队列 顺序结构 实现

    一个能够自动扩容的顺序结构的队列 ArrQueue (GCC编译). /** * @brief C语言顺序结构队列的实现 * @author wid * @date 2013-10-30 * * @n ...

  2. C语言 栈 顺序结构 实现

    一个能够自动扩容的顺序结构的栈 ArrStack 实例 (GCC编译). /** * @brief C语言实现的顺序结构类型的栈 * @author wid * @date 2013-10-29 * ...

  3. C语言之顺序结构

    该章内容:这章我们学习三大结构之一:顺序结构,它是程序从上往下顺序执行,是程序运行最简单的方式.printf和scanf函数使用和特例是必考知识.本章是考试的重点章节. 学习方法:从简单的顺序结构题目 ...

  4. (七)C语言之顺序结构

  5. Java 流程控制语句 之 顺序结构

    在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的.也就是说,程序的流程对运行结果 有直接的影响.所以,我们必须清楚每条语句的执行流程.而且,很多时候我们要通过控制语句的执行顺序来实 ...

  6. C语言第二次作业-----顺序结构

    一:改错题 (1)输出指定信息: 将给定源代码输入编译器: 执行编译命令,发现编译器报错,错误信息如下: 经检查,发现源程序将"stdio.h"误拼为"stido.h&q ...

  7. C语言程序设计第二次作业--顺序结构

    C语言程序设计第二次作业--顺序结构 1.输出带框文字:在屏幕上输出以下3行信息. ************* Welcome ************* 源程序 #include <stido ...

  8. C语言第二次作业——顺序结构

    一.改错题 1.输出带框文字:在屏幕上输出以下3行信息. (1)源程序 对程序进行编译,发现错误信息1 错误原因:stdio拼写错误 改正方法:将stdio正确拼写 对程序进行编译,发现错误信息2 错 ...

  9. C语言程序设计第二次作业—————顺序结构改

    1.输出带框文字:在屏幕上输出以下3行信息. ************* Welcome ************* 源程序 #include <stido.h> int mian() { ...

随机推荐

  1. 通过WinForm控件创建的WPF控件无法输入的问题

    今天把写的一个WPF程序发布到别的机器上执行,发现一个比较奇怪的问题:在那个机器上用英文输入法无法输入数字,非要切换到中文输入法才行:但在我的机器上却是好好的. 最开始以为是输入法的问题,弄了好一阵子 ...

  2. nginx的gzip选项和expire过期时间记录

    最近,参加了公司的组织的一个公开课,收获还是挺多的,下面来总结接一下: 一. 使用nginx来进行网页内容的压缩编码与传输速度的优化: 先来观察一下news.sina.com.cn在请求和传输的时候发 ...

  3. Windows Server 2003/2008 单网卡搭建VPN

    Windows Server 2003/2008 单网卡搭建VPN 1.打开[控制面板] --> [管理工具] --> [路由和远程访问] 2.鼠标右击你要管理的电脑 在弹出式菜单中选中[ ...

  4. 【转载】OpenGL ES 三种类型修饰 uniform attribute varying

    其实attribute varying已经被in和out代替了,但是有些工程代码里面仍然还在,所以权当笔记好了. 1.uniform变量uniform变量是外部application程序传递给(ver ...

  5. SBT 构建scala eclipse开发

    scala eclipse sbt 应用程序开发 搭建Eclipse开发Scala应用程序的一般步骤 一.环境准备: 1.Scala : http://www.scala-lang.org/ 2.Sc ...

  6. jQuery触发<a>标签的点击事件无效

    <a id="workFrame" href="pages/work.html" target="FrameBox">首页< ...

  7. NDK相关以及同步相关博客收集

    http://www.cnblogs.com/heiing/archive/2013/01/20/2868268.htmlhttp://blog.sina.com.cn/s/blog_461c24d5 ...

  8. 前端---HTML

    HTML基础 本章内容: 简介 HTML定义 标签定义和属性 HTML5基本结构 HTML5字符集 <head>标签 <title> <base/> <lin ...

  9. python-->基础-->004-->迭代器

    http://blog.chinaunix.net/uid-23500957-id-3990473.html http://www.cnblogs.com/vamei/archive/2012/07/ ...

  10. MVC5+EF6 简易版CMS(非接口) 第三章:数据存储和业务处理

    目录 简易版CMS后台管理系统开发流程 MVC5+EF6 简易版CMS(非接口) 第一章:新建项目 MVC5+EF6 简易版CMS(非接口) 第二章:建数据模型 MVC5+EF6 简易版CMS(非接口 ...