目录
前言
函数介绍
strlen
代码演示
模拟strlen
strcpy
代码演示
模拟strcpy
strcat
代码演示
模拟strcat
strcmp
代码演示
模拟strcmp
长度受限制的字符串函数 - strncpy、strncat、strncmp
strncpy
代码演示
strncat
代码演示
strncmp
代码演示
strstr
代码演示
模拟strstr
strtok
代码演示
strerror
代码演示
补充:perror函数
前言
C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串中或者字符数组中。 字符串常量适用于那些对它不做修改的字符串函数。
函数介绍
strlen
size_t strlen ( const char * str );
1.字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )。
2.参数指向的字符串必须要以 '\0' 结束。
3.注意函数的返回值为size_t,是无符号的( 易错 )
4.学会strlen函数的模拟实现
功能 - 计算字符串的长度
代码演示
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abc";
int len = strlen(arr);
printf("%d\n", len);
return 0;
}
模拟strlen
计数器版本
#include<stdio.h>
int my_strlen(const char* str)//加const使函数更安全
{
assert(str != NULL);//断言
int count = 0;
while(*str != '\0')
{
str++;
count++;;
}
return count;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
递归版本 - 不用创建临时变量count
#include<stdio.h>
int my_strlen(const char* str)
{
assert(str != NULL);
if (*str != '\0')
return my_strlen(str + 1) + 1;
else
return 0;
}
int main()
{
char arr[] = "abc";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}
除了以上两个版本,模拟strlen函数还有其他版本,大家有兴趣可以去搜索了解一下,这里就不一一列举了。
strcpy
char* strcpy(char * destination, const char * source );.
Copies the C string pointed by source into the array pointed by destination, including the terminating nullcharacter(and stopping at that point).
1.源字符串必须以 '\0' 结束。2.会将源字符串中的 '\0' 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。
功能 - 将源字符串拷贝到目的字符串
代码演示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
char arr[20] = "#############";
//arr = "hello";//err arr表示数组首元素地址,是const类型,不能被赋值
//printf("%c\n", "hello"[1]);//e "hello"可以说本身是个地址
/*char* p = "hello";
strcpy(arr, p);*/
strcpy(arr, "hello");//与上等效
/*char arr2[] = { 'a','b','c' };
strcpy(arr, arr2);*/ //err
/*char* str = "#########";
strcpy(str, "hello");*/ //err 源字符串为常字符串,不可改变
printf("%s\n", arr);//hello
return 0;
}
模拟strcpy
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* str)
{
assert(str && dest);
char* ret = dest;
while (*dest++ = *str++)
{
;
}
return ret;
}
int main()
{
char arr[20] = "#############";
my_strcpy(arr, "hello");
printf("%s\n", arr);//hello
return 0;
}
strcat
char * strcat ( char * destination, const char * source );
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 of the new string formed by the concatenation of both in destination.
1.源字符串必须以 '\0' 结束。2.会将源字符串中的 '\0' 拷贝到目标空间。
3.目标空间必须有足够的大,能容纳下源字符串的内容。
4.目标空间必须可修改。
5.字符串自己给自己追加会如何? 不可以自己追加,会将自己的'\0'覆盖掉,死循环
功能 - 将源字符串追加在目的字符串后面
代码演示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
char arr[20] = "hello ";
strcat(arr, "world");
printf("%s\n", arr);//hello world
return 0;
}
模拟strcat
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest)
{
dest++;
}
/*do
{
*dest = *src;
dest++;
src++;
} while (*src);*/
//简洁写法
while (*dest++ = *src++)
{
;
}
return ret;//返回目标空间的起始地址 意义:方便链式访问 - 返回值做另一个函数的参数
}
int main()
{
char arr[20] = "hello ";
//my_strcat(arr, "world");
printf("%s\n", my_strcat(arr, "world"));//hello world
return 0;
}
strcmp
int strcmp(const char* str1, const char* str2);
This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null - character is reached.
标准规定:(注意:比较的是两个字符串的首个不同字符的大小,而不是字符串长短)第一个字符串大于第二个字符串,则返回1;
第一个字符串等于第二个字符串,则返回0;
第一个字符串小于第二个字符串,则返回-1。
功能 - 比较字符串
代码演示
#include<stdio.h>
#include<string.h>
int main()
{
//char* p1 = "abc";
//char* p2 = "abcdef";
//if (p1 > p2)//比较的是两个字符串首字母地址大小
//{
// printf(">\n");
//}
//else
//{
// printf("<=\n");
//} //err
//if ("abc" > "abcdef")//比较的是两个字符串首字母地址大小
//{
// printf(">\n");
//}
//else
//{
// printf("<=\n");
//} //err
int ret1 = strcmp("abb", "ac");
printf("%d\n", ret1);//-1
int ret2 = strcmp("ab", "ab");
printf("%d\n", ret2);//0
int ret3 = strcmp("ac", "abc");
printf("%d\n", ret3);//1
return 0;
}
模拟strcmp
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* p1, const char* p2)
{
assert(p1 && p2);
//写法一
/*while (*p1 || *p2)
{
if (*p1 < *p2)
return -1;
else if (*p1 > *p2)
return 1;
p1++;
p2++;
}
return 0;*/
//写法二
while (*p1 == *p2)
{
if (*p1 == '\0')
return 0;
*p1++;
*p2++;
}
//此处可用 return *p1 - *p2;代替,二者等效
if (*p1 < *p2)
return -1;
else
return 1;
}
int main()
{
char* p1 = "ab";
char* p2 = "ac";
int ret = my_strcmp(p1, p2);
if (ret < 0)
printf("%s<%s\n",p1,p2);
else if (ret > 0)
printf("%s>%s\n",p1,p2);
else
printf("%s=%s\n",p1,p2);
return 0;
}
长度受限制的字符串函数 - strncpy、strncat、strncmp
下面将介绍strncpy、strncat、strncmp三个函数,与strcpy、strcat、strcmp三个函数相比,多个n,多个size_t num参数,长度受到限制。
strncpy
char * strncpy ( char * destination, const char * source, size_t num );
Copies the first 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.
1.拷贝num个字符从源字符串到目标空间。2.如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
代码演示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefg";
char arr2[] = "qwer";
strncpy(arr1, arr2, 2);
printf("%s\n", arr1);//qwcdefg
strncpy(arr1, arr2, 6);
printf("%s\n", arr1);//qwer
return 0;
}
strncat
char * strncat ( char * destination, const char * source, size_t num );
Appends the first num characters of source to destination, plus a terminating null - character.If the length of the C string in source is less than num, only the content up to the terminating null character is copied.
将源的前num个字符追加到目标,再加上一个终止字符'\0'。如果源中的C字符串长度小于num,则仅复制终止字符'\0'之前的内容。
代码演示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello ";//需要初始化足够大被追加
char arr2[] = "world";
strncat(arr1, arr2, 2);
printf("%s\n", arr1);//hello wo
}
strncmp
int strncmp(const char* str1, const char* str2, size_t num);
比较到前num个字符,比到出现一个字符不一样或者num个字符全部比完或者一个字符串结束全部比完。
代码演示
#include<stdio.h>
#include<string.h>
int main()
{
char* p1 = "abcdefg";
char* p2 = "abcqaer";
int ret = strncmp(p1, p2, 3);
printf("%d\n", ret);//0
ret = strncmp(p1, p2, 4);
printf("%d\n", ret);//-1
ret = strncmp(p1, p2, 5);
printf("%d\n", ret);//-1
return 0;
}
strstr
char * strstr ( const char *str1, const char *str2 );
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
返回指向str1中第一个出现的str2的指针,如果str2不是str1的一部分,则返回空指针。
功能 - 在str1字符串中查找str2字符串
代码演示
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "bcd";
char* ret = strstr(arr1, arr2);//在arr1中查找是否包含arr2数组
if (ret == NULL)
printf("没找到\n");
else
printf("找到了:%s\n", ret);//找到了:bcdefabcdef
return 0;
}
模拟strstr
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
if (*str2 == '\0')
return (char*)str1;
const char* s1, *s2, *cp = str1;
while (*cp)
{
s1 = cp;
s2 = str2;
while ((*s1 == *s2) && *s1 && *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)cp;
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "bcd";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
printf("没找到\n");
else
printf("找到了:%s\n", ret);//找到了:bcdefabcdef
return 0;
}
strtok
char* strtok(char* str, const char* sep);
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向此段首字符的指针。
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
功能 - 分割字符串
如:
将192.168.3.122分割成 此处 . 为分隔符
192
168
3
122将kyg@abc.qwe分割成 此处 @ 和 . 为分隔符
kyg
abc
qwe
代码演示
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "kyg@abc.qwe";
char* p = "@.";
char tmp[20] = { 0 };
strcpy(tmp, arr);
//strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
char* ret = NULL;
//
ret = strtok(tmp, p);//kyg@abc.qwe\0 -> kyg\0abc.qwe\0 - 返回指向k的指针,并保存原 @ 的位置
//strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
printf("%s\n", ret);//kyg
ret = strtok(NULL, p);//kyg\0abc.qwe\0 -> kyg\0abc\0qwe\0 - 返回指向a的指针,并保存原 . 的位置
//strtok函数的第一个参数为 NULL ,函数将在上一个字符串中被保存的位置开始,查找下一个标记。
printf("%s\n", ret);//abc
ret = strtok(NULL, p);//kyg\0abc\0qwe\0 - 返回指向q的指针,并保存最后\0的位置
printf("%s\n", ret);//qwe
ret = strtok(NULL, p);
//如果字符串已结束,则返回 NULL 指针。
printf("%s\n", ret);//(null)
//以上部分可简单写为下面代码
/*for (ret = strtok(tmp, p); ret != NULL; ret = strtok(NULL, p))
{
printf("%s\n", ret);
}*/
return 0;
}
strerror
char* strerror(int errnum);
返回错误码所对应的错误信息(字符串)的首字符地址。
功能 - 调用库函数失败时,都有设置错误码,strerror可返回错误码所对应的错误信息。
int errno; - 全局的错误码
代码演示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
//printf("%s\n", strerror(0));//No error
//printf("%s\n", strerror(1));//Operation not permitted
//printf("%s\n", strerror(2));//No such file or directory
//printf("%s\n", strerror(3));//No such process
FILE* pf = fopen("test.txt", "r");//以读的方式打开test.txt文件,打开失败会返回NULL空指针
if (pf == NULL)
{
printf("%s\n", strerror(errno));//No such file or directory - 没有这个文件或文件夹
return 1;//若打开失败,则返回1终止代码
}
//...省略读文件一系列操作代码
fclose(pf);//关闭文件
pf = NULL;
return 0;
}
补充:perror函数
void perror( const char *string ); 头文件 - stdio.h
strerror只是返回错误码所对应的错误信息;而perror会直接打印出错误信息,使用很方便。
代码演示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
perror("error");//No such file or directory - 没有这个文件或文件夹
return 1;//若打开失败,则返回1终止代码
}
//...省略读文件一系列操作代码
fclose(pf);//关闭文件
pf = NULL;
return 0;
}
打印结果
perror函数的参数为一个字符串,可自己随意确定;
由打印结果可以看出,perror函数会先打印出参数字符串并在其后加上:和一个空格,然后才是错误信息字符串。