需求: 使用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. vmware 仅主机模式 ip配置

    首先关闭防火墙 主机(宿主机器 win7) 虚拟机(xp) 3..重要提示:  如果ping不通首先考虑防火墙的问题!!! vmware配置: nat模式下玩耍: 1. 配置nat的虚拟网卡:  2. ...

  2. centos6下的安装navicat premium

    centos6下的安装navicat premium CentOS6下做开发的时候,数据库客户端是一个必须要有的工具,因为经常要和数据库打交道.由于数据库的类型多样,有MySQL.Oracle.Pos ...

  3. T-SQL 理解SQL SERVER中的分区表(转)

    转载来源一定要明显:  http://www.cnblogs.com/CareySon/archive/2011/12/30/2307766.html 而且这个大神对于数据库方面的文章非常棒 强烈推荐 ...

  4. java Web JSTL介绍及基本应用

    由于实际开发中我们一般不能在jsp页面上写java代码,而el表达式也做不了判断 循环之类的复杂操作,为了弥补这些缺点,所以就有了JSTL. 简介 JavaServer Pages Standard ...

  5. cocos+kbe问题记录

    1.不要使用setTimeout函数 setTimeout函数,setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式. 是HTML DOM中的方法,在游戏中使用,属于全局的延时,当游 ...

  6. oracle 创建表 外键约束

    create table usertable( id int primary key, username ) not null, birthday date, sex ), address ) ); ...

  7. 数字图像处理实验(10):PROJECT 05-01 [Multiple Uses],Noise Generators 标签: 图像处理MATLAB 2017-05-26 23:36

    实验要求: Objective: To know how to generate noise images with different probability density functions ( ...

  8. 洛谷P2569 [SCOI2010]股票交易

    P2569 [SCOI2010]股票交易 题目描述 最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律. 通过一段时间的观察,lxhgww预测到了未来T天内某只股 ...

  9. HUSTSE2017级5班3组小组JIRA软件使用体验看法汇总--未订正版

    小组JIRA软件使用体验看法汇总 小黄 JIRA还是比较方便的,在项目组合管理阶段,可以让团队同时按时发布,也可以让计划变得更容易和快捷,可以跟踪团队的重要计划,清楚的了解项目的进度. 看了JIRA的 ...

  10. Eclipse工具

    1 ArrayList的常见方法 * a: add(参数) 向集合中添加元素 * b: get(int index) 取出集合中的元素,get方法的参数,写入索引 * c: size() 返回集合的长 ...