目录
二、长度不受限制的函数:strcpy,strcat,strcmp
一、strcmp
int strcmp(const char* string1, const char* string2)
1字符串大于2字符串,返回大于0的数字
1字符串小于2字符串,返回小于0的数字
相等返回0
int main()
{
const char* p1 = "abcdef";
const char* p2 = "qwert";
int ret = strcmp(p1, p2);
printf("%d\n", ret);
return 0;
}
比较的方法并不是元素个数比大小,而是相应的元素比ANSCII码值,比如a和q比,a小于q,所以返回-1。
但是呢这是在vs里面进行的,不同的编译环境返回的数值不一样,但是范围还是一样,大于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 if(*str1 < *str2)
return -1;
}
int main()
{
const char* p1 = "abcdef";
const char* p2 = "abqwe";
int ret = my_strcmp(p1, p2);
printf("ret = %d\n", ret);
return 0;
}
如果abc和abcd比较,那么循环到\0和d比较,不一样,就来到下面的if else,0小于d,返回-1。
或者if else改成return (*str1 - *str2)也可。
二、长度不受限制的函数:strcpy,strcat,strcmp
读取到\0才停止,但是这样有不安全,比如strcpy函数,如果目的地不足够长于源头字符串,但是还是拷贝过去了,会形成非法访问,所以不安全。还有长度限制的函数:strncpy,strncat,strncmp。
strncpy
char* strncpy(char* strDest, const char* strSource, size_t count)
count也就是要拷贝几个字节,单位是字节。比如
int main()
{
char arr1[10] = "abcdef";
char arr2[] = "hello bit";
strncpy(arr1, arr2, 4);
return 0;
}
拷贝4个字节,\0不会被拷贝过去。当指定的个数大于源字符串大小,剩下的就补\0,直到指定的字节个数。
关于这个函数,是这样定义的
char* _cdecl strncpy(char* dest, const char* source, size_t count)
{
char* start = dest;
while (count && (*dest++ = *source++))/* copy string*/
count--;
if (count)/* pad out with zeroes*/
while (--count)
*dest++ = '\0';
return(start);
}
同样的,其他两个也是原先基础上加上字节个数
追加函数strncat
追加后,还会再最后自动加一个\0,因为最终要追加成一个字符串。如果count大于追加过去的字符串个数,那么追加完在后面放上一个\0,追加就结束了,不会在后面放上好几个\0
定义
char* _cdecl strncat(char* front, const char* back, size_t count)
{
char* start = front;
while (*front++)
front--;
while (count--)
if (!(*front++ = *back++))
return(start);
*front = '\0';
return(start);
}
strncmp
也就是比较几个字符,数值也就不一样。
三、strstr
char* strstr(const char*, const char*)
int main()
{
const char* p1 = "abcdef";
const char* p2 = "def";
const char* ret = strstr(p1, p2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
函数找不到就会返回空指针,找到会返回d的地址,用指针变量ret接收后,会从d开始往后打印,如果此时p1是abcdefgh,那么结果就会出来abcdefgh。如果p1是abcdefabcdef,有两个def,那么结果会从第一个开始。
模拟实现
#include <stdio.h>
#include <assert.h>
const char* my_strstr(const char* p1, const char* p2)
{
assert(p1 != NULL);
assert(p2 != NULL);
const char* s1 = p1;
const char* s2 = p2;
const char* cur = p1;
if (*p2 == '\0')
{
return p1;
}
while (*cur)
{
s1 = cur;
s2 = (char*)p2;
while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cur;
}
cur++;
}
return NULL;
}
int main()
{
const char* p1 = "abcdefgh";
const char* p2 = "def";
const char* ret = strstr(p1, p2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
最好画图才能明白。库函数的定义是
char* my_strstr(const char* str1, const char* str2)
{
char* cp = str1;
char* s1, * s2;
if (!*str2)
return((char*)str1);
while (*cp)
{
s1 = cp;
s2 = (char*)str2;
while (s1 && s2 && !(*s1 - *s2))
s1++, s2++;
if (!*s2)
return(cp);
cp++;
}
return (NULL);
}
但是VS2019这里查得严,cp,s1,s2,函数类型都得是const char*才行。
其实还可以第一个写的为基础再优化。在s2的if语句后再写这个
if (*s1 == '\0')
{
return NULL;
}
结束。