需求: 使用C语言封装string 字符串,实现字符串的增、删、改、查等API函数。

要求: 不能使用 string 库函数,所有库函数必须自己手动实现。

【项目实现】

myString.h 代码如下:

 #include <stdlib.h>
#include <string.h>
#include <stdio.h> //字符串封装,需要库函数
//不需要库函数
struct CString
{
char *p; //保存字符串首地址
int realLen; //字符串实际长度
}; typedef struct CString myString; //相当于myString就是struct CString的简写 //字符串封装需要实现:初始化、打印、增[尾部增加/任意位置增加](字符/字符串)、删(字符/字符串)、查(字符/字符串)、改(字符/字符串) void init(myString *string); //原封不动初始化
void initWithLen(myString *string, int len); //开辟长度,内存清零
void initWithString(myString *string, char *copyString); //初始化并拷贝字符串
void printString(myString *string); //打印字符串 void run(myString *string); //将字符串string按照指令来执行 //增[尾部增加](字符/字符串):
void backAddChar(myString *string,char ch); //尾部增加字符
void backAddStr(myString *string,char *str); //尾部增加字符串 //查(字符/字符串):
char *findFirstChar(myString *string, char ch); //在字符串string中查找第一个出现的字符ch,返回第一个找到的字符
char *findFirstStr(myString *string, char *str); //在字符串string中查找第一个子串str,返回第一个找到的子串的地址 //删(字符/字符串)
int delFirstChar(myString *string, const char ch); //成功返回0,失败返回-1;依赖于查找函数;删除第一个找到的字符
int delFirstStr(myString *string, char * const str); //删除第一个找到的字符串 //增[任意位置增加](字符/字符串):
void addChar(myString *string, char ch, char *pos); //任意位置增加字符
void addStr(myString *string, char *str, char *pos); //任意位置增加字符串 //改(字符/字符串)
void changeFirstChar(myString *string, const char oldChar, const char newChar); //修改字符
void changeFirstStr(myString *string, char * const oldStr, char * const newStr); //修改字符串

myString.c 代码如下:

 #define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "myString.h" //实现库函数strlen():
int mystrlen(const char *p)
{
if (p == NULL)
return -; //失败
int len = ;
while (*p != '\0') //字符串终止条件
{
len++; //长度自增
p++; //指针不断向前
}
return len;
} //实现库函数strcpy():
char *mystrcpy(char *strDest, const char *strSrc) //const限定不被意外修改
{
if (strDest == NULL || strSrc == NULL) //异常处理
return NULL; char *destbak = strDest; //destbak保留strDest的初始位置,因为循环结束后strDest指向了末尾
while (*strSrc != '\0')
{
*strDest = *strSrc; //赋值字符
strSrc++;
strDest++; //指针不断向前,字符挨个赋值
}
*strDest = '\0'; //注意:此处需要添加'\0'作为结束
return destbak; //返回的是strDest的起始位置,所以用destbak
} //初始化结构体字符串
void init(myString *string)
{
string->p = NULL;
string->realLen = ;
} void initWithLen(myString *string, int len)
{
//string->p = (char *)malloc(sizeof(char *)*len); //分配内存,但是分配的内存不为‘0’,可以使用calloc函数
string->p = (char *)calloc(len, sizeof(char *)); //分配内存并清0,避免了垃圾数据的影响
string->realLen = len; //长度
} void initWithString(myString *string, char *copyString)
{
int length = mystrlen(copyString); //获取字符串长度,需实现strlen()库函数
string->p = (char *)calloc(length + , sizeof(char)); //分配内存
mystrcpy(string->p, copyString); //拷贝字符串,需实现strcpy()库函数
string->realLen = length + ; //设置长度
} //打印字符串
void printString(myString *string)
{
printf("%s\n", string->p);
} void run(myString *string)
{
system(string->p); //执行指令
} //-----------------------------------增[尾部增加](字符/字符串)-------------------------------------------------
//实现库函数strcat():
char *mystrcat(char *strDest, const char *strSrc)
{
if (strDest == NULL || strSrc == NULL)
return NULL; //失败 char *destbak = strDest;
while (*strDest != '\0')
{
strDest++; //strDest指针向前移动,一直到最后一个字符'\0'的位置
}
while (*strSrc != '\0') //从strDest尾部开始拷贝
{
*strDest = *strSrc;
strSrc++;
strDest++;
}
*strDest = '\0';
return destbak;
} //尾部增加字符
void backAddChar(myString *string, char ch)
{
if (mystrlen(string->p) + == string->realLen) //意味着满了
{
//重新分配内存,增加一个字符的位置
string->p = realloc(string->p, string->realLen + );
string->realLen += ; //注意:不能用 string->realLen++; 若用++,这个值在寄存器中而并没有赋值 string->p[string->realLen - ] = ch;
string->p[string->realLen - ] = '\0';
}
else
{
int nowLen = mystrlen(string->p); //求出当前长度
string->p[nowLen] = ch;
string->p[nowLen + ] = '\0'; //字符增加
}
} //尾部增加字符串
void backAddStr(myString *string, char *str)
{
int nowStrLen = mystrlen(string->p);        //获取当前字符串长度
int addStrLen = mystrlen(str);       //要增加的字符串的长度
if (nowStrLen + addStrLen + > string->realLen) //判定是否越界
{
int needAddLen = nowStrLen + addStrLen + - string->realLen; //需要扩展的长度
string->p = (char *)realloc(string->p, string->realLen + needAddLen); //增加字符串长度 mystrcat(string->p, str); //拷贝字符串,需要自己实现库函数strcat()
string->realLen += needAddLen; //增加长度
}
else
{
mystrcat(string->p, str); //拷贝字符串
}
} //-----------------------------------查(字符/字符串)-------------------------------------------------
//在字符串string中查找第一个出现的字符ch,返回第一个找到的字符
//实现库函数strchr():在字符串string中查找第一个出现的字符ch
//函数原型: char *strchr(char *str,char c);
char *mystrchr(const char *str, const char c)
{
if (str == NULL) //异常情况
return NULL; while (*str != '\0')
{
if (*str == c)
{
return str; //找到返回地址
}
str++;
}
return NULL; //没有找到返回NULL
}
char *findFirstChar(myString *string, char ch)
{
char *p = mystrchr(string->p, ch);
return p;
}
//在字符串string中查找第一个子串str,返回第一个找到的子串的地址
//实现库函数strstr():在字符串str1中查找指定子串str2,返回第一个找到的子串的地址
//函数原型: char *strstr(char *str1,char *str2);
char *mystrstr(const char * const str1, const char * const str2) //注意这里第二个const的使用,不允许str1指针后移
{
if (str1 == NULL || str2 == NULL) //异常
return NULL; char *p = NULL; //保存找到的地址
char *strbak1 = str1; //对str1的起始位置作备份 while (*strbak1 != '\0')
{
int flag = ; //标识符,一开始假定是相等的
char *strbak2 = str2; //此语句放在循环中,每次循环都需要重新赋值
char *nowstrbak1 = strbak1; while (*strbak2 != '\0')
{
if (*nowstrbak1 != '\0') //没有到str1的末尾
{
if (*strbak2 != *nowstrbak1)//有一个不等
{
flag = ; //赋值为0,代表不等
}
nowstrbak1++;
strbak2++;
}
else
{
flag = ;
break;
}
} if (flag == )
{
p = strbak1; //当前位置
return p;
}
strbak1++;
} return NULL;
}
char *findFirstStr(myString *string, char *str)
{
char *pres = mystrstr(string->p, str);
return pres; //返回地址
} //-----------------------------------删(字符/字符串)-------------------------------------------------
//删除第一个找到的字符
int delFirstChar(myString *string, const char ch) //成功返回0,失败返回-1;依赖于查找函数
{
char *p = mystrchr(string->p, ch); //查找 if (p == NULL)
return ;
else
{
char *pnext = p + ;
while (*pnext != '\0')
{
*p = *pnext; //删除一个字符,整体向前移动
p++;
pnext++;
}
*p = '\0'; //字符串一定要有结尾 return ;
}
} //删除第一个找到的字符串
int delFirstStr(myString *string, char * const str)
{
char *p = mystrstr(string->p, str); //查找 if (p == NULL)
return ;
else
{
int length = mystrlen(str); //求子串的长度
char *pnext = p + length;
while (*pnext != '\0')
{
*p = *pnext; //删除一个字符,整体向前移动
p++;
pnext++;
}
*p = '\0'; return ;
}
} //-----------------------------------增[任意位置增加](字符/字符串)-------------------------------------------------
//任意位置增加字符
void addChar(myString *string, char ch, char *pos)
{
if (pos == NULL || string == NULL) //异常情况
return; if (mystrlen(string->p) + == string->realLen) //意味着满了
{
//重新分配内存,增加一个字符的位置
string->p = realloc(string->p, string->realLen + );
string->realLen += ; //注意:不能用 string->realLen++; 若用++,这个值在寄存器中而并没有赋值 int nowLen = mystrlen(string->p); //求出当前长度
int moveLen = mystrlen(pos); //求出现在要移动的长度
for (int i = nowLen - ; i > (nowLen - moveLen); i--)
{
string->p[i] = string->p[i - ]; //轮询移动
}
string->p[nowLen - moveLen] = ch; //先移动,再插入 string->p[nowLen + ] = '\0'; //注意结尾
}
else
{
int nowLen = mystrlen(string->p); //求出当前长度
int moveLen = mystrlen(pos); //求出现在要移动的长度
for (int i = nowLen - ; i > (nowLen - moveLen); i--)
{
string->p[i] = string->p[i - ]; //轮询移动
}
string->p[nowLen - moveLen] = ch; //先移动,再插入 string->p[nowLen + ] = '\0'; //注意结尾
}
} //任意位置增加字符串
void addStr(myString *string, char *str, char *pos)
{
if (pos == NULL || string == NULL) //异常情况
return; int nowStrLen = mystrlen(string->p); //获取当前字符串长度
int addStrLen = mystrlen(str); //要增加的字符串的长度
if (nowStrLen + addStrLen + > string->realLen) //判定是否越界
{
int needAddLen = nowStrLen + addStrLen + - string->realLen; //需要扩展的长度
string->p = (char *)realloc(string->p, string->realLen + needAddLen); //增加字符串长度
string->realLen += needAddLen; //增加长度 //移动,拷贝
int nowStrLen = mystrlen(string->p); //获取当前字符串长度
int moveStrLen = mystrlen(pos); //求出现在要移动的长度
int insertStrLen = mystrlen(str); //要插入的长度 for (int i = nowStrLen; i >= nowStrLen - moveStrLen; i--)
{
string->p[i + insertStrLen] = string->p[i]; //字符移动
}
for (int j = ; j < insertStrLen; j++)
{
string->p[nowStrLen - moveStrLen + j] = str[j]; //赋值拷贝
}
}
else
{
mystrcat(string->p, str); //拷贝字符串
}
} //-----------------------------------//改(字符/字符串)-------------------------------------------------
//修改字符
void changeFirstChar(myString *string, const char oldChar, const char newChar)
{
char *pstr = string->p;
while (*pstr != '\0')
{
if (*pstr == oldChar) //查找
{
*pstr = newChar; //赋值
return;
}
pstr++;
}
} //修改字符串
void changeFirstStr(myString *string, char * const oldStr, char * const newStr)
{
char *pfind = findFirstStr(string, oldStr); //找到位置
if (pfind != NULL)
{
delFirstStr(string, oldStr); //删除
addStr(string, newStr, pfind); //插入
}
} void main()
{
myString str1;
initWithString(&str1,"note"); printString(&str1); //note /* 测试一:****************************************************************/
//backAddChar(&str1, 'd');
//printString(&str1); //noted
//run(&str1); //backAddStr(&str1, "pad");
//printString(&str1); //notepad
//run(&str1); /* 测试二:****************************************************************/
//backAddStr(&str1, "pad");
//printString(&str1); //notepad
//char *strp = findFirstChar(&str1, 'a');
//*strp = 'A';
//printString(&str1); //notepAd //backAddStr(&str1, "pad");
//printString(&str1); //notepad
//char *strp = findFirstStr(&str1, "te");
//*strp = 'X';
//printString(&str1); //noXepad //backAddStr(&str1, "pad");
//printString(&str1); //notepad
//char *strp = findFirstStr(&str1, "ad");
//*strp = 'X';
//printString(&str1); //notepXd //backAddStr(&str1, "pad");
//printString(&str1); //notepad
//char *strp = findFirstStr(&str1, "ada");
//if (strp != NULL)
//{
// *strp = 'X';
//}
//printString(&str1); //notepad(并没有改变,没有找到相应子串) /* 测试三:****************************************************************/
//backAddStr(&str1, "pad");
//printString(&str1); //notepad
//delFirstChar(&str1,'e');
//printString(&str1); //notpad //backAddStr(&str1, "padnotepad");
//printString(&str1); //notepadnotepad
//delFirstStr(&str1, "pad");
//printString(&str1); //notenotepad /* 测试四:****************************************************************/
//backAddStr(&str1, "padnotepad");
//printString(&str1); //notepadnotepad
//char *p = findFirstChar(&str1, 't');//查找第一个t的位置
//if (p != NULL)
//{
// addChar(&str1, 'A', p); //在p的前面位置插入'A'
//}
//printString(&str1); //noAtenotepa //backAddStr(&str1, "padnotepad");
//printString(&str1); //notepadnotepad
//char *p = findFirstChar(&str1, 't');//查找第一个t的位置
//if (p != NULL)
//{
// addStr(&str1, "12345", p); //在p的前面位置插入'A'
//}
//printString(&str1); //no12345tepadnotepad /* 测试五:****************************************************************/
//backAddStr(&str1, "padnotepad");
//printString(&str1); //notepadnotepad
//changeFirstChar(&str1, 'a', 'i');
//printString(&str1); //notepidnotepad backAddStr(&str1, "padnotepad");
printString(&str1); //notepadnotepad
changeFirstStr(&str1, "notepad", "");
printString(&str1); //123456789notepad system("pause");
return ;
}

1. C/C++项目一的更多相关文章

  1. Fis3前端工程化之项目实战

    Fis3项目 项目目录结构: E:. │ .gitignore │ fis-conf.js │ index.html │ package.json │ README.md │ ├─material │ ...

  2. 【原】Android热更新开源项目Tinker源码解析系列之三:so热更新

    本系列将从以下三个方面对Tinker进行源码解析: Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Android热更新开源项目Tinker源码解析系列之二:资源文件热更新 A ...

  3. 最近帮客户实施的基于SQL Server AlwaysOn跨机房切换项目

    最近帮客户实施的基于SQL Server AlwaysOn跨机房切换项目 最近一个来自重庆的客户找到走起君,客户的业务是做移动互联网支付,是微信支付收单渠道合作伙伴,数据库里存储的是支付流水和交易流水 ...

  4. Hangfire项目实践分享

    Hangfire项目实践分享 目录 Hangfire项目实践分享 目录 什么是Hangfire Hangfire基础 基于队列的任务处理(Fire-and-forget jobs) 延迟任务执行(De ...

  5. Travis CI用来持续集成你的项目

    这里持续集成基于GitHub搭建的博客为项目 工具: zqz@ubuntu:~$ node --version v4.2.6 zqz@ubuntu:~$ git --version git versi ...

  6. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  7. 【原】Android热更新开源项目Tinker源码解析系列之二:资源文件热更新

    上一篇文章介绍了Dex文件的热更新流程,本文将会分析Tinker中对资源文件的热更新流程. 同Dex,资源文件的热更新同样包括三个部分:资源补丁生成,资源补丁合成及资源补丁加载. 本系列将从以下三个方 ...

  8. Angular企业级开发(5)-项目框架搭建

    1.AngularJS Seed项目目录结构 AngularJS官方网站提供了一个angular-phonecat项目,另外一个就是Angular-Seed项目.所以大多数团队会基于Angular-S ...

  9. 【分享】标准springMVC+mybatis项目maven搭建最精简教程

    文章由来:公司有个实习同学需要做毕业设计,不会搭建环境,我就代劳了,顺便分享给刚入门的小伙伴,我是自学的JAVA,所以我懂的.... (大图直接观看显示很模糊,请在图片上点击右键然后在新窗口打开看) ...

  10. ABP入门系列(2)——通过模板创建MAP版本项目

    一.从官网创建模板项目 进入官网下载模板项目 依次按下图选择: 输入验证码开始下载 下载提示: 二.启动项目 使用VS2015打开项目,还原Nuget包: 设置以Web结尾的项目,设置为启动项目: 打 ...

随机推荐

  1. SpringMVC 接收表单数据的方式

    1.@RequestParam @RequestMapping(value = "/xxxx.do") public void create(@RequestParam(value ...

  2. Oracle11gR2--SEC_CASE_SENSITIVE_LOGON参数解析

    在Oracle的11g之前的版本中密码是不区分大小写的(使用双引号强制除外). 在Oracle的11g以及以后的版本中对此有所增强.从此密码有了大小写的区分. 这个大小写敏感特性是通过SEC_CASE ...

  3. 【Dubbo学习】

    dubbo的介绍 dubbo是一个分布式的开源框架,其核心部分如下: 1.服务提供者:provider 2.服务消费者:consumer 3.注册中心:registry (仅仅只是负责通知) 服务者在 ...

  4. BP算法在minist数据集上的简单实现

    BP算法在minist上的简单实现 数据:http://yann.lecun.com/exdb/mnist/ 参考:blog,blog2,blog3,tensorflow 推导:http://www. ...

  5. scala 在vim中的语法高亮

    https://github.com/derekwyatt/vim-scala 提供了一个选择 看install手册,发现两个命令都是必须的. mkdir -p ~/.vim/{ftdetect,in ...

  6. 在zookeeper集群的基础上,搭建solrCloud

    1 将在window中部署的单机版solr上传到node-01中 cd /export/software/ rz 选择资料中的solr.zip进行上传(此zip就是  solr的简单部署:在tomca ...

  7. 解决nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)

    nginx先监听了ipv4的80端口之后又监听了ipv6的80端口,于是就重复占用了.更加坑人的是你去看了端口占用它又把80端口释放了,是不是很囧. 解决方案是编辑nginx的配置文件 修改这一段:

  8. 关于PHP的一个坑爹问题(页面刷新)

    最近在用PHP做一个服务端和一个客户端,在快要完工的时候,出现了一个重大问题---- 当在客户端手动输入IP和端口的时候,一按连接,OK,连接成功,嘻嘻,就在我自以为大功告成的时候,来了个晴天霹雳,一 ...

  9. ROW_NUMBER分页

    var query = string.Format("SELECT {0} FROM (SELECT ROW_NUMBER() OVER (ORDER BY {3}) AS RowNum, ...

  10. LightOJ 1248 Dice (III) (水题,期望DP)

    题意:给出一个n面的色子,问看到每个面的投掷次数期望是多少. 析:这个题很水啊,就是他解释样例解释的太...我鄙视他,,,,, dp[i] 表示 已经看到 i 面的期望是多少,然后两种选择一种是看到新 ...