字符串与内存操作函数
字符串函数
字符串长度:strlen
size_t strlen ( const char*str )
- 字符串以 \0 为结束标志,strlen函数返回的是 \0 以前出现的字符个数。
- 且参数指向的字符串必须要以 \0 结尾。
- 需要注意的是strlen函数返回值为size_t,是无符号的。
接下来,如果要深入学习这类函数,我们还得需要知道他们是如何实现的。
↓
strlen函数的模拟实现
size_t my_strlen(char*str)
{
int cou=0;
while(*str!='\0')
{
str++;
cou++;
}
return cou;
}
int main()
{
char arr1[]="abc";
int ret = my_strlen(arr1);
printf("%d\n",ret);
return 0;
}
拷贝字符串:strcpy
char* strcpy(char * destination, const char * source )
- 将来源source中的字符串拷贝到目标destination中。
- 当然来源字符串也必须以 \0 结尾。
- 拷贝时也会将来源字符串中的 \0 一起拷贝。
- 且目标空间必须足够大,以确保能放下来源字符串。
模拟实现strcpy
↓
char* my_strcpy(char*str1,char*str2)
{
assert(str1);
assert(str2);
char* ret=str1;
while(*str1++ =*str2++)
{
;
}
return ret;
}
int main()
{
char arr1[20]="sytw";
char arr2[]="adcdefgh";
printf("%s\n",my_strcpy(arr1,arr2));
return 0;
}
比较字符串:strcmp
int strcmp ( const char * str1, const char * str2 )
- 这个笔者以为大家应该都比较熟悉。
- 第一个字符串大于第二个字符串,则返回大于0的数字。
- 第一个字符串等于第二个字符串,则返回0。
- 第一个字符串小于第二个字符串,则返回小于0的数字。
但是其中涉及到的具体实现可能还有人不太清楚,所以还是来看看模拟实现strcmp。
↓
int my_strcmp(char* s1, char* s2)
{
assert(*s1 && *s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
{
return 0;
}
s1++;
s2++;
}
return *s1 - *s2;
}
int main()
{
char arr1[] = { "abcdef" };
char arr2[] = { "abq" };
int ret = my_strcat(arr1, arr2);
printf("%s\n", ret);
return 0;
}
追加字符串:strcat
char * strcat ( char * destination, const char * source )
- 依旧,来源字符串source必须要以 \0 结尾。
- 目标空间destination足够大,能容下来源字符串内容。
- 这段应该很熟悉,与strcpy内容非常相似,因为两个函数都要通过找到 \0 来实现。
那就一起来看看strcat函数是如何实现的吧
↓
char* my_strcat(char* s1, char* s2)
{
char* det = s1;
while (*det != '\0')
{
det++;
}
while (*det++ = *s2++)
{
;
}
return s1;
}
int main()
{
char arr1[20] = { "abcdef" };
char arr2[] = { "abq" };
printf("%s\n", my_strcat(arr1, arr2));
return 0;
}
搜索字符串:strstr
char * strstr ( const char *str1, const char * str2)
- 在一个字符串中找另一字符串是否存在。
- 如果存在则返还字串所在的起始地址。
- 如果不存在则返回NULL。
模拟实现
↓
char* my_strstr(const char* s1,const char* s2)
{
const char* str1 = s1;
const char* str2 = s2;
const char* p = s1;
while (*p)
{
str1 = p;
str2 = s2;
while (*str1 != '\0' && *str2 != '\0' && (*str1 == *str2))
{
str1++;
str2++;
}
if (*str2 == '\0')
{
return p;
}
p++;
}
return NULL;
}
int main()
{
char arr1[] = { "abcdefhigk" };
char arr2[] = { "hig" };
char* p = my_strstr(arr1, arr2);
if (p == NULL)
{
printf("不存在\n");
}
else
{
printf("%s\n", p);
}
return 0;
}
内存操作函数
拷贝内存中的数据:memcpy
void * memcpy ( void * destination, const void * source, size_t num )
- 可以拷贝任何类型的数据。
- source的位置开始向后复制num个字节的数据到destination的内存位置。
- 且在遇到 \0 时不会停下。
看看模拟实现
↓
void* my_memcpy(void* dest,void* src,size_t num)
{
void* ret=dest;
assert(dest);
assert(src);
while(num--)
{
*(char*)dest=*(char*)src;
dest=(char*)dest+1;
src=(char*)src+1;
}
return ret;
}
int main()
{
int arr1[]={1,2,3,4,5,6,7,8,9,10};
int arr2[]={0};
my_memcpy(arr2,arr1,20);
for(int i=0;i<10;i++)
{
printf("%d\n",arr2[i]);
}
return 0;
}
拷贝数据(叠加版):memmove
void * memmove ( void * destination, const void * source, size_t num )
- 看到这个函数和memcpy一模一样,所以差别在哪里?
- 区别就是在处理时的来源源内存块和目标内存块是可以重叠的。
- 就是说我们在处理内存数据时,如果源空间和目标空间出现重叠,就得使用memmove函数处理。
来看模拟实现是不是和memcpy也比较类似?
↓
void* my_memmove(void* dest,void* src,size_t num)
{
void* ret=dest;
assert(dest);
assert(src);
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;
}
int main()
{
int arr1[]={1,2,3,4,5,6,7,8,9,10};
my_memmove(arr1+2,arr1,20);
for(int i=0;i<10;i++)
{
printf("%d\n",arr1[i]);
}
return 0;
}