专栏:C语言
每日一句:别在乎别人的目光,自己只管一心走路。熬过去,你就能看到柳暗花明,熬过去,你就能看到雨后彩虹,熬过去,你就能看到动人风景。
字符串函数
- 前言
- 一、求字符串长度:strlen
- 1.strlen的简单介绍
- 2.strlen的模拟实现
- 2.1利用指针-指针实现
- 2.2利用递归实现
- 2.3利用循环实现
- 二、拷贝字符串strcpy和strncpy
- 1.strcpy的介绍
- 1.1strcpy的模拟实现
- 2.strncpy的简单介绍
- 三、连接字符串strcat和strncat
- 1.strcat的简单介绍
- 1.1strcat模拟实现
- 2.strncat的简单介绍
- 四、比较字符串strcmp和strncmp
- 1.strcmp的简单介绍
- 1.1strcmp的模拟实现
- 2.strncmp的简单介绍
- 五、查找字符穿strstr
- 1.strstr的简单介绍
- 1.1strstr的模拟实现
- 六、错误信息strerror和perror
- 1.strerror的简单介绍
- 2.perror的简单介绍
- 七、内存函数memcpy,memmove和memset
- 1memcpy的简单介绍
- 1.1memcpy的模拟实现
- 2.memmove的简单介绍
- 2.1memmove的模拟实现
- 3.memset的简单介绍
- 总结
前言
本文重点介绍处理字符和字符串库函数的使用和注意事项
文章中的函数介绍图片来源于cplusplus.com
一、求字符串长度:strlen
1.strlen的简单介绍
strlen函数的作用是求字符串长度
size_t strlen(const char *str);
字符串是已‘\0'
作为结束标志,strlen函数返回的是在字符串中出现在'\0'
之前的有效字符的个数。
参数str指向的字符串必须要以'\0'
作为结束标志
注意函数的返回值为size_t
,size_t是无符号的
2.strlen的模拟实现
在这里,给大家介绍三种实现方式
2.1利用指针-指针实现
前面介绍过,指针-指针得到的是元素之间的个数,利用这个原理,就能实现strlen
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
const char* st = str;记录str的起始地址
while (*++str);
return str - st;
}
int main()
{
char str[] = "abcdef";
int len = my_strlen(str);
printf("%d\n", len);
return 0;
}
2.2利用递归实现
如果*str
不为'\0'
就可以return 1 + my_strlen(++str)
这样每次都可以+1,直到遇到字符串的结束标志'\0'
,结束递归。
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
if (*str)
{
return 1 + my_strlen(++str);
}
else
{
return 0;
}
}
int main()
{
char str[] = "abcdef";
int len = my_strlen(str);
printf("%d\n", len);
return 0;
}
2.3利用循环实现
利用循环实现很简单,循环只要不遇到'\0'
,就继续循环。
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
assert(str);
int cnt = 0;
while (*str)
{
cnt++;
str++;
}
return cnt;
}
int main()
{
char str[] = "abcdef";
int len = my_strlen(str);
printf("%d\n", len);
return 0;
}
二、拷贝字符串strcpy和strncpy
1.strcpy的介绍
char* strcpy(char* destination, const char* source);
源字符串必须以'\0'
为结束标志
会将源字符串中的'\0'
拷贝到目标空间
目标空间必须足够大,以确保能够存放源字符串
目标空间必须可变
1.1strcpy的模拟实现
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* str1, const char* arr2)
{
assert(str1 && arr2);
char* ret = str1;
while (*str1++ = *arr2++);
return ret;
}
int main()
{
char str1[20] = "";
const char arr2[] = "h h x x";
my_strcpy(str1, arr2);
printf("%s", str1);
return 0;
}
注:strcpy的返回值是目标字符串的起始地址
2.strncpy的简单介绍
char * strncpy ( char * destination, const char * source, size_t num );
拷贝num个字符从源字符串到目标字符串中
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标字符串的后面追加0,直到够num个为止
三、连接字符串strcat和strncat
1.strcat的简单介绍
char * strcat ( char * destination, const char * source );
源字符串必须以'\0'
为结束标志
目标空间必须足够大,以确保能够容纳源字符串的内容
目标空间必须可变
1.1strcat模拟实现
要模拟实现strcat,需要先找到目标字符串的尾,也就是’\0’的位置,然后让源字符串的内容连接在目标字符串后面即可
#include <stdio.h>
#include <assert.h>
char* my_strcat(char* arr, const char* str)
{
assert(arr && str);
char* ret = arr;
while (*++arr);
while (*arr++ = *str++);
return ret;
}
int main()
{
char arr[20] = "hao hao";
const char str[10] = " xue xi";
my_strcat(arr, str);
printf("%s", arr);
return 0;
}
2.strncat的简单介绍
char * strncat ( char * destination, const char * source, size_t num );
如果源字符串的长度小于 num,则仅复制源字符串的结束标志之前的内容。
四、比较字符串strcmp和strncmp
1.strcmp的简单介绍
int strcmp ( const char * str1, const char * str2 );
这个strcmp是比较字符串的函数,但它并不是一串一串的比较,而是一个字符一个字符的比较。
如果str1 > str2 则返回 1
如果str1 = str2 则返回 0
如果srt1 < str2 则返回 -1
1.1strcmp的模拟实现
#include <stdio.h>
#include <assert.h>
#include <string.h>
int my_strcmp(const char* arr, const char* str)
{
assert(arr && str);
while (*arr == *str)
{
if (!*arr)
{
return 0;
}
arr++;
str++;
}
if (*arr > *str)
{
return 1;
}
else
{
return -1;
}
}
int main()
{
char arr[20] = "ba";
const char str[10] = "bd";
int cmp = my_strcmp(arr, str);
printf("%d\n%d", cmp, strcmp(arr, str));
return 0;
}
2.strncmp的简单介绍
int strncmp ( const char * str1, const char * str2, size_t num );
在这里,num是要比较的字符个数。
五、查找字符穿strstr
1.strstr的简单介绍
char * strstr ( const char * str1, const char * str2 );
str2 中指定的整个字符序列在 str1 中首次出现的位置,如果序列在 str1 中不存在,则返回null
指针。
1.1strstr的模拟实现
#include <stdio.h>
int n, m;
int ne[20];
char* my_strstr(char* str, char* ch)
{
for (int i = 2, j = 0; i <= n; i++)
{
while (j && str[i] != str[j + 1])
{
j = ne[j];
}
if (str[i] == str[j + 1])
{
j++;
}
ne[i] = j;
}
for (int i = 1, j = 0; i <= m; i++)
{
while (j && ch[i] != str[j + 1])
{
j = ne[j];
}
if (ch[i] == str[j + 1])
{
j++;
}
if (j == n)
{
return ch + i + 1 - n;
break;
}
}
}
int main()
{
char str[20], ch[20];
scanf("%d%s%d%s", &n, (str + 1), &m, (ch + 1));
printf("%s", my_strstr(str, ch));
return 0;
}
六、错误信息strerror和perror
1.strerror的简单介绍
char * strerror ( int errnum );
返回错误码所对应的错误信息。
#include <stdio.h>
#include <string.h>
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
printf("%s\n", strerror(4));
printf("%s\n", strerror(5));
return 0;
}
这就是一些错误信息。
2.perror的简单介绍
void perror ( const char * str );
打印报错信息
#include <stdio.h>
#include <string.h>
int main()
{
FILE* fp = fopen("Haifan.txt", "r");//这里并没有该文件
if (fp == NULL)
{
perror("fp");
}
/*fclose(fp);
fp = NULL;*/
return 0;
}
七、内存函数memcpy,memmove和memset
1memcpy的简单介绍
void * memcpy ( void * destination, const void * source, size_t num );
函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到’\0’的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。
1.1memcpy的模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* arr1, const void* arr2, size_t num)
{
assert(arr1 && arr2);
void* ret = arr1;
while (num--)
{
*((char*)arr1) = *((char*)arr2);
arr1 = (char*)arr1 + 1;
arr2 = (char*)arr2 + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[5] = { 0 };
my_memcpy(arr1, arr2, 8);
return 0;
}
2.memmove的简单介绍
void * memmove ( void * destination, const void * source, size_t num );
和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。
2.1memmove的模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memmove(void* arr1, const void* arr2, size_t num)
{
assert(arr1 && arr2);
void* ret = arr1;
if (arr1 < arr2)
{
while (num--)
{
*((char*)arr1) = *((char*)arr2);
arr1 = (char*)arr1 + 1;
arr2 = (char*)arr2 + 1;
}
}
else
{
while (num--)
{
*((char*)arr1 + num) = *((char*)arr2 + num);
}
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5 };
my_memmove(arr1+1, arr1, 16);
int arr2[] = { 1,2,3,4,5 };
memmove(arr2 + 1, arr2, 16);
return 0;
}
3.memset的简单介绍
void * memset ( void * ptr, int value, size_t num );
这个函数是对ptr按字节把ptr每一个字节初始化成value,一共是num个字节
#include <stdio.h>
#include <string.h>
int main()
{
int arr[5] = { 0 };
memset(arr, 0x3f, sizeof(arr));
return 0;
}
这样,就能把arr的每个字节变成了0x3f
总结
以上是对常用字符串函数的总结,希望对大家有所帮助。