目录
一、字符串函数
1.求字符串长度——strlen
模拟实现
2.字符串拷贝函数——strcpy/strncpy
3.字符串追加函数——strcat/strncat
4.字符串比较函数——strcmp/strncmp
5.字符串查找函数——strstr
6.字符串分割函数——strtok
二、内存操作函数
1.内存拷贝函数——memcpy
2.内存移动函数——memmove
3.内存比较函数——memcmp
4.内存设置函数——memset
编辑
一、字符串函数
1.求字符串长度——strlen
1)字符串'\0'作为结束标志,strlen函数返回的是在字符串中'\0'前出现的字符个数(不包含'\0')。
2)当字符串不以'\0'结尾时,将输出一个随机值(系统越界访问直到找到'\0'字符为止)。
3)size_of 是无符号整型。所以两个strlen的结果直接相减得到的也是无符号整型,所以即使是负数也被认为是正数。
模拟实现
size_t my_strlen(char* s)
{
size_t ret = 0;
while (s[ret++] != '\0');
return ret - 1;
}
int main()
{
char s[] = "hello world!";
printf("库函数:%zd\n", strlen(s));
printf("模拟实现:%zd\n",my_strlen(s));
return 0;
}
2.字符串拷贝函数——strcpy/strncpy
对于strcpy:
1)源字符串必须以'\0'结束,strcpy执行到'\0'字符停止。
2)源字符串中的'\0'也会被拷贝到目标空间。
3)目标空间应该足够大以存放源字符串。
4)目标空间必须可变。(避免向dest传字符串常量参数)
char* my_strcpy(char* dest, char* src)
{
assert(dest && src);
char* ret = dest;
while (*(dest++) = *(src++));
return ret;
}
int main()
{
char arr1[] = "Hello world!";
char arr2[20] = "";
printf("arr1:%s\narr2:%s\n",arr1,my_strcpy(arr2,arr1));
return 0;
}
对于strncpy:
1)多了一个num参数,表示要拷贝的字节个数。
2)如果源字符串的长度小于num,则拷贝完源字符串后,在后面追加'\0'直到num个。
3)需要注意strncpy在拷贝结束时不会自动补‘\0’。
char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* ret = dest;
while (num--)
{
if (*src == '\0')
{
*(dest++) = '\0';
}
else
{
*(dest++) = *(src++);
}
}
return ret;
}
3.字符串追加函数——strcat/strncat
对于strcat:
1)源字符串必须以'\0'结束,strcat从目标字符串的'\0'开始,执行到源字符串的'\0'字符停止。
2)源字符串中的'\0'也会被追加到目标空间。
3)目标空间应该足够大以容纳追加的源字符串。
4)目标空间必须可变。
5)不可以给自己追加。给自己追加会使得src和dest两个字符串同时改变,找不到'\0'而死循环。
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest != '\0')
dest++;
while (*dest++ = *src++);
return ret;
}
对于strncat:
1)追加结束后会自动补一个'\0'。
2)当指定追加字节大于源字符串总长度时,追加到末尾‘\0’处结束。
char* my_strncat(char* dest, char* src, size_t num)
{
assert(dest && src);
char* ret = dest;
while (*dest != '\0')
{
dest++;
}
while (num--)
{
if (!(*dest++ = *src++))
return ret;
}
if (num == 0);
{
*dest = '\0';
}
return ret;
}
4.字符串比较函数——strcmp/strncmp
对于strcmp:
比较两个字符串是否相等(首字母)。
若str1>str2,返回大于0的数;若str1<str2,返回小于0的数;若str1=str2,返回0 。
int my_strcmp(const char* e1, const char* e2)
{
assert(e1 && e2);
while (*e1 == *e2)
{
if (*e1 == '\0')
return 0;
else
{
e1++;
e2++;
}
}
return *e1 - *e2;
}
对于strncmp:
比较两个字符串是否相等(首字母),比较num个字符。
若str1>str2,返回大于0的数;若str1<str2,返回小于0的数;若str1=str2,返回0 。
5.字符串查找函数——strstr
查找一个字符串中是否存在指定的子字符串。若存在,返回第一个找到的子字符串在原字符串中的首字符位置;若不存在,则返回一个空指针。
char* my_strstr(const char* s1, const char* s2)
{
assert(s1 && s2);
char* ret = s1;
while (*s1 != '\0')
{
int cur = 0;
while (*s1 != *s2)
{
s1++;
}
while (s1[cur] == s2[cur])
{
cur++;
if (s2[cur] == '\0')
return s1;
}
s1++;
}
return NULL;
}
6.字符串分割函数——strtok
1)后一个参数是个字符串,内容为将要用作分隔符的字符的集合。
2)第一个参数为指定的字符串(可包含0个或多个分隔符)。
3)strtok函数找到str的下一个分隔符后,将其用'\0'结尾,返回一个指向这个'\0'前字符串首字符的指针。(strtok函数会改变被操作的字符串)
4)对于一个字符串第一次调用strtok函数,第一个参数不为NULL,函数找到字符串中第一个标记,并保存。
5)对同一个字符串再次调用strtok函数,第一个参数为NULL,函数将从保存的上次标记处开始,查找下一个标记。
6)如果字符串中不存在更多的标记,则返回NULL指针。
int main()
{
char arr[] = "lang1940629384@mail.nwpu.edu.cn";
char* p = "@.";
char buf[1024] = {0};
strcpy(buf,arr);
char* ret = NULL;
for(ret = strtok(arr,p);ret != NULL;ret = strtok(NULL,p))
{
printf("%s\n",ret);
}
return 0;
}
//output:
// lang1940629384
// mail
// nwpu
// edu
// cn
二、内存操作函数
1.内存拷贝函数——memcpy
1)函数从source的位置开始向后复制num个字节的数据到destination指向的内存位置。
2)函数不会因为遇到'\0'而停止,而是一直执行直到操作过num个字节的数据为止。
3)如果source与destination有拷贝过程中不应该有重叠。
void* my_memcpy(void* dest, const void* src, size_t size)
{
assert(dest && src);
while (size--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
2.内存移动函数——memmove
拷贝内存中储存的数据,功能与memcpy相同。二者区别在于memmove考虑重叠对象的问题,而memcpy不考虑该情况。
void* my_memmove(void* dest, const char* src, size_t size)
{
assert(dest && src);
if (dest > src)
{
dest = (char*)dest + size - 1;
src = (char*)src + size - 1;
while (size--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
else
{
while (size--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
}
3.内存比较函数——memcmp
用于比较从ptr1和ptr2指针开始的num个字节。若小于返回负数,大于返回正数,相等返回0 。
4.内存设置函数——memset
设置指定内存空间内为指定字符。即将ptr指针指向的位置开始num个字节内容变为指定值value。