《C语言字符串与内存函数详解与模拟实现》
memove和memcpy的差别就是,memmove函数处理的。通过观察内存,我们可以发现,每个字节都被改成了1。
C语言字符串函数和内存函数
这篇博客我将讲解C语言中常见的字符函数,其中包含strcat、strcmp、strcpy、memcpy、memmove等等一系列的字符串函数和内存函数。
字符串函数
strcat
详解
字符串连接函数
char* strcat(char* dest, const char* src);
参数:
- dest:指向目的地空间。
- src:指向源头数据。
功能:将src追加在dest字符串的末尾。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "shdfks";
char arr2[20] = "fhufkh";
strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
注意事项:
- 源字符串必须以’\0’结束
- 目标字符串也必须有’\0’,否则无法知道追加从哪里开始
- 目标空间必须足够大,能容纳下源字符串的内容
- 目标空间必须可修改
模拟实现
char* My_strcat(char* dest, char* src)
{
assert(dest && src);
char* p = dest;
while (*dest!='\0')
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return p;
}
strcmp
详解
字符串比较函数
int strcmp(const char* str1, const char* str2);
功能:按ASCII码值,逐字符比较两个字符串,直到遇到不同字符或遇到’\0’结束。
返回值:
- 返回0:str1==str2两个字符串完全相等。
- 返回>0(正数):str1>str2第一个不同字符,str1的ASCII更大。
- 返回<0(负数):str1<str2第一个不同字符,str1的ASCII更小。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "fhvfks";
char arr2[20] = "fhufkh";
int p = strcmp(arr1, arr2);
printf("%d\n", p);
return 0;
}
注意事项:
- 按ASCII逐字节比较,第一个不同就停止比较,不是按字符串长度比较。
- 大小写不相等。
- 返回值只看正负和0。
- 不能写 ==1 判断,只能写 >0 ,<0 ,==0判断。
- 字符串必须以’\0’结尾。
模拟实现
int My_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1=='\0')
{
return 0;
}
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
strcpy
详解
字符串拷贝函数
char* strcmp(char*dest, const char* src);
参数:
- dest:指向目的地空间。
- src:指向源头数据。
功能:将src中的内容拷贝到dest中。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[20] = "fhufkh";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
注意事项:
- 从源字符串src逐个字符拷贝到目标dest,连带末尾’\0’一起拷贝。
- 目标数组空间必须足够大,能装下源字符串加上’\0’,不然越界访问。
- 目标空间必须可修改。
- 源字符串必须以’\0’结尾。
- 不能拷贝自己,dest和src空间重叠,结果不可控。
模拟实现
char* My_strcpy(char* dest, char* src)
{
assert(dest && src);
char* p = dest;
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
return p;
}
strstr
详解
字符串查找函数
char* strstr(const char*str1, const char*str2);
功能:查找str2指向的字符串在str1指向的字符串中第一次出现的位置,并返回它的地址。
返回值:
- 找到返回第一次出现的地址。
- 找不到返回NULL。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "bcdefabcdefabcd";
char arr2[20] = "abc";
char* p = strstr(arr1, arr2);
printf("%s\n", p);
return 0;
}
模拟实现
char* My_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* p1 = str1;
const char* p2 = str2;
while (*str1 != '\0')
{
p1 = str1;
p2 = str2;
while (*p1 == *p2)
{
p1++;
p2++;
if (*p2 == '\0')
{
return (char*)str1;
}
}
str1++;
}
return NULL;
}
strtok
详解
字符串分割函数
char* strtok(char* str, const char* delim);
参数:
- str:首次调用时传入待分割的字符串;后续调用传入NULL,表示继续分割同一个字符串。
- delim:包含所有分割符的字符串(每个字符都视为独立的分隔符)。
功能:分割字符串:根据delim参数中指定的分隔符,将输入字符串str拆分成多个子字符串。
返回值:
- 成功时,返回指向当前子字符串的指针。
- 没有更多子字符串时返回NULL。
使用步骤:
- 首次调用:传入待分割字符串和分隔符。
- 后续调用:传入NULL和相同的分隔符,继续分割。
- 结束调用:当返回NULL时,表示分割完成。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hdj.cji@djc.@fjss";
char arr2[5] = { '.','@' };
char buf[20] = { 0 };
strcpy(buf, arr1);
char* p = NULL;
for (p = strtok(buf, arr2);p != NULL;p = strtok(NULL, arr2))
{
printf("%s\n", p);
}
return 0;
}
注意事项:
- 破坏性操作:如果需要保留源字符串,应先拷贝一份。
- 连续分割符:多个连续的分割符会被视为单个分割符,不会返回空字符串。
- 空指针处理:如果输入的str为NULL且没有前序调用,行为未定义(也就是跳过了strtok(buf,arr2)直接使用NULL)。
strncat
详解
和strcat几乎相同,只不过多了一个参数。
char* strncat(char* dest, const char* src, size_t num);
参数:
- dest:指向目的地空间。
- src:指向源头数据。
- num:最多追加的字符个数。
功能:将src最多num个字符追加在dest字符串的末尾。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "shdfks";
char arr2[20] = "fhufkh";
strncat(arr1, arr2,4);
printf("%s\n", arr1);
return 0;
}
和strcat比较:
- 多了一个参数。
- strncat函数中源字符串不一定要有’\0’了。
- strncat更加灵活,也更加安全。
- 在设计参数时会多一层考虑:目标空间大小够不够用。
注意事项:不足num个只补一个’\0’。
模拟实现
char* My_strncat(char* dest, char* src,size_t num)
{
assert(dest && src);
char* p = dest;
while (*dest != '\0')
{
dest++;
}
while (num--)
{
*dest++ = *src++;
}
return p;
}
strncmp
详解
和strcmp几乎相同,只不过多了一个参数。
int strcmp(const char* str1, const char* str2 ,size_t num);
功能:按ASCII码值,逐字符比较两个字符串,最多比较num次。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "fhvfks";
char arr2[20] = "fhufkh";
int p = strncmp(arr1, arr2, 4);
printf("%d\n", p);
return 0;
}
和strcmp比较:
- 可以比较任意长度,更加灵活、安全。
模拟实现
int My_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
while (*str1 == *str2 && num != 0)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
num--;
}
if (num == 0)
{
return 0;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
strncpy
详解
和strcpy几乎相同,只不过多了一个参数。
char* strncmp(char*dest, const char* src, size_t num);
参数:
- dest:指向目的地空间。
- src:指向源头数据。
- num:最多拷贝的字符串个数。
功能:将src中的内容拷贝到dest中。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[20] = "fhufkh";
strncpy(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;
}
和strcpy比较:
- strcpy函数拷贝到’\0’为止,如果目标空间不够的话,容易出现越界行为。
- strncpy函数指定了拷贝的长度,源字符串不一定要用’\0’。
- 在设计参数的时候会多一层思考:目标空间大小够不够用。
- strncpy相对strcpy函数更加安全。
注意事项:
- strncpy函数,拷贝数目不足num个,直接补’\0’,不管后面是什么,直到数目到达到num个。
- 当src>num时,不会在最后补’\0’。
模拟实现
char* My_strncpy(char* dest, char* src, size_t num)
{
assert(dest && src);
char* p = dest;
while (num>0)
{
*dest = *src;
if (*src != '\0')
{
src++;
}
dest++;
num--;
}
while (num > 0)
{
*dest = '\0';
num--;
}
return p;
}
内存函数
memcpy
详解
内存块拷贝函数(不可重叠)
void* memcpy(void* dest, const void* src, size_t num);
memcpy是完成内存块拷贝的,不关注内存中存放的数据是什么,但不能解决内存重叠问题。
功能:函数memcpy从src的位置开始向后复制num个字节的数据到dest指向的内存位置。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[20] = "hd,kjs fhkf";
memcpy(arr1, arr2, 20 * sizeof(char));
printf("%s\n", arr1);
return 0;
}
注意事项:如果src和dest有任何的重叠,复制的结果都是未定义的。
模拟实现
void* My_memcpy(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
while (num)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
num--;
}
return ret;
}
memmove
详解
内存块拷贝函数(可重叠)
void* memmove(void* dest, const void* src, size_t num);
memove和memcpy的差别就是,memmove函数处理的源内存块的目标内存块是可以重叠的。
演示:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "123456789";
char arr2[20] = "123456789";
memmove(arr1, arr1 + 5, 10);
memmove(arr2 + 5, arr2, 10);
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
模拟实现
void* My_memmove(void* dest, const void* src, size_t num)
{
assert(dest && src);
void* ret = dest;
//从前向后拷贝
if(dest<src)
{
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
//从后向前拷贝
else
{
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
memset
详解
设置内存块的内容
void* memset(void* ptr, int value, size_t num);
功能:memset函数是用来设置内存块内容的,将内存中指定长度的空间设置为特定的内容。
参数:
- ptr:指针,指向要设置的内存空间,也就是存放了要设置的内存空间的起始地址。
- value:要设置的值,函数将会把value值转换成unsigned char的数据进行设置的,也就是以字节为单位来设置内存块的。
- num:单位字节。
演示:
int main()
{
char arr1[20] = "123456789";
memset(arr1,1,20*sizeof(char));
printf("%s\n", arr1);
return 0;
}
通过观察内存,我们可以发现,每个字节都被改成了1。
更多推荐

所有评论(0)