总结下字符串操作函数,然后自己再实现下,就这样。
1.初始化字符串
#include <string.h>
void *memset(void *s, int c, size_t n);
返回值:和s的指向相同
说明: memset
函数把s
所指的内存地址开始的n
个字节都填充为c
的值。通常c
的值为0,把一块内存区清零。例如定义char buf[10];
,如果它是全局变量或静态变量,则自动初始化为0(位于.bss
段),如果它是函数的局部变量,则初值不确定,可以用memset(buf, 0, 10)
清零,由malloc
分配的内存初值也是不确定的,也可以用memset
清零。
具体的实现:
void * memset(void* buffer, int c, int count)
{
char* pvTo=(char*)buffer;
assert(buffer != NULL);
while(count-->0)
*pvTo++=(char)c;
return buffer;
}
2,求字符串的长度
#include <string.h>
size_t strlen(const char *s);
返回值:字符串的长度
说明:strlen
函数返回s
所指的字符串的长度。该函数从s
所指的第一个字符开始找'\0'
字符,一旦找到就返回,返回的长度不包括'\0'
字符在内。例如定义char buf[]= "hello";
,则strlen(buf)
的值是5,但要注意,如果定义char buf[5] = "hello";
,则调用strlen(buf)
是危险的,会造成数组访问越界。
具体实现代码:
size_t strlen(const char* str)
{
assert(str!=NULL);
int len = 0;
while (*str!='\0') /**< '\0', stop */
{
str++;
len++ ;
}
return len;
}
3.字符串拷贝
#include<string.h>
void *memcpy(void *dest, const void *src, size_t n);
void *memmove(void *dest, const void *src, size_t n);
char *strcpy(char *dest,const char *src);
返回值:dest指向哪,返回的指针就指向哪
memcpy
函数从src
所指的内存地址拷贝n
个字节到dest
所指的内存地址,和strncpy
不同,memcpy
并不是遇到'\0'
就结束,而是一定会拷贝完n
个字节。这里的命名规律是,以str
开头的函数处理以'\0'
结尾的字符串,而以mem
开头的函数则不关心'\0'
字符,或者说这些函数并不把参数当字符串看待,因此参数的指针类型是void *
而非char *
。
memmove
也是从src
所指的内存地址拷贝n
个字节到dest
所指的内存地址,虽然叫move但其实也是拷贝而非移动。但是和memcpy
有一点不同,memcpy
的两个参数src
和dest
所指的内存区间如果重叠则无法保证正确拷贝,而memmove
却可以正确拷贝。假设定义了一个数组char buf[20] = "hello world\n";
,如果想把其中的字符串往后移动一个字节(变成"hhello world\n"
),调用memcpy(buf + 1, buf, 13)
是无法保证正确拷贝的。
memcpy在Linux中的实现:
void *memcpy(void *dest, const void *src, size_t count)
{
char *tmp = dest;
const char *s = src;
while (count--)
*tmp = *s ;
return dest;
}
memmove在使用过程中要注意一下几点:
(1)当源内存的首地址等于目标内存的首地址时,不进行任何拷贝
(2)当源内存的首地址大于目标内存的首地址时,实行正向拷贝
(3)当源内存的首地址小于目标内存的首地址时,实行反向拷贝
具体的实现:
void* memmove(void* dest, const void* src, size_t n)
{
char* d = (char*) dest;
const char* s = (const char*) src;
if (s>d) // start at beginning of s
{
while (n--)
*d++ = *s++;
}
else if (s<d)// start at end of s
{
d = d+n-1;
s = s+n-1;
while (n--)
*d-- = *s--;
}
return dest;
}
strcpy的实现:
char *strcpy(char *strDest, const char *strSrc)
{
assert((strDest!=NULL) && (strSrc !=NULL));
char *address = strDest;
while( (*strDest++ = * strSrc++) != '\0') ;
return address ;
}
4.字符串连接
#include<string.h>
char *strcat(char *dest,char *src);
char *strncat(char *dest, const char *src, size_t n);
把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0',src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串,返回dest的指针
strcat的实现:
char* cb_strcat(char* dst, char* src)
{
assert(src!=NULL);
char* retAddr = dst;
/* --- get last position --- */
while (*dst++ != '\0');
dst--;
while (*dst++ = *src++);
return retAddr;
}
5.字符串比较
#include <string.h>
int memcmp(const void *s1, const void *s2, size_t n);
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
返回值:
负值表示s1小于s2,0表示s1等于s2,正值表示s1大于s2
strcmp的实现:
int strcmp(char* str, char* str2)
{
assert((str!=NULL) && (str2!=NULL));
char* pStr = str;
char* pStr2 = str2;
while (*pStr && *pStr2 && (*pStr==*pStr2))
{
pStr++;
pStr2++;
}
return (*pStr - *pStr2); //相等则为0 , 前者大于后者大于0, 反之小于0
}
strncmp的实现:
int strcmp(char* str, char* str2,size_t size)
{
assert((str!=NULL) && (str2!=NULL));
char* pStr = str;
char* pStr2 = str2;
while (size--&&*pStr && *pStr2 && (*pStr==*pStr2))
{
pStr++;
pStr2++;
}
return (*pStr - *pStr2); //相等则为0 , 前者大于后者大于0, 反之小于0
6.同样是字符/字符串比较
#include <strings.h>
int strcasecmp(const char *s1, const char *s2);
int strncasecmp(const char *s1, const char *s2, size_t n);
忽略大小写的比较,返回值的规则同上
7.字符的匹配
#include <string.h>
char *strchr(const char *s, int c);
char *strrchr(const char *s, int c);
返回值:
如果找到字符c,返回字符串s中指向字符c的指针,如果找不到就返回NULL
8.子串的匹配
#include <string.h>
char *strstr(const char *haystack, const char *needle);
返回值:
如果找到子串,返回值指向子串的开头,如果找不到就返回NULL
char *strstr (char *buf,char *sub)
{
if (!*sub)
return buf;
while (*buf)
{
bp = buf;
sp = sub;
do
{
if (!*sp)
return buf;
} while (*bp++ == *sp++);
buf += 1;
}
return 0;
}
9.分割字符串
待续~~~~