C语言_删除字符函数中的字符处理函数

iOS学习、交流、进步
C语言中字符和字符串的处理函数总结
1. 字符输出函数putchar()
调用格式:putchar(c)
向终端输出一个字符,c可以是一个字符变量或字符常量、整形变量、整形常量或转义字符。
2. 字符输入函数getchar()
调用格式: getchar();
从终端输入一个字符。当程序执行到getchar()函数时,将等待用户从键盘上输入一个字符,并将字符作为函数结果值返回。getchar()函数没有参数。
3. 字符串输出函数puts()
调用格式:puts(字符数组名);
将一个以’\0’结束的字符串输出到显示器上,输出时将’\0’置换成’\n’,输出字符串后换行。
4. 字符串输入函数gets()
调用格式:gets(字符数组);
从键盘上输入一个字符串到字符数组中,以按[Enter]键结束字符串输入,并将其转换为’\0’存入字符串尾部。函数的返回值是字符数组的首地址。
5. 字符串连接函数strcat()
调用格式:strcat(字符数组1,字符数组2或字符串常量)
将字符数组2或字符串常量连接到字符数组1的后面,函数de返回值是字符数组1的首地址。
6. 字符串复制函数strcpy()
调用格式:strcpy(字符数组1,字符数组2或字符串常量)
将字符数组2或字符串常量复制到字符数组1中,连同结束标志’\0’也一起复制,字符数组中原来的内容被覆盖。函数的返回值是字符数组1的首地址。
7. 字符串比较函数strcmp()
调用格式:strcmp(字符串1,字符串2)
比较两个字符串的大小。规则:对两个字符串中的字符从左至右逐个比较其ASCII码值,直到出现第一个不同的字符或遇到’\0’为止。若两个字符串全部字符相同,则认为相等;若出现不相同的字符,则以第一个不相同的字符的比较结果为准。函数的返回值是第一个不同ASCII码值的差值,有以下三种取值:
字符串1=字符串2,函数值为0;
字符串1&字符串2,函数值为大于0的整数;
字符串1&字符串2,函数值为小于0的整数。
8. 字符串长度测试函数strlen()
调用格式:strlen(字符数组或字符串常量)
测试字符数组或字符串常量的实际长度(不含结束标志’\0’),并返回字符数组或字符串常量的长度。
9. 大写字母转小写字母函数strlwr()
调用格式:strlwr(字符串)
将字符串中的大写字母转小写字母。
10. 小写字母转大写字母函数strupr()
调用格式:strupr(字符串)
将字符串中的小写字母转大写字母。
没有更多推荐了,在讨论着四种方法之前,首先要对函数有一个简单的认识,无论是在形实结合时,还是在return语句返回时,都有一个拷贝的过程。你传进来的参数是个值,自然函数在工作之前要把这个值拷贝一份供自己使用,你传进来的是个地址,函数也就会拷贝该地址供自己使用。同样return返回时,如果返回一个值,函数会将该值拷贝一份以提供给主调函数使用,返回的是一个指针(也就是地址),自然拷贝的就是一个地址,供主调函数使用。
先给出一个错误的例子:
#include &stdio.h&
#include &string.h&
char * retstring();
int main()
char * name2;
name2 = retstring();
printf("%s\n",name2);
return <span style="color: #;
char * retstring()
char name[<span style="color: #];
strcpy(name,"汉青");
编译一下代码,会发现提示一个警告,大概意思就是说返回了一个局部变量的地址。这个程序的输出结果是不确定的,因为我们都知道,局部变量的生存期是就在块内部,这里也就是在函数retstring()的内部,在main函数中,name的内存空间已经被回收。
所以不能返回一个自动变量的字符串。。。
下面给出四种返回字符串的方法:
1、 将字符串指针作为函数参数传入,并返回该指针。
2、 使用malloc函数动态分配内存,注意在主调函数中释放。
3、 返回一个静态局部变量。
4、 使用全局变量。
下面是详细解释:
方法一:将字符串指针作为函数参数传入,并返回该指针。
典型的strcpy()函数应该就是采用的这种方法,第一个参数为指向目的字符串的指针,返回值也为这个指针。
char* strcpy(char* des,const char* source)
assert((des != NULL) && (source != NULL));
 while((*r++ = *source++)!='\0');
方法二:使用malloc函数动态分配,但是一定要注意在主调函数中将其释放,应为malloc动态分配的内存位于堆区,而堆区的内存是要程序员自己释放的。
一个例子如下:
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
char * retstring();
int main()
char * name2;
name2 = retstring();
printf("%s\n",name2);
//记住一定要用free释放,否则会造成内存泄露
free(name2);
return <span style="color: #;
char * retstring()
name = (char *)malloc(<span style="color: #);
strcpy(name,"张汉青");
方法三:返回一个静态局部变量。
一个例子如下:
#include &stdio.h&
#include &string.h&
#include &stdlib.h&
char * retstring();
int main()
char * name2;
name2 = retstring();
printf("%s\n",name2);
return <span style="color: #;
char * retstring()
static char name[<span style="color: #];
strcpy(name,"张汉青");
这种方法有一个问题: 由于采用了静态局部变量(位于静态区,程序结束时由系统进行释放),这就导致,如果多次调用这个函数,下一次调用会将上一次调用的结果覆盖掉。
C语言中的库函数,tmpnam()函数、getenv()函数等应该都是采用的这种方法,这也就是为什么,使用这样的函数的时候应该立即将返回结果拷贝一份的原因。
方法四: 使用全局变量。
一个例子如下:
g_s[<span style="color: #0];
strcpy(g_s,
参考了:http://blog.csdn.net/turkeyzhou/article/details/6104135#comments
就写到这里啦,希望对你有所帮助。。有错误的地方还请指正,谢谢~~
阅读(...) 评论()C语言中的string.h中的内存字符串处理函数 - 夕阳飞飞 - 博客园
随笔 - 47, 文章 - 0, 评论 - 1, 引用 - 0
转载请注明出处:http://blog.csdn.net/zhubin215130/article/details/8993403
void *memcpy(void *dest, const void *src, size_t n);
从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中.
void *memmove( void* dest, const void* src,size_t count);
由src所指内存区域复制count个字节到dest所指内存区域。memmove用于从src拷贝count个字符到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。但复制后src内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
void *memset(void *s, int ch, size_t n);
将s中前n个字节(typedef unsigned int size_t)用ch替换并返回s。memset作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法.
int&memcmp(const void *buf1, const void *buf2, unsigned int count);
比较内存区域buf1和buf2的前count个字节。当buf1&buf2时,返回值&0当buf1=buf2时,返回值=0当buf1&buf2时,返回值&0
extern char *strcpy(char* dest, const char *src);
把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间.src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。
char *&strncpy(char *dest, char *src,size_t num);
复制src中的内容(字符,数字、汉字....)到dest,复制多少由num的值决定,返回指向dest的指针。如果遇到null字符('\0'),且还没有到num个字符时,就用(num - n)(n是遇到null字符前已经有的非null字符个数)个null字符附加到destination。
extern char *strcat(char *dest,char *src);
把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。
extern char *strncat(char *dest,char *src,int n);
把src所指字符串的前n个字符添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'。src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。返回指向dest的指针。
extern int&strcmp(const char *s1,const char * s2);
比较字符串s1和s2。当s1&s2时,返回值&0当s1==s2时,返回值=0当s1&s2时,返回值&0即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。
int&strncmp(char *str1, char *str2, int maxlen);
此函数功能即比较字符串str1和str2的前maxlen个字符。
如果前maxlen字节完全相等,返回值就=0;
在前maxlen字节比较过程中,如果出现str1[n]与str2[n]不等,则返回(str1[n]-str2[n])。
int&strcasecmp&(const char *s1, const char *s2);
strcasecmp()用来比较参数s1和s2字符串,比较时会自动忽略大小写的差异。
若参数s1和s2字符串相等则返回0。
s1大于s2则返回大于0 的值。
s1 小于s2 则返回小于0的值。
int&strncasecmp(const char *s1, const char *s2, size_t n)
strncasecmp()用来比较参数s1和s2字符串前n个字符,比较时会自动忽略大小写的差异,
若参数s1和s2字符串相同则返回0&
s1若大于s2则返回大于0的值
s1若小于s2则返回小于0的值.
extern char *strchr(const char *s,char c);
查找字符串s中首次出现字符c的位置,返回首次出现c的位置的指针,如果s中不存在c则返回NULL。
extern unsigned int&strlen(char *s);
计算字符串s的(unsigned int型)长度,不包括'\0'在内.返回s的长度,不包括结束符NULL。1 字符串基础
字符串是一种重要的数据类型,有零个或多个字符组成的有限串行。
定义子串: 串中任意个连续的字符组成的子序列,并规定空串是任意串的子串,任意串也是其自身的子串,如字符串&adereegfb&中它本身、空串、诸如&ader&连续的字符串都是它的子串。子序列则不要求字符连续,但顺序要与主串保持一致,若有&abcd&与&ad&则两者的最长公共子序列为&ad&。在动态规划中计算最长公共子序列和最长公共子串中一定要能区分这两个概念!
在C语言中并没有显示的字符串类型,它有如下两种风格的字符串:
字符串常量: 以双引号扩起来的字符序列,规定所有的字符串常量都由编译器自动在末尾添加一个空字符
字符数组: 末尾添加了'\0'的字符数组,一般需要显示在末尾添加空字符。
char c1[]={&#39;c&#39;,&#39;+&#39;,&#39;+&#39;}; //末尾没有空字符
char c2[]={&#39;c&#39;,&#39;+&#39;,&#39;+&#39;,&#39;\0&#39;}; //末尾显示添加空字符
char c3=&c++&; //末尾自动添加空字符
注意到通过字符数组初始化和字符串常量初始化并不完全相同的。因为字符串常量包含一个额外的空字符用于结束字符串,用它来初始化创建数组时,末尾会自动添加空字符。所以c1的长度是3,后两者的长度是4,并且字符数组c2和c3都被称为C风格字符串,而字符数组c1不是C风格字符串。
规定C风格的字符串都是以NULL空字符('\0')作为终结符结尾。由于它是字符串的终止符,但它本身并不是字符串的一部分,所以字符串的长度并不包括NULL字节,如strlen函数。而且C标准库中提供的各种字符串处理函数都要求提供的字符串或字符数组必须以空字符结束,否则会出现不可预料的结果。如:
char c[]={&#39;c&#39;,&#39;+&#39;,&#39;+&#39;};
printf(&%d\n&,strlen(c)); //结果输出为6,这是不正确的
2 标准库中的字符串处理函数
C标准库中头文件&string.h&定义了两组字符串函数(C++中用&string&表示)。
第一组函数的名字以str开头,它主要处理以'\0'结尾的字符串,所以字符串内部不能包含任何'\0'字符。
第二组函数的名字以mem开头,主要考虑非字符串内部含有零值的情形,它能够处理任意的字节序列,操作与字符串函数类似
除了memmove函数外,其他函数都没定义重叠对象间的行为
为了提高程序在不同机器上的移植性,利用typedef定义新类型名,即typedef unsigned int size_t。 程序员必须要保证目标字符数组的空间能够足以存放结果字符串(有可能存在字符数组溢出的危险)
字符串处理类
如下表为字符串处理函数说明,变量s,t的类型是char *, cs和ct的类型是const char *;n的类型为size_t,c的类型为int。
内存操作类
按照字节数组的方式操作对象,提供一个高效的函数接口(提供字节流的访问)。其中s,t类型是void * , cs,ct的类型是const void *; n类型为size_t,c类型为int。
总结起来,头文件& string.h&实现了如下函数:
长度计算、长度不受限和受限的复制、连接和比较版本的函数
基础字符串查找(查找一个字符、一组字符和匹配一个子串)、高级字符串查找(查找子串前缀位置、返回token标记)
处理任意字节序列的内存操作如复制、比较、查找和初始化等函数
2.1 手写字符串处理函数
A strlen/strcmp/strcpy/strcat等函数
代码实现和测试如下:
#include &stdio.h&
#include &assert.h&
#include &stdlib.h&
#include &string.h&
#include &stdbool.h&
/***********************************
* 基本的字符串函数
* strlen/strcmp/strcpy/strcat/strncmp/strncpy/strncat
* strdup/strrev
* atoi/strtod
**********************************/
size_t my_strlen(const char *src) {
assert(src != NULL);
int len = 0;
while(*src++ != &#39;\0&#39;) {//函数退出条件是src=&#39;\0&#39;但之后还进行了自增运算
// const char *psrc =
// while(*psrc++ != &#39;\0&#39;) ;
// return psrc - src - 1;
* 切记不可用*s++ == *t++
* 因为不相等时时还会继续比较一次,自增运算应放在循环体内
int my_strcmp(const char *s,const char *t) {
assert(s != NULL && t != NULL);
while(*s == *t) {
if(*s == &#39;\0&#39;)
// return ((*(unsigned char *)s & *(unsigned char *)t) & 0)? 1: -1;
return ((*s - *t) & 0)?1:-1;
int my_strncmp(const char *s,const char *t,size_t n) {
assert(s != NULL && t != NULL);
while(n-- && *s == *t) { //条件用n判断但之后n减少了1
if(n == 0 && *s == *t)
return ((*s - *t) & 0)? 1: -1;
* 要求src和dst不重叠,且dst有足够空间
char *my_strcpy(char *dst,const char *src) {
if(src == dst) return
assert(src != NULL && dst != NULL);
char *pdst =
while(*pdst++ = *src++);
//*pdst = &#39;\0&#39;; //该代码可以忽略
char *my_strncpy(char *dst,const char *src,size_t n) {
assert(src != NULL && dst != NULL);
char *pdst =
while(n-- & 0 && *src != &#39;\0&#39;)
*pdst++ = *src++;
*pdst = &#39;\0&#39;; //切记勿忘
char *my_strcat(char *dst,const char *src) {
assert(src != NULL && dst != NULL);
char *pdst =
while(*pdst) pdst++;
while((*pdst++ = *src++) != &#39;\0&#39;);
//*pdst = &#39;\0&#39;; //该行可以忽略
char *my_strncat(char *dst,const char *src,size_t n) {
assert(src != NULL && dst != NULL);
char *pdst =
while(*pdst) pdst++ ;
while(n-- && (*pdst++ = *src++)) ;
*pdst = &#39;\0&#39;;
/*字符串拷贝到新位置,需要配合free使用*/
char *my_strdup(const char *src) {
if(src == NULL) return NULL;
/*先计算字符串长度*/
size_t len = my_strlen(src);
char *new_addr = malloc(len + 1);
char *res = new_
while((*new_addr++ = *src++) != &#39;\0&#39;);
// char *str = my_strdup(&hello world!&);
// printf(&%s\n&,str);
// free(str);
char *my_strrev(char *src) {
assert(src != NULL);
char *t = src + my_strlen(src) - 1;
while(s & t) {
// char s[] = &hello&;
// printf(&%s\n&,my_strrev(s)); //不能使用字符串,因为字符串是常量,无法修改
* 字符串转整数即atoi
* 如果第一个非空格字符存在,从数字或者正负号开始做类型转换,
* 检测到非数字或者结束符时停止转换返回相应整数;否则溢出时就返回0
* 判断字符串是不是数字,类似于strtod
int my_atoi(const char *src) {
const char *p =
while(*p && (*p == &#39; &#39; || *p == &#39;\t&#39; || *p == &#39;\n&#39;) ) p++;
long long res = 0;
bool flag =
bool valid =
if(*p == &#39;+&#39;)
else if(*p == &#39;-&#39;) {
/*检测到非数字字符时停止转换,返回整形数否则返回0*/
for(;*p && (*p &= &#39;0&#39; && *p &= &#39;9&#39;);p++) {
int sign = (flag == true)?-1:1;
res = res * 10 + sign * (*p - &#39;0&#39;);
if((flag && res & 0x) || (!flag && res & 0x7fffffff)) {
if(*p == &#39;\0&#39;) {
return (int)
void test() {
if(my_strlen(&&) == strlen(&&))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strlen(&hello&) == strlen(&hello&))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strlen(&hello world&) == strlen(&hello wrold&))
printf(&test successful!\n&);
printf(&test failed\n&);
void test1() {
if(my_strcmp(&3357&,&3367&) == strcmp(&3357&,&3367&))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strcmp(&hello&,&hi&) == strcmp(&hello&,&hi&))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strcmp(&help&,&hello&) == strcmp(&help&,&hello&))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strcmp(&help&,&help&) == strcmp(&help&,&help&))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strncmp(&hello&,&hi&,1) == strncmp(&hello&,&hi&,1))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strncmp(&hello&,&hi&,1) == strncmp(&hello&,&hi&,1))
printf(&test successful!\n&);
printf(&test failed\n&);
if(my_strncmp(&help&,&help&,2) == strncmp(&help&,&help&,2))
printf(&test successful!\n&);
printf(&test failed\n&);
void test2() {
char dst[20];
char dst1[20];
//strcmp(my_strcpy(dst,&hello&),strcpy(dst1,&hello&)) == 0;
if(strcmp(my_strncpy(dst,&hello&,3),strncpy(dst1,&hello&,3)) == 0)
printf(&test successful!\n&);
printf(&test failed\n&);
void test3() {
char dst[20] = {&#39;h&#39;,&#39;e&#39;,&#39;\0&#39;};
//strcmp(my_strncat(dst,&world&,3),&hewor&) == 0;
if(strcmp(my_strcat(dst,&world&),&heworld&) == 0)
printf(&test successful!\n&);
printf(&test failed\n&);
int main() {
typedef void (*func)();
func test_func[] = {test,test1,test2,test3};
int len = sizeof(test_func) /sizeof(test_func[0]);
for(int i = 0; i &i++)
test_func[i]();
实现时要注意一个细节,指针的自增运算与循环条件结束的问题。例如为什么在strcat实现中使用该函数遍历到字符串结束符会出现问题。这是因为该语句首先判断*pdst != '\0',不论是否满足条件都会执行指针的自增运算,也就是说都执行到了'\0'字符的下一个位置了,如果还需要利用到尾字符这样就出错了。
再例如while(*s++ = *t++);: 它首先是*s = *t;然后再判断*s != '\0';若满足继续循环,否则退出循环。但是务必注意的是不论继续循环与否接下来要执行s +=1,t += 1;
B 字符串查找函数
有以下几个查找函数:
strchr/strrchr/strspn/strcspn/strpbrk
strstr/strtok
char *my_strchr(const char *src,int ch) {
assert(src != NULL);
const char *psrc =
while(*psrc != &#39;\0&#39; && *psrc != ch) {
return (*psrc == &#39;\0&#39;)? NULL : (char *)
char *my_strrchr(const char *src,int ch) {
if(src == NULL) return NULL;
const char *rsrc =
while(*rsrc!= &#39;\0&#39;) rsrc++;
for(-- *rsrc !=--rsrc) {
if(rsrc == src)
return NULL;
return (char *)
/*BF算法的指针版本*/
char *my_strstr(const char *cs,const char *ct) {
assert(cs != NULL && ct != NULL);
const char *s =
const char *t =
for(; *cs != &#39;\0&#39;;cs++) {
for(s = cs,t =*t != &#39;\0&#39; && *s == *t;s++,t++);
if(*t == &#39;\0&#39;)
return (char *)
return NULL;
/*BF算法的数组版本*/
char *my_strstr1(const char *cs,const char *ct) {
assert(cs != NULL && ct != NULL);
int len1 = my_strlen(cs);
int len2 = my_strlen(ct);
for(int i = 0; i &= len1 - len2;i++) {
int j = 0;
while(j & len2 && cs[i + j] == ct[j]) j++;
if(j == len2)
return (char *)(cs + i);
return NULL;
void get_next(const char *pat,int *next,int n) {
int j = -1;
next[0] = -1;
for(int i = 1; i &i++) {
while(j != -1 && pat[j + 1] != pat[i])
j = next[j]; //回退到匹配尾字符的位置
if(pat[j + 1] == pat[i]) j++;
next[i] = //更新当前位置的next值
int kmp_strstr(const char *src,const char *pat) {
int slen = my_strlen(src);
int plen = my_strlen(pat);
int *next = malloc(sizeof(int) * plen);
get_next(pat,next,plen);
int j = -1;
for(int i = 0; i &i++) {
while(j & -1 && pat[j + 1] != src[i])
j = next[j];
if(pat[j + 1] == src[i]) j++;
if(j == plen - 1) { //表明模式串最后一个字符被匹配
free(next);
return i -
free(next);
return -1;
void test4() {
printf(&%s\n&,my_strstr(&hello&,&ell&));
printf(&%s\n&,my_strstr1(&damnyouif you have passwd&,&ave&));
printf(&%d\n&,kmp_strstr(&hello&,&ell&));
printf(&%d\n&,kmp_strstr(&damnyouif you have passwd&,&ave&));
printf(&%d\n&,kmp_strstr(&hello&,&st&));
在子串匹配的算法中,使用暴力查找算法时间复杂度为O(m*n),KMP算法的时间复杂度为O(m+n)。解释下KMP算法的思路: 先计算next数组(部分匹配表),再基此表在文本串进行查找匹配。
举一个例子,例如模式串ABCDABD不匹配...ABCDABE...。考虑到前六个字符ABCDAB是匹配的,且B的匹配值是2(说明有个前缀和后缀相同,记最长的前缀长度,本例中是后缀串AB和前缀串AB),则文本串中后面的AB无需再次比较了,因为模式串有前缀AB和它匹配,于是模式串移动4位。
那么在KMP算法中这种移位是怎么实现的?
首先我们构造一个next数组,得到该模式串以每个字符结尾其前缀串和后缀串的最长匹配下标。 next数组可转化为给定一个字符数组,求该字符串的最大相等k前缀和k后缀,求出这个最大的k
也就是说我们判断的是pat[j+1](前缀字符)与pat[i](当前字符)是否匹配。这其实是一个动态规划问题,即已知dp[0..i-1]求出dp[i]。即当pat[j+1] == pat[i]时匹配了dp[i]=j+1;不相等呢回退指针看看有没有匹配的字符或者到达不匹配的标志
C memset/memchr/memcmp/memcpy/memmove等函数
内存操作函数是按照字符数组的方式操作对象,注意这几个函数中的size大小均为对应类型的大小乘以元素的个数。下面重点讲述以下几个函数:
memset : 为内存块做初始化工作,一般是在对定义的字符数组初始化为某个字符或者其他类型的默认值。
char buf[10];
memset(buf,&#39;c&#39;,10); //将buf数组中的元素都设置成字符&#39;c&#39;,用法正确
char buf[] = &hello,world&;
memset(buf,&#39;0&#39;,strlen(buf)); //同上,针对字符串用的是strlen
struct record {
char name[16];
//快速清空结构体元素和数组,用法正确
struct record r1;
strcut recodr arr[10];
memset(&r1,0,sizeof(struct record));
memset(&arr,0,sizeof(struct record) * 10);
int a[10];
memset(buf,0,sizeof(int) * 10);//将int数组初始化为0,用法正确但不建议使用,直接初始化
memset(buf,1,sizeof(int) * 10);//用法错误,这是对40个字节进行赋值,并非每个元素是1
可以看到几个特点
初始化字符数组时用strlen,初始化其他类型时用sizeof。这是因为sizeof返回数组或类型为其分配好的空间大小,并不关心里面存储的数据;而strlen值关心存储的数据内容,并且字符串长度不包括结束符
memset一般是用来对较大结构体或数组进行初始化或清除操作,使用对应类型默认值
memcpy : 从源起始位置拷贝n个字节到目标的起始位置,用于复制任意可读写类型的空间。
它不允许两内存区域出现重叠。相比strcpy只能用于复制字符串来说,memcpy是可以复制任何内容;并且它的复制指定了拷贝的字节长度,操作更安全。那么当src和dst以任何形式出现了重叠,就会出现数据覆盖的问题,这样的结果是未定义的,如:
dst目的地址空间在src源地址空间右面(src + n & dst)
src目的地址空间在dst源地址空间右面(dst + n & src)
那么如何处理呢,这就要用到memmove函数了
memmove : 它可以保证源串在被覆盖之前将重叠区域的字节先拷贝到目标区域中(先处理重叠部分即可)。
它的思路是:
若dst小于src有重叠时(dst+n & src),仍从头开始复制
若src小于dst有重叠时(src+n & dst),从尾部开始复制
代码实现如下:
void *my_memset(void *src,int c,size_t n) {
assert(src != NULL);
char *psrc = (char *)
while(n--) {
/*返回c在cs的前n个字符第一次出现的位置,找不到返回NULL*/
void *my_memchr(const void *src,int c,size_t n) {
assert(src != NULL);
char *psrc = (char *)
while(n--) {
if(*psrc == c)
return NULL;
int my_memcmp(const char *cs,const char *ct,size_t n) {
assert(cs != NULL && ct != NULL);
while(n-- && *cs == *ct) {
if(n == 0 && *cs == *ct)
return *cs - *
/*将串src中的n个字符拷贝到dst中,以字节流方式处理,按字符数组的方式操作对象*/
void *my_memcpy(void *dst,const void *src,size_t n) {
assert(src != NULL && dst != NULL);
char *psrc = (char *)
char *pdst = (char *)
while(n--) {
*pdst++ = *psrc++;
void *my_memmove(void *dst,const void *src,size_t n) {
assert(src != NULL && dst != NULL);
char *psrc = (char *)
char *pdst = (char *)
if(dst & src && dst - src & n) {
while(n--) {
*(pdst + n) = *(psrc + n);
while(n--) {
*pdst++ = *psrc++;
void test5() {
char s1[] = &Hello,world!&;
char s2[] = &Hello,worl!&;
if(my_memcmp(s1,s2,sizeof(s2)) == memcmp(s1,s2,sizeof(s2)))
printf(&test successful!\n&);
printf(&test failed\n&);
void test6() {
char str[] = &memmove can be very useful......&;
char str1[] = &memmove can be very useful......&;
if(strcmp(my_memmove(str + 20,str + 15,11),memmove(str1 + 20,str1 + 15,11)) == 0)
printf(&test successful!\n&);
printf(&test failed\n&);
以上为字符串处理的完整实现,如有问题欢迎指正^_^
3 字符串的实际应用
3.1 字符串包含和逆置问题
3.1.1 串的模式匹配算法
3.1.2 字符串移位包含问题
3.1.3 翻转单词中的顺序
3.2 字符串的转换、删除、替换
3.2.1 字符串转换思路
3.2.2 字符串删除思路
3.2.3 字符串的替换
3.2.4 统计字符串次数问题
3.3 字符串的排列、组合
3.3.1 字符串排列
3.3.2 字符串组合
3.3.3 next_perm和prev_perm
3.4 字符串回文问题
3.4.1 最长回文子串
3.4.2 回文分割
3.4.3 最少插入字符
阅读(...) 评论()

我要回帖

更多关于 C语言函数返回字符数组 的文章

 

随机推荐