需求: 使用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. Windows + Ubuntu 双系统安装

    前言:本篇文章是对之前文章的更新,更新的主内容是把原来用手机拍摄的图片换成了虚拟机的截图,以及对磁盘划分的新的见解和一些使用感受,原本是打算删除之前的那篇Win + Ubuntu双系统的文章的,后来想 ...

  2. Win8.1(64bit) Hyper-V 安装Ubuntu 14.04LTS(64 bit)

    为了学习在Linux平台下开发,时隔将近一年多,重新搭建开发环境. 写文档确实很费时间,不过还是很有必要写的,这么一个简单的事情花了接近3个小时才算最终大功告成. 像这种连环嵌套的问题,一旦超过了1个 ...

  3. sql代码段添加数据

      declare @i int,@index int     set @i=1     set @index=0   while @i<1000000   begin    set @inde ...

  4. 【技术调研】最强Node-RED初探总结

    在某个项目中需要调研下node-red的功能,我大概花了三天时间研究了相关的官方文档,写了几个Demo总结了下node-red相关的功能.如需转载,请注明出处 https://www.cnblogs. ...

  5. spark编译安装 spark 2.1.0 hadoop2.6.0-cdh5.7.0

    1.准备: centos 6.5 jdk 1.7 Java SE安装包下载地址:http://www.oracle.com/technetwork/java/javase/downloads/java ...

  6. JAVA基础知识总结16(IO流)

    IO流:用于处理设备上数据. 流:可以理解数据的流动,就是一个数据流.IO流最终要以对象来体现,对象都存在IO包中. 流也进行分类: 1:输入流(读)和输出流(写). 2:因为处理的数据不同,分为字节 ...

  7. SpringBoot RestController 同时支持返回xml和json格式数据

    @RestController 默认支持返回json格式数据,即使不做任何配置也能返回json数据 当接口需要支持xml或json两种格式数据时应该怎么做呢? 只要引入 Jackson xml的 ma ...

  8. Linux xclip命令

    一.简介 xclip命令建立了终端和剪切板之间通道,可以用于以命令的方式将终端输出或文件的内容保存到剪切板中,也可以用于将剪切板的内容输出到终端或文件中. 在 X 系统里面,从一个窗口复制一段文字到另 ...

  9. zlib编程

    一.简介 zlib是提供数据压缩用的函式库,使用DEFLATE算法,最初是为libpng函式库所写的,后来普遍为许多软件所使用,今天,zlib是一种事实上的业界标准.   二.基本信息 数据头(hea ...

  10. python之连接oracle数据库

    环境: windows,python2.7 1.下载cx_Oracle 在windows下不要使用easy_install或者pip,因为这样安装不会同步环境,并报错: distutils.error ...