目录
- 求字符串长度
strlen - 长度不受限制的字符串长度
strcpy
strcat
strcmp - 长度受限制的字符串长度
strncpy
strncat
strncmp - 字符串查找
strstr
strtok
------------------------------------------分割线----------------------------------------------
0.前言
在C语言中,字符和字符串使用和处理十分的频繁,但是C语言本身是没有字符串类型的,字符串常常放在常量字符串或者字符数组中。
字符串常量适用于那些对它不做修改的字符串常量。
1.函数介绍
1.1 strlen
size_t strlen(const char*string); //strlen函数的一般形式
- 在C语言中,字符串是以’\0’作为标志,strlen函数返回的是在字符串中’\0’前面的字符的个数。
- strlen使用的条件是其所指向的字符串必须以’\0’结束。
- 注意strlen函数的返回值size_t是无符号的(易错点)
- 使用strlen函数,需要引用头文件#include<string.h>。
strlen函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
//字符数组的初始化
char str1[] = "abcdefg";
char str2[] = "acfsd";
if(strlen(str1)>strlen(str2))
{
printf(">");
}
else
{
printf("<");
}
return 0;
}
运行结果:
strlen函数的模拟实现:
//strle函数的模拟实现
#include<stdio.h>
#include<string.h>
int my_strlen(char* str) //返回类型为int,形参用指针的形式接收实参
{
int count = 0; //定义'\0'之前字符的个数
while(*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
//字符数组的初始化
char str1[] = "abcdefg";
char str2[] = "acfsd";
if (my_strlen(str1) > my_strlen(str2))
{
printf(">");
}
else
{
printf("<");
}
return 0;
}
运行结果:
1.2 strcpy函数
char* strcpy(char* dest, const char* src); //strcpy函数的一般形式
- 将源指向的C字符串复制到目标指向的数组中,包括终止的空字符(并在该点停止)。
- 源字符串必须以’\0’结束。
- 会将源字符串中的’\0’拷贝到目标空间。(详解见下文代码)
- 目标空间必须足够大,以确保能存放源字符串。
- 目标空间必须可变。
- 使用strlen函数,需要引用头文件#include<string.h>。
strcpy函数的使用:
//strcpy函数的使用
#include<stdio.h>
#include<string.h>
int main()
{
const char* str1 = "abcdefgh"; //str1指向的是常量字符串,常量是不可修改的
char str2[20] ="poiuyt"; //目标空间是可变的,并且足够大
int sz = sizeof(str2) / sizeof(str2[0]);
strcpy(str2, str1); //这里注意源字符串和目标字符串在函数中的前后位置
printf("%s\n", str2);
return 0;
}
运行结果:
验证源字符串中的’\0’拷贝到目标空间:
strcpy函数的模拟实现(初阶版):
//strcpy函数的使用
#include<stdio.h>
#include<string.h>
char* my_strcpy(char* dest, char* src)
{
char* ret = dest; //strcpy函数返回的是目标函数的起始地址
while (*src != '\0')
{
*(dest) = *(src);
dest++;
src++;
}
return ret;
}
int main()
{
const char* str1 = "abcdefgh"; //str1指向的是常量字符串,常量是不可修改的
char str2[50] ="poiuytxxxxxxxxxxxxx"; //目标空间是可变的,并且足够大
int sz = sizeof(str2) / sizeof(str2[0]);
my_strcpy(str2, str1); //这里注意源字符串和目标字符串在函数中的前后位置
printf("%s\n", str2);
return 0;
}
运行结果:
strcpy函数的模拟实现(进阶版):
//strcpy函数的使用(进阶版)
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src); //对dest和src进行断言,确保其是有效指针
char* ret = dest; //strcpy函数返回的是目标函数的起始地址
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
const char* str1 = "abcdefgh"; //str1指向的是常量字符串,常量是不可修改的
char str2[50] = "poiuytxxxxxxxxxxxxx"; //目标空间是可变的,并且足够大
int sz = sizeof(str2) / sizeof(str2[0]);
printf("%s\n", my_strcpy(str2, str1)); //链式访问
return 0;
}
运行结果:
**这里初阶版和进阶版的运行结果并不相同,大家可以思考一下为什么。。
1.3 strcat函数
char* strcat(char* dest, const char* src); //strcat函数的一般形式
- 源字符串必须以’\0’结束。
- 目标空间必须足够大,能够容纳源字符穿串的内容。
- 目标必须可以可以修改。
- 需要引用头文件#include<string.h>。
strcat函数的使用:
//strcat函数
#include<stdio.h>
#include<string.h>
int main()
{
char* str1 = "abcdefgh";
char str2[30] = "abcd";
strcat(str2, str1);
printf("%s\n", str2);
return 0;
}
运行结果:
strcat函数的模拟实现(初阶版):
//strcat函数的模拟实现
#include<stdio.h>
#include<string.h>
char* my_strcat(char* dest,const char* src)
{
char* ret = dest;
while (*(src) != '\0')
{
dest++;
if (*dest == '\0') //dest为字符串str2的首字符地址,对其自增,找到其末尾的地址
{
*dest = *src; //将str1的第一个字符赋值给str2的最后一个字符
src++; //src自增,指向str1的下一个字符
}
}
return ret;
}
int main()
{
char* str1 = "world";
char str2[30] = "hello";
my_strcat(str2, str1);
printf("%s\n", str2);
return 0;
}
strcat函数的模拟实现(进阶版):
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest&&src); //对dest和src进行断言,确保其是有效指针
char* ret = dest;
while (*dest) //找到字符串str2的'\0'处的地址
{
dest++;
}
while (*dest++ = *src++) //将字符串str1的内容拷贝到str2的'\0'往后,覆盖'\0'
{
;
}
return ret;
}
int main()
{
char* str1 = "world";
char str2[30] = "hello";
printf("%s\n", my_strcat(str2, str1));
return 0;
}
运行结果:
如何让字符串对自己进行追加,结果会怎么样呢?大家可以思考一下。。
1.4 strcmp函数
int strcmp(const char* str1, const char* str2); //strcmp函数的一般形式
- 这个函数开始比较每个字符串的第一个字符。如果它们相等,则继续执行下面的对,直到字符不同或到达一个结束的空字符为止。
- 标准规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字。
- 第一个字符串等于第二个字符串,则返回0。
- 第一个字符串小于第二个字符串,则返回小于0的数字。
- 需要引用头文件#include<string.h>。
strcmp函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
char*str1 = "halloe";
char*str2= "hello";
int ret=strcmp(str1, str2); //将函数返回值设为ret
//对ret进行判断
if (ret>0)
{
printf("str1>str2\n");
}
else if (ret == 0)
{
printf("str1 =str2\n");
}
else
{
printf("str1<str2\n");
}
return 0;
}
strcmp函模拟实现:
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(char* str1, char* str2)
{
assert(str1,str2);
while(*str1==*str2)
{
//相等
if (str1 =='\0')
{
return 0;
}
str1++;
str2++;
}
//不相等
if (*str1 > *str2)
{
return 1;
}
else
{
return -1;
}
}
int main()
{
char* str1 = "hello";
char* str2 = "helloaa";
int ret = my_strcmp(str1, str2); //将函数返回值设为ret
//对ret进行判断
if (ret > 0)
{
printf("str1>str2\n");
}
else if (ret == 0)
{
printf("str1 =str2\n");
}
else
{
printf("str1<str2\n");
}
return 0;
}
> strcmp函数比较的不是两个字符串的大小,而是比较两个字符串对应位置上字符的大小,如果相等就跳过比较下一对字符,直至遇到不同的字符或者’\0’
1.5 strncpy函数
char* strncpy(char* dest, const char* src, size_t num); //strncpy函数的一般形式
- 将源的第一个num字符复制到目标。 如果源C字符串结束 (以空字符为标志)在复制num字符之前找到, 目的地用零填充,直到向其写入总数为num的字符。
- 拷贝num个字符到目标空间。
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标后面追加0,直到num个(见下文详解1)。
- 需要引用头文件#include<string.h>。
strncpy函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
char str1[]= "qwe";
char str2[30]= "abcdef";
strncpy(str2, str1, 5);
printf("%s\n", str2);
return 0;
}
运行结果:
详解1:
1.6 strncat函数
char* strncat(char* dest, const char* src, size_t num); //strncat函数的一般形式
- 将源的第一个num字符添加到目标,并加上一个结束的空字符(这里我们可以验证一下这个空字符是加上的还是目标字符本身自带的,见详解2)。
- 如果源代码中C字符串的长度小于num,则只包含结束之前的内容null字符复制。
- 需要引用头文件#include<string.h>。
strncat函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
char str1[]= "qwe";
char str2[30]= "abcdef";
strncat(str2, str1, 5);
printf("%s\n", str2);
return 0;
}
运行结果:
详解2:
1.7 strncmp函数
int strncmp(const char* str1, const char* str2, size_t num); //strncmp函数的一般形式
-str1和str2的比较范围为num个字符,即只逐一比较num个字符之前的对应每个字符的大小。
- 标准规定:
- 第一个字符串大于第二个字符串,则返回大于0的数字。
- 第一个字符串等于第二个字符串,则返回0。
- 第一个字符串小于第二个字符串,则返回小于0的数字。
- 需要引用头文件#include<string.h>。
strncmp函数的使用:
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abcdefgh";
char str2[] = "abcdeggh";
int ret =strncmp(str1, str2, 2);
if (ret > 0)
{
printf("str1>str2");
}
else if (ret == 0)
{
printf("str1=str2");
}
else
{
printf("str1>str2");
}
return 0;
}
运行结果:
strcmp函数和strncmp函数的相同点和不同点是什么呢?大家可以思考一下。。。
1.8 strstr函数
int strstr(const char* str1, const char* str2); //strstr函数的一般形式
- 返回一个指向str1中第一次出现str2的指针,如果str2不是其中的一部分,则返回一个空指针
str1(即判断str2是否是str1的子串)。 - 如果是,就返回str2首次出现在str1中的地址;如果不是,就返回空指针。
- 需要引用头文件#include<string.h>。
strstr函数的使用
#include<stdio.h>
#include<string.h>
int main()
{
char str1[]= "abcdefgh";
char str2[]= "cd";
char* ret=strstr(str1, str2);
if (NULL == ret)
{
printf("找不到子串!\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
运行结果:
strstr函数的模拟(初阶版):
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2); //对str1和str2断言
char* s1 = str1;
char* s2 = str2;
if (*str2 == *str1) //第一个字符相等
{
while (*str2)
{
if (*str2!= *str1) //从第一个字符开始,同步遍历str1,str2,若出现不同的字符,则返回NULL
return NULL;
str1++;
str2++;
}
return s1; //遍历完成,没有出现不同的字符,说明str2是str1的子串,返回str1的首字符地址
}
else //第一个字符不相等
{
while (*str1 != 0)
{
str1++;
if (*str2 == *str1) //往后遍历,找与str2首字符相同的字符
{
char*cur = str1; //记录此时str1的地址
while (*str2)
{
if (*str2 != *str1)
return NULL;
str2++;
str1++;
}
return cur;
}
}
}
}
int main()
{
char str1[]= "abcdefgh";
char str2[]= "ef";
char* ret=my_strstr(str1, str2);
if (NULL == ret)
{
printf("找不到子串!\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
运行结果:
strstr函数的模拟(进阶版):
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = str1;
const char* s2 = str2;
const char* cur = str1; //定义一个cur指针指向str1
while (*cur)
{
s1 = cur;
s2 = str2; //初始化s2的位置
while (*s1 && *s2 && (*s1 == *s2)) //通过移动cur的位置,找到s1和s2相同的字符,随后s1和s2同步往后遍历
{
s1++;
s2++;
}
if (*s2 == '\0') //s1和s2的遍历的每一个字符都相同
{
return cur;
}
cur++; //遍历str1的
}
return NULL;
}
int main()
{
char str1[] = "abcdefgh";
char str2[] = "bcd";
char* ret = my_strstr(str1, str2);
if (NULL == ret)
{
printf("找不到子串!\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
运行结果:
1.9 strtok函数
char* strtok(char* str, const char* sep); //strtok函数的一般形式
- sep参数是个字符串,定义了用作分隔符的字符集合。
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标
记。 - strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容
并且可修改。) - strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。 - strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记 - 如果字符串中不存在更多的标记,则返回 NULL 指针。
strtok函数的使用(初阶版):
#include<stdio.h>
#include<string.h>
int main()
{
char str1[]= "abndfg@fdff.dsfsf ";
char str2[30] = { 0 };
strcpy(str2,str1); //将str1拷贝到str2中
const char*sep = "@.";
printf("%s\n", strtok(str2,sep)); //只找第一个标记
printf("%s\n", strtok(NULL,sep)); //从保存的位置继续往后找
printf("%s\n", strtok(NULL,sep)); //从保存的位置继续往后找
return 0;
}
运行结果:
strtok函数的使用(进阶版):
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abndfg@fdff.dsfsf ";
char str2[30] = { 0 };
strcpy(str2, str1); //将str1拷贝给str2;
const char* sep = "@.";
char* str = NULL; //定义一个空指针
for (str = strtok(str2, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
运行结果(进阶版):
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abndfg@fdff.dsfsf ";
char str2[30] = { 0 };
strcpy(str2, str1); //将str1拷贝给str2;
const char* sep = "@.";
char* str = NULL; //定义一个空指针
for (str = strtok(str2, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
运行结果: