重点梳理
c语言冲提供了许多与字符串相关的函数,包括字符串的复制、求字符串的长度等。本节主要介绍C语言库函数中与字符串相关的库函数,熟悉这些函数方便以后编程时的使用。
1.求字符串长度
求字符串长度:strlen()
库函数:size_t strlen ( const char * str )
2.长度不受限制的字符串函数
字符串复制:strcpy()
库函数:char * strcpy ( char * destination, const char * source );
字符串拼接:strcat()
库函数:char * strcat ( char * destination, const char * source )
字符串比较:strcmp()
库函数:int strcmp ( const char * str1, const char * str2 );
3.长度受限制的字符串函数
以下函数与长度不受限制的字符串函数最大的区别就是,下面这些函数操作的字符个数是n个上边的函数操作的是整个字符串。
字符串复制:strncpy()
库函数:char * strncpy ( char * destination, const char * source, size_t num );
字符串拼接:strncat()
库函数:char * strncat ( char * destination, const char * source, size_t num );
字符串比较:strcnmp()
库函数:int strncmp ( const char * str1, const char * str2, size_t num );
4.字符串查找
判断子串:strstr()
库函数:const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
字符串分割:strtok()
5.错误信息报告
错误信息报告:strerror()
6.内存操作函数
内存操作函数主要指从内存中进行操作,比如memmove和memcpy就是内存拷贝函数除此之外内存操作函数按字节进行操作,这样无论是char类型int类型还是其他类型都可以使用,而上面讲的那些函数只适用于char类型字符串。
内存复制:memcpy()
库函数:void * memcpy ( void * destination, const void * source, size_t num );
memmove()
库函数:void * memmove ( void * destination, const void * source, size_t num );
memset()
库函数:void * memset ( void * ptr, int value, size_t num );
内存比较:memcmp()
库函数:int memcmp ( const void * ptr1, const void * ptr2, size_t num );
注:以上函数使用时,都要引入头文件:#include
有些库函数需要我们熟练掌握并熟悉它的实现过程,这些字符串无论是在开发还是在找工作面试是都是一个重点,以下内容就是C语言中需要熟练掌握并熟悉实现过程的一些库函数的模拟实现和使用:
1.strlen()
size_t strlen ( const char * str )
size_t是返回值类型,一般是整型
str是需要计算的字符串,其中const表示该字符串只可以使用不可以修改。
模拟实现
//方法一
int my_strlen(const char* str)
{
//count记录字符串的长度
int count = 0;
while (*str++)
count++;
return count;
}
//注意:*str++,由于后置++的优先级高于*的优先级,所以str先与++结合在于*结合。但,后置++是先使用在++,所以上边代码还可以写成下面的形式
int my_strlen(const char* str)
{
//count记录字符串的长度
int count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
//方法二---递归
int my_strlen(const char * str)
{
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
}
//方法三---指针
int my_Strlen(const char* str)
{
char* ret = str;
while(*ret)
{
ret++;
}
return ret - str;
}
使用方法
//方法一
char* str = "abac";
strlen(str);
//方法二
strlen("abcac");
2.strcpy()
char * strcpy ( char * destination, const char * source );
返回值类型为char*,destination表示目标字符串,source表示源字符串
该函数的作用是将源字符串复制到目标字符串并返回复制后的目标字符串。
模拟实现
char* my_strcpy(char * destination, const char * source)
{
assert(source);
assert(destination);
char* dst = destination;
while (*source)
{
*destination = *source;
source++;
destination++;
}
*destination = '\0';
return dst;
}
//注意:assert是断言的意思,确保字符串不为空,在使用assert时要引入头文件:#include
使用
char str1[] = "Sample string";
char str2[40];
char str3[40];
my_strcpy(str2, str1);
my_strcpy(str3, "copy successful");
/*str1: Sample string
str2 : Sample string
str3 : copy successful*/
printf("str1: %s\nstr2: %s\nstr3: %s\n", str1, str2, str3);
3.strcat()
char * strcat ( char * destination, const char * source )
将源字符串拼接到目标字符串后,并返回拼接后的目标字符串。
模拟实现
char* my_strcat(char * destination, const char * source)
{
assert(destination != NULL);
assert(source != NULL);
char* ret = destination;
while (*destination)
{
destination++;
}
while (*source)
{
*destination = *source;
source++;
destination++;
}
*destination = '\0';
return ret;
}
使用方法
char str[80];
strcpy(str, "these ");
my_strcat(str, "strings ");
my_strcat(str, "are ");
my_strcat(str, "concatenated.");
puts(str);
//输出结果为:these strings are concatenated.
4.strcmp()
int strcmp ( const char * str1, const char * str2 );
比较字符串str1和str2,当str1大于str2返回1,当str1小于str2返回-1,当str1与str2相等返回0;
模拟实现
//方法一
int my_strcmp(const char * str1, const char * str2)
{
assert(str1);
assert(str2);
while (*str1 && *str2)
{
if (*str1 == *str2)
{
str1++;
str2++;
}
else
{
if (*str1 > *str2)
return 1;
else
return -1;
}
}
if (*str1)
{
return 1;
}
else
{
if (*str1 == *str2)
return 0;
else
return -1;
}
}
//方法二
int my_strcmp (const char * src, const char * dst)
{
int ret = 0 ;
assert(src != NULL);
assert(dest != NULL);
while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
++src, ++dst;
if ( ret < 0 )
ret = -1 ;
else if ( ret > 0 )
ret = 1 ;
return( ret );
}
使用方法
char key[] = "apple";
char buffer[80];
do {
printf("Guess my favorite fruit? ");
fflush(stdout);
scanf("%79s", buffer);
} while (my_strcmp(key, buffer) != 0);
puts("Correct answer!");
//result
Guess my favourite fruit? orange
Guess my favourite fruit? apple
Correct answer!
5.strncpy、strncmp、strncat
这几个函数与上面几个类似,只是操作范围不同。
char * strncpy ( char * destination, const char * source, size_t num );
将源字符串source中的num个字符复制到目标字符串destination字符串,并返回目标字符串
char * strncat ( char * destination, const char * source, size_t num );
将源字符串中的num个字符串拼接到目标字符中,并返回目标字符串
int strncmp ( const char * str1, const char * str2, size_t num );
比较str1和str2中的num个字符
模拟实现
char* my_strncpy(char * destination, const char * source, int num)
{
while (num)
{
*destination = *source;
destination++;
source++;
num--;
}
*destination = '\0';
return destination;
}
char str1[] = "To be or not to be";
char str2[40];
char str3[40];
/* copy to sized buffer (overflow safe): */
my_strncpy(str2, str1, sizeof(str2)-1);
/*partial copy (only 5 chars): */
my_strncpy(str3, str2, 5);
//str3[5] = '\0'; /* null character manually added */
puts(str1);
puts(str2);
puts(str3);
char * my_strncat(char * destination, const char * source, int num)
{
char* ret = destination;
while (*destination)
{
destination++;
}
while (num)
{
*destination = *source;
destination++;
source++;
num--;
}
*destination = '\0';
return ret;
}
char str1[20];
char str2[20];
my_strcpy(str1, "To be ");
my_strcpy(str2, "or not to be");
my_strncat(str1, str2, 6);
puts(str1);
6.memcpy()
void * memcpy ( void * destination, const void * source, size_t num );
描述:Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.
从源字符串中复制num个字节到目标字符串中
注意:为了能过适应更多类型,复制时按字节复制
模拟实现
void * my_memcpy(void * destination, const void * source, int num)
{
char* dst = (char*)destination;
char* src = (char*)source;
while (num)
{
*dst = *src;
dst++;
src++;
num--;
}
*dst = '\0';
return destination;
}
//注意:由于char类型占用一个字节,所以将字符串强制转换成char*类型后进行操作,可以实现每次只操作一个字符
//使用
struct {
char name[40];
int age;
} person, person_copy;
char myname[] = "Pierre de Fermat";
/* using memcpy to copy string: */
my_memcpy(person.name, myname, strlen(myname) + 1);
person.age = 46;
/* using memcpy to copy structure: */
my_memcpy(&person_copy, &person, sizeof(person));
printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
7.memmove()
void * memmove ( void * destination, const void * source, size_t num );
描述:Copies the values of num bytes from the location pointed by source to the memory block pointed by destination.
从源字符串复制num个字节到目标字符串
注意:看似memmove和memcpy都是从源字符串复制num个字符到目标字符串,但是两个函数有很大区别
memcpy函数在进行复制时不考虑重叠问题,而memmove函数考虑重叠问题。关于重叠问题,在下面我们将详细介绍。
void * memmove ( void * dst, const void * src, size_t count)
{
void * ret = dst;
//前重叠或者不影响结果的后重叠,此时从前往后复制和从后往前复制都可以
if (dst <= src || (char *)dst >= ((char *)src + count))
{
while (count--)
{
*(char *)dst = *(char *)src;
dst = (char *)dst + 1;
src = (char *)src + 1;
}
}
//后重叠,从后往前复制
else
{
dst = (char *)dst + count - 1;
src = (char *)src + count - 1;
while (count--)
{
*(char *)dst = *(char *)src;
dst = (char *)dst - 1;
src = (char *)src - 1;
}
}
return(ret);
}
8.memmove函数和memcpy函数的辨析---前后重叠问题
在字符串的拷贝过程中,由于mem系列函数是内存操作函数即内存拷贝,所以有可能会遇到内存重叠导致拷贝失败的问题,具体描述如下图:
关于memmove函数从前往后复制和从后往前复制的解析: