字符串函数
前言
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。
字符串常量适用于那些对它不做修改的字符串函数
函数介绍
strlen
函数基础
函数介绍:strlen
size_t strlen ( const char * str );
头文件:string.h
函数名:strlen
函数参数:str,参数类型是const char* ,即需要进行求字符串长度的起始地址
函数返回类型: size_t,size_t是unsigned int的类型重定义,是无符号整型。库 函数使用size_t类型可能考虑的是字符串的长度不可能是负 数,所以用了无符号类型size_t。
函数功能:计算字符串的长度
- 字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
- 参数指向的字符串必须要以 ‘\0’ 结束。
- 注意函数的返回值为size_t,是无符号的( 易错 ).
- 学会strlen函数的模拟实现
'\0’的重要性
int main()
{
char arr[] = { "abc" };
int len = strlen(arr);// 3
printf("%d\n", len);
return 0;
}
int main()
{
char arr[] = { 'a', 'b', 'c' };
int len = strlen(arr);//随机值
printf("%d\n", len);
return 0;
}
函数strlen在字符串后找’\0’,直到找到后才会停下。
模拟实现
strlen函数的模拟实现三种方法:
1.计数器方法
2.递归方法(不创建临时变量求字符串长度)
3.指针 - 指针方法
#include<stdio.h>
#include<assert.h>
//1.计数器实现求字符串长度函数
int my_strlen1(const char* str)//整个过程不改变指针指向内容,加上const
{
assert(str != NULL);//加上断言,防止接收空指针
int count = 0;
while (*str != '\0')//也可以直接用while(*str)
{
count++;
str++;
}
return count;
}
//2.递归实现求字符串长度,不用创建临时变量
int my_strlen2(const char* str)
{
assert(str != NULL);
if (*str != '\0')//也可以直接用if(*str)
{
return 1 + strlen(str + 1);//不能直接使用str++,可以使用++str,建议直接用str+1
}
else
return 0;
}
//3.指针-指针得到中间元素的个数,实现求字符串长度
int my_strlen3(const char* str)
{
assert(str != NULL);
const char* tmp = str;//创建临时指针变量保存str起始值
while (*str != '\0')
{
str++;
}
return str - tmp;
}
int main()
{
char arr[] = "abcdefgh";
int ret1 = my_strlen1(arr);//1.计数器方法
int ret2 = my_strlen2(arr);//2.递归方法
int ret3 = my_strlen3(arr);//3.指针 - 指针方法
printf("%d\n", ret1);
printf("%d\n", ret2);
printf("%d\n", ret3);
return 0;
}
strcpy
函数介绍:strcpy
char* strcpy(char* destination,const char* source);
头文件:string.h
函数名:strcpy
函数参数:参数1:destination, 类型:char* ,表示将字符串拷贝的目的地位置
参数2:source,类型:char* ,表示被拷贝字符串拷贝的源地址起始位置。
函数返回类型: char*, 实际上就是返回destination(目的地)的起始位置
函数功能:字符串拷贝
- Copies the C string pointed by source into the array pointed by destination, including the terminating nullcharacter (and stopping at that point).
- 源字符串必须以 ‘\0’ 结束。
- 会将源字符串中的 ‘\0’ 拷贝到目标空间。
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变。
- 学会模拟实现。
模拟实现
版本一(基础版)
#include<stdio.h>
#include<assert.h>
char* my_strcpy1(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* dest_start = dest;
//拷贝src指向字符串的内容到dest指向的空间,包括'\0'
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
return dest_start;
}
int main()
{
char arr1[] = "abcdefghik";
char arr2[] = "hello";
my_strcpy1(arr1, arr2);//模拟实现strcpy函数
printf("%s", arr1);
return 0;
}
版本二(精简版)
#include<stdio.h>
#include<assert.h>
char* my_strcpy2(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* dest_start = dest;
while (*dest++ = *src++)
{
;
}
return dest_start;
}
int main()
{
char arr1[] = "abcdefghik";
char arr2[] = "hello";
my_strcpy2(arr1, arr2);//模拟实现strcpy函数
printf("%s", arr1);
return 0;
}
strcat
函数基础
函数介绍:strcat
char* strcat(char* destination,const char* source)
头文件:string.h
函数名:strcat
函数参数:参数1:destination, 类型:char* ,表示将字符串追加的目的地位置
参数2:source,类型:char* ,表示被追加字符串的源地址起始位置。
函数返回类型: char*,实际上就是返回destination(目的地)的起始位置
函数功能:字符串追加
(1)Appends a copy of the source string to the destination string.The
terminating null character in destination is overwritten by the first character of source, and a null - character is included at the end ofthe new string formed by the concatenation of both in destination.
(2)源字符串必须以‘\0’结束。目标空间也必须包含’\0’,以确定追加的起始位置。
(3)目标空间必须有足够的大,能容纳下源字符串的内容。
(4)目标空间必须可修改。
(5)字符串自己给自己追加,如何 ?
用strcat自己给自己追加会导致程序崩溃,无法实现自己追加自己!(从’\0’开始追加,自己追加自己的时候,’\0‘改成了被追加的首字符,再寻找追加字符串结束的’\0’时,找不到’\0’,会导致死循环)
模拟实现
char* my_strcat(char* dest, const char* src)
{
assert(dest != NULL);
assert(src != NULL);
char* dest_start = dest;
//1.找到目的空间中的'\0'
while ( *dest )//跳过不是'\0'的字符
{
dest++;
}
//2.追加
while (*dest++ = *src++)
{
;
}
return dest_start;
}
int main()
{
char arr1[30] = "hello";
char arr2[] = "world";
my_strcat(arr1, arr2);//模拟实现strcat
printf("%s", arr1);
return 0;
}
strcmp
函数基础
函数介绍:strcmp
int strcmp(const char* str1,const char* str2)
(1)This function starts comparing the first character of each string.lf they are equal to each other, itcontinues with the following pairs until the characters differ or until a terminating null - character isreached.
标准规定︰
(2)第一个字符串大于第二个字符串,则返回大于O的数字。
(3)第一个字符串等于第二个字符串,则返回0
(4)第一个字符串小于第二个字符串,则返回小于0的数字
模拟实现
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* p1, const char* p2)
{
assert(p1 && p2);
while (*p1 == *p2)
{
if (*p1 == '\0')
{
return 0;
}
p1++;
p2++;
}
if (*p1 > *p2)
{
return 1;
}
else
{
return -1;
}
int main()
{
char* p1 = "abcdef";
char* p2 = "abqwt";
int ret = my_strcmp(p1, p2);
if(ret = 0)
printf("p1 = p2\n");
else
if (ret = -1)
printf("p1 < p2\n");
else printf("p1 > p2\");
return 0;
}
strncpy
strncpy与strcpy相比较多了一个字母n,这个n代表的是需要拷贝字符的个数,也就是说strncpy需要关注拷贝字符的个数,而不是像strcpy那样关注’\0’。
char * strncat ( char * destination, const char * source, size_t num );
Copies the fifirst num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.
拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
基础版
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src, size_t n)
{
char* dest_start = dest;
while ((n > 0) && (*src != '\0'))
{
*dest = *src;
dest++;
src++;
n--;
}
while (n > 0)
{
*dest = '\0';
dest++;
n--;
}
return dest_start;
}
int main()
{
char arr1[10] = "abcdefg";
char arr2[] = "1234";
size_t len = 0;
scanf("%d", &len);
my_strncpy(arr1, arr2, len);
printf("%s", arr1);
return 0;
}
进阶版
#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src, size_t count)
//count比n更有实际意义
{
assert(dest != NULL);//引用断言
assert(src != NULL);
char* start = dest;
while (count && (*dest++ = *src++) != '\0')
{
count--;
}
if (count)
{
while (count--)
{
*dest++ = '\0';
}
}
return start;
}
int main()
{
char arr1[10] = "abcdefg";
char arr2[] = "1234";
size_t len = 0;
scanf("%d", &len);
my_strncpy(arr1, arr2, len);
printf("%s", arr1);
return 0;
}
strcat
strcat函数是字符串追加,在使用的时候以src的’\0’作为追加结束标志,因此在使用strcat来追加一个字符串数组本身的时候,会因\0被提前覆盖而无法追加成功。
char* strncat(char* destination,const char* source,size_t num);
(1)Appends the first num characters of source to destination, plus a terminating null - character.
(2)lf the length of the C string in source is less than num, only the content up to the terminating null - character is copied.
(3)如果追加的字符长度大于目的地空间的剩余容量,则出现越界访问,要避免这种情况发生。
模拟实现
基础版
#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src, size_t count)
{
char* start = dest;
//dest找到\0的位置
while (*dest!='\0')
{
dest++;
}
while (count)
{
//将src中的字符追加给dest
*dest = *src;
dest++;
src++;
//如果src以及指向\0的位置,提前结束循环
if (*src == '\0')
{
break;
}
count--;
}
*dest = '\0';//字符个数追加完毕后,再单独追加'\0'
return start;
}
int main()
{
char arr1[15] = "12345\0xxxxxxx";
char arr2[] = "abcd";
size_t count = 0;
scanf("%d", &count);
my_strncat(arr1, arr2, count);
printf("%s", arr1);
return 0;
}
进阶版
#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src, size_t count)
{
assert(dest != NULL && src != NULL);
char* start = dest;
while (*dest++)
;
dest--;
while (count--)
if ((*dest++ = *src++) == '\0')
return start;
*dest = '\0';
return start;
}
int main()
{
char arr1[15] = "12345\0xxxxxxx";
char arr2[] = "abcd";
size_t count = 0;
scanf("%d", &count);
my_strncat(arr1, arr2, count);
printf("%s", arr1);
return 0;
}
strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
- 比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
库函数源代码:
int __cdecl strncmp
(
const char* first,
const char* last,
size_t count
)
{
size_t x = 0;
if (!count)
{
return 0;
}
/*
* This explicit guard needed to deal correctly with boundary
* cases: strings shorter than 4 bytes and strings longer than
* UINT_MAX-4 bytes .
*/
if (count >= 4)
{
/* unroll by four */
for (; x < count - 4; x += 4)
{
first += 4;
last += 4;
if (*(first - 4) == 0 || *(first - 4) != *(last - 4))
{
return(*(unsigned char*)(first - 4) - *(unsigned char*)(last - 4));
}
if (*(first - 3) == 0 || *(first - 3) != *(last - 3))
{
return(*(unsigned char*)(first - 3) - *(unsigned char*)(last - 3));
}
if (*(first - 2) == 0 || *(first - 2) != *(last - 2))
{
return(*(unsigned char*)(first - 2) - *(unsigned char*)(last - 2));
}
if (*(first - 1) == 0 || *(first - 1) != *(last - 1))
{
return(*(unsigned char*)(first - 1) - *(unsigned char*)(last - 1));
}
}
}
/* residual loop */
for (; x < count; x++)
{
if (*first == 0 || *first != *last)
{
return(*(unsigned char*)first - *(unsigned char*)last);
}
first += 1;
last += 1;
}
return 0;
}
strstr
#include <stdio.h>
#include <assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = NULL;
const char* s2 = NULL;
char* cp = str1;
while (*cp)
{
s1 = cp;
s2 = str2;
if (*s2 == '\0')
{
return s1;
}//判断条件str2为空
while (s1 && s2 && (*s1 == *s2))//避免s1='\0'或者s2='\0',即字符串结束仍未找到的情况
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
//在arr1中查找是否包含arr2
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("can't search \n");
}
else
{
printf("can search:-> %s\n", ret);
}
return 0;
}
strtok
char* strtok(char* str, const char* sep)
字符串分割函数
#include<stdio.h>
#include<string.h>
int main()
{
//192.168.31.121 网络ip地址 --点分十进制
//192 168 31 121 ---strtok .
char arr[] = "abcdefg@123.com";
char* p = "@.";
char buf[100] = { 0 };
char* ret = 0;//用于接收分割后标记的位置
//分割字符串之前先进行临时拷贝
strcpy(buf, arr);
//分割buf中的字符串
//ret = strtok(buf, p);
//printf("%s\n", ret);
//ret = strtok(NULL, p);
//printf("%s\n", ret);
//ret = strtok(NULL, p);
//printf("%s\n", ret);
//一次性打印
for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}
return 0;
}