写在前面:
在实现字符串函数时需要注意以下几点:
- 检查传入参数(字符串指针)的合法性
- 对指针进行参数保护
strlen
size_t strlen ( const char * str );
- 字符串以’\0’作为结束标志,strlen函数返回的是在字符串中’\0’前面出现的字符个数(不包含’\0’);
- 参数指向的字符串必须有’\0’;
- 注意函数的返回值为size_t类型,是无符号的(易错)
模拟实现:
size_t my_strlen(const char* str)
{
////方式1
//assert(str != NULL); //断言,若str是空串则报错
//const char* pstr = str; //对原指针进行保护
//
//size_t len = 0; //注意返回值类型
//while (*pstr != '\0')
//{
// len++;
// pstr++;
//}
//return len;
////方式2
//assert(str != NULL); //断言,若str是空串则报错
//const char* pstr = str; //对原指针进行保护
//
//size_t len = 0; //注意返回值类型
//while (*pstr++ != '\0')
//{
// len++;
//}
//return len;
//方式3,不使用第三方变量,递归方式
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str++);
}
strcpy
char * strcpy ( char * destination, const char * source );
- source字符串必须以‘\0’结束
- source字符串中的‘\0’也会被拷贝到destination中
- destination的空间必须足够大,以确保能够存放source字符串
- destination必须是可变的空间
模拟实现:
char* my_strcpy(char* destination, const char* source)
{
assert(destination != NULL && source != NULL);
char* str1 = destination;
const char* str2 = source;
*str1 = *str2;
if (*str2 != '\0')
{
my_strcpy(++str1, ++str2);
}
else
return destination;
}
void main()
{
char str1[20] = "hello"; //注意str1不可以是指针类型的字符串,因为指针类型的字符串指向一个常量空间,不允许被修改
char *str2 = "bit";
my_strcpy(str1, str2);
printf("str1 = %s\n", str1);
}
strcat
char * strcat ( char * destination, const char * source );
- source字符串必须以‘\0’结束
- destination的空间必须足够大,以确保能够存放source字符串
- destination必须是可变的空间
- 字符串自己给自己追加会引发异常
模拟实现:
char* my_strcat(char* destination, const char* source)
{
assert(destination != NULL && source != NULL);
char* str1 = destination;
const char* str2 = source;
while (*str1 != '\0')
{
str1++;
}
while (*str2 != '\0')
{
*str1++ = *str2++;
}
*str1 = '\0';
return destination;
}
void main()
{
char str1[20] = "12345";
char* str2 = "67890";
printf("%s\n", my_strcat(str1, str2));
}
strcmp
int strcmp ( const char * str1, const char * str2 );
- str1大于str2,则返回大于0的数
- str1等于str2,则返回0
- str1小于str2,则返回小于0的数
- 需要注意的是:字符串1234比字符串123111大,因为该函数的判断是根据第一个不相同的字符大小来判断的。
模拟实现:
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 != NULL && str2 != NULL);
const char* str11 = str1;
const char* str22 = str2;
int i = 0;
while ((*str11 != '\0') || (*str22 != '\0'))
{
if (*str11 - *str22 != 0)
break;
str11++;
str22++;
}
i = *str11 - *str22;
return i;
}
void main()
{
char* str1 = "12111";
char* str2 = "13111";
int i = strcmp(str1, str2);
if (i == 0)
printf("str1 == str2\n");
else if (i > 0)
printf("str1 > str2\n");
else
printf("str1 < str2\n");
}
memcpy
void * memcpy ( void * destination, const void * source, size_t num );
- 从source的位置开始向后复制num个字节的数据到destination的内存位置
- 该函数在遇到’\0’时不会停下来
- 如果source与destination有任何的重叠,复制的结果都是未定义的
用法示例及模拟实现:
void* my_memcpy(void* destination, const void* source, size_t num)
{
assert(destination != NULL && source != NULL);
char* pdest = (char*)destination;
const char* psour = (const char*)source;
while (num--)
{
*pdest++ = *psour++;
}
return destination;
}
typedef struct Person
{
char name[40];
int age;
}Person;
void main()
{
char my_name[] = "Monologue";
int my_age = 20;
Person me;
Person* pme = &me;
Person me2;
//memcpy(me.name, my_name, strlen(my_name) + 1);
my_memcpy(me.name, my_name, strlen(my_name) + 1);
my_memcpy(&me.age, &my_age, sizeof(my_age));
my_memcpy(&me2, &me, sizeof(me));
printf("myname:%s\nmyage:%d\n",pme->name,pme->age);
printf("my2name:%s\nmy2age:%d\n", pme->name, pme->age);
}
memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
- memcmp与strcmp比较相似,区别在于stecmp比较的是两个字符串,而memcmp比较是两块内存空间的内存(包括字符串)
- 另一个不同点就是memcmp是以num作为比较的最大循环次数,并不是以\0来进行判断
模拟实现:
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
assert(ptr1 != NULL && ptr2 != NULL);
const char* pptr1 = (const char*)ptr1;
const char* pptr2 = (const char*)ptr2;
while (num--)
{
if (*pptr1 != *pptr2)
return(*pptr1 - *pptr2);
else
{
pptr1++;
pptr2++;
continue;
}
}
return 0;
}
void main()
{
char str1[10] = "acc";
char* str2 = "abcd";
int i = my_memcmp(str1, str2, strlen(str2) + 1);
if (i == 0)
printf("str1 == str2\n");
else if (i > 0)
printf("str1 > str2\n");
else
printf("str1 < str2\n");
}