(一)求字符串长度函数
strlen
??strlen是求字符串长度函数,以\0为结束,长度不包括\0, ??MSDN上解释为(这里的size_t是无符号整型): ????????????size_t strlen( const char *string );
int main()
{
char arr1[]="abcdef";
char arr2[]={ 'a','b','c' };
size_t sz = strlen(arr1);
printf("%d", sz);
printf("%d", strlen(arr2));
return 0;
??这里的arr2数组中找不到\0,strlen随即向后查找,输出随机值。
if (strlen("abc") - strlen("abcdef") > 0)
{
printf("hehe\0");
}
else
{
printf("haha\0");
}
??strlen返回无符号整型,计算过后不可能是负数,所以打印hehe。 ??strlen的模拟实现如下,有三种方式 ??1.计数器
size_t my_strlen(char* p)
{
size_t x = 0;
while (*p)
{
x++;
p++;
}
return x;
}
2.指针 - 指针
size_t my_strlen(char* p)
{
size_t x = 0;
char* ch = p;
while (*p)
{
p++;
}
return p - ch;
}
3.递归
size_t my_strlen(char* p)
{
if (*p)
{
return 1 + my_strlen(++p);
}
else
{
return 0;
}
}
(二)字符串拷贝函数
strcpy — strncpy
??strcpy字符串拷贝函数,将一个字符串内容拷贝到另一个字符串中,遇到\0停下来,原字符串必须以\0结束。 ??MSDN上解释为: ????????????char *strcpy( char *strDestination, const char *strSource );
int main()
{
char arr1[] = "xxxxxxxxxxxxxxxxxx";
char arr2[] = "hello";
printf("%s\n", strcpy(arr1, arr2));
return 0;
}
??将字符串arr2的内容拷贝到arr1中,连同\0一起拷贝过去。 ??下面模拟实现strcpy函数
char* my_strcpy(char* str1,const char* str2)
{
assert(str1 && str2);
char* ret = str1;
while (*str1)
{
*str1++ = *str2++;
}
return ret;
}
??strncpy函数相对于strcpy在长度方面受限,比strcpy更加安全,可以指定拷贝字符的个数。 ??MSDN上解释为: ????????????char *strncpy( char *strDest, const char *strSource, size_t count );
int main()
{
char arr1[20] = "abcdefghi";
char arr2[] = "xxx";
strcpy(arr1, arr2, 2);
printf("%s", arr1);
return 0;
}
??strncpy函数的模拟实现如下,
char* my_strncpy(char* str1, const char* str2, size_t count)
{
assert(str1 && str2);
char* ret = str1;
for (int i = 0;i < count;i++)
{
*str1++ = *str2++;
}
return ret;
}
(三)字符串追加函数
strcat — strncat
??strcat是字符串连接/追加函数,在一个字符串末尾连接另一个字符串,原字符串必须以\0结束,且要保证目标空间大小足够。 ??MSDN上解释为: ????????????char *strcat( char *strDestination, const char *strSource );
int main()
{
char arr1[4] = "abf";
char arr2[] = { 'a','b','f','\0' };
strcat(arr1, arr2);
return 0;
}
??这时虽然打印仍然是abfabf,但是也会弹出对话框显示错误,arr1的空间不足,没有办法在后面连接,给arr1[4]分配更大的空间即可。 ??下面是模拟实现strcat函数
char* my_strcat(char* dest,const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest)
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
??与strcpy和strncpy的关系类似,strncat函数相对于strcat在长度方面受限,比strcat更加安全,可以指定追加字符的个数。 ??MSDN上解释为: ????????????char *strncat( char *strDest, const char *strSource, size_t count );
int main()
{
char arr1[10] = "abf";
char arr2[] = { 'a','b','f','\0' };
strncat(arr1, arr2, 2);
printf("%s", arr1);
return 0;
}
??strncat函数的模拟实现如下,
char* my_strncat(char* dest,const char* src,size_t count)
{
assert(dest && src);
char* ret = dest;
while (*dest)
{
dest++;
}
for(int i=0;i<count;i++)
{
*dest++ = *src++;
}
return ret;
}
(四)字符串比较函数
strcmp — strncmp
??strcmp是字符串比较函数,strcmp比较的是内容(即ASCII码值),不是长度,字符串1小于字符串2的时候返回-1(小于0),大于时返回1(大于0),等于时返回0。 ??MSDN上解释为: ????????????int strcmp( const char *string1, const char *string2 );
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abc";
int ret = strcmp(arr1, arr2);
if (ret == 0)
printf("=");
else if (ch > 0)
printf(">");
else if(ch<0)
printf("<");
return 0;
}
??strcmp函数的模拟实现如下,
int my_strcmp(const char* s1,const char* s2)
{
assert(s1 && s2);
while (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
return *s1 - *s2;
}
??strncmp函数相对于strcmp在长度方面受限,比strcmp更加安全,可以指定比较字符的个数。
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abce";
int ret = strncmp(arr1, arr2, 3);
printf("%d",ret);
return 0;
}
??strncmp函数的模拟实现如下,
int my_strncmp(const char* s1,const char* s2,size_t count)
{
assert(s1 && s2);
for (int i = 0;i < count;i++)
{
if (*s1 == *s2)
{
if (*s1 == '\0')
return 0;
s1++;
s2++;
}
else
return *s1 - *s2;
}
return 0;
}
(五)字符串查找函数
strstr
??strstr是字符串查找函数,可以实现在一个字符串中查找另一个字符串是否存在,返回str2在atr1中第一次出现的位置(char*的指针),如果不存在,则返回为空。 ??MSDN上解释为: ????????????char *strstr( const char *string, const char *strCharSet );
int main()
{
char arr1[] = "i am a student";
char arr2[] = "student";
char* ret = strstr(arr1, arr2);
if (ret == NULL)
{
printf("找不到");
}
else
{
printf("%s\n", ret);
}
return 0;
}
??strstr函数的模拟实现如下,
char* my_strstr(const char* str1,const char* str2)
{
assert(str1 && str2);
char* cp = str1;
char* s1;
char* s2;
if (*str2 == '\0')
return str1;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s2 != '\0' && *s1 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
??在实现过程中,要注意如下的情况,如果在匹配字符串过程中发现不相等,则需要从开始匹配的位置开始重新进行匹配。
(五)字符串切割函数
strtok
??strtok是字符串切割函数,它会找到str中的下一个标记,并将其用\0来结尾,返回一个指向这个标记的指针。 ??MSDN上解释为: ????????????char *strtok( char *strToken, const char *strDelimit ); ??第一个参数用来指定字符串,第二个参数sep是一个字符串,定义用作分隔符的字符集合。 ??strtok函数的第一个参数不为NULL,将找到str中的第一个标记并且保存它在字符串中的位置。strtok函数的第一个参数为NULL时,函数将在同一个字符串被保存的位置开始,查找下一个标记。如果字符串中不存在更多的标记,则返回NULL指针。
int main()
{
char arr1[] = "lyy@editor.csdn.net";
char arr2[30] = { 0 };
char ch[] = "@.";
strcpy(arr2, arr1);
char* ret = NULL;
for (ret = strtok(arr2, ch);ret != NULL;ret = strtok(NULL, ch))
{
printf("%s\n",ret);
}
return 0;
}
??此时的输出值如下:
(六)错误信息报告函数
strerror & perror
??strerror是错误信息报告函数,返回的是错误码对应的错误信息。C语言库函数调用失败的时候,会把错误码存到errco变量里面去,再调用的时候,解释errno变量中对应的错误信息。 ??MSDN上解释为: ????????????char *strerror( int errnum );
int main()
{
FILE* pf = fopen("text,txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
}
else
{
printf("打开文件成功");
}
return 0;
}
??此时屏幕上打印为, ??perror也是错误信息报告函数,相对于strerror操作更为简单。 ??MSDN上解释为: ????????????void perror( const char *string );
int main()
{
FILE* pf = fopen("text,txt", "r");
if (pf == NULL)
{
perror("测试");
}
else
{
printf("打开文件成功");
}
return 0;
}
??perror函数会打印自定义信息之后再添加一个冒号和空格,随后打印错误信息。需要注意的是,perror函数一旦使用就必须要打印,输出如下,
(七)内存操作函数
memcpy
??memcpy是内存拷贝函数,不仅限于字符串。(不能进行重叠拷贝) ??MSDN上解释为: ????????????void *memcpy( void *dest, const void *src, size_t count ); ??前两个是目标地址和原始地址,最后是要拷贝地址的大小。
int main()
{
int arr1[5] = { 1,2,3,4,5 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 5 * sizeof(int));
for (int i = 0;i < 10;i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
??memcpy函数的模拟实现如下,
void* my_memcpy(void* dest, const void* src, size_t count)
{
char* ch = dest;
assert(dest && src);
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ch;
}
memmove
??memmove函数和memcpy作用类似,不同的是memmove可以实现重复内存拷贝。 ??MSDN上解释为: ????????????void *memmove( void *dest, const void *src, size_t count );
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
memmove(arr+2, arr, 16);
for (int i = 0;i < 10;i++)
{
printf("%d ", arr[i]);
}
return 0;
}
??同一个字符串内部进行拷贝时,memmove输出为1 2 1 2 3 4 7 8 9 0,但是对于memcpy来说,在拷贝过程中,原字符串发生改变,输出为1 2 1 2 1 2 7 8 9 0,后续并不是我们想要的效果。memmove在本质上相当于memcpy的高级版本。 ??由于拷贝过程中可能存在原字符串改变的问题,我们需要考虑以下情况,当dest在低地址,src在高地址时,需要从前向后拷贝,当dest在高地址,src在低地址的时候,需要从后向前拷贝(拷贝顺序与指针位置有关)。 ??memmove函数的模拟实现如下,
void* my_memmove(void* dest, const void* src, size_t count)
{
char* ch = dest;
if (dest < src)
{
while (count--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
while (count--)
{
*((char*)dest+count) = *((char*)src+count);
}
}
return ch;
}
memcmp
??memcmp是内存比较函数,比较的是内存数据的大小,可以指定字节个数,大于返回1(大于0的数),小于返回-1(小于0的数),相等返回0。 ??MSDN上解释为: ????????????void *memcpy( void *dest, const void *src, size_t count );
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,6,6 };
int ret = memcmp(arr1, arr2, 12);
return 0;
}
memset
??memset是内存设置函数,以字节为单位改变内存中的数据。 ??MSDN上解释为: ????????????void *memset( void *dest, int c, size_t count );
int main()
{
int arr[] = { 1,2,3,4,5 };
memset(arr, 1, 24);
return 0;
}
??内存中显示为,
|