字符函数与字符串函数
字符函数与字符串函数
- 1、 strcmp 函数
- 1.1、使用
- 1.2、模拟实现
- 2、字符分类函数和字符转换函数
- 2.1、字符分类函数
- 2.1、字符转换函数
- 2.3、实践
- 3、strlen 函数
- 3.1、使用
- 3.1、模拟实现
- 4、`strcpy()`函数
- 4.1、使用
- 4.2、模拟实现
- 5、`strcat()`函数
- 5.1、使用
- 5.2、模拟实现
- 6、`strncpy()`
- 6.1、使用
- 7、`strncat()`
- 7.1、使用
- 8、`strncmp()`
- 8.1、使用
- 9、`strstr()`
- 9.1、使用
- 9.2、模拟实现
- 10、`strtok()`
- 10.1、使用
- 11、`strerror()`
- 11.1、使用
- 11.2、`perror()`
1、 strcmp 函数
1.1、使用
strcmp 函数的声明:
int strcmp(const char* str1, const char* str2);
使用函数时,包含头文件string.h
。返回类型是 int 类型,输入参数都是 char* 类型。
函数开始时,从每个字符串的第一个字符出发,比较其ASCII值的大小,若相等,则分别进行至下一个,直到出现ASCII值不相等,或转义字符\0
的出现。
不同情况下的返回值:
返回值 | 情况 |
---|---|
大于0 | 第一个字符串中字符的ASCII值大于对应第二个字符串的 |
0 | 所有字符相匹配相匹配 |
小于0 | 第一个字符串中字符的ASCII值小于对应第二个字符串的 |
比如,我们来比较两个字符串:
#include<stdio.h>
#include<string.h>int main()
{char ch1[] = "abq";char ch2[] = "abcdef";int ret = strcmp(ch1, ch2);if (ret > 0)printf("ch1 > ch2");//语句1else if (ret < 0)printf("ch1 < ch2");//语句2elseprintf("ch1 == ch2");//语句3return 0;
}
结果输出语句1。
1.2、模拟实现
模拟实现,要达到函数的返回类型、参数、功能与原函数一致。
在设计的函数中,我们接收到两个字符串首元素的地址。若要挨个进行比较,我们可以使用while
循环。循环的条件是两个字符相等。
当两个字符串不相等时,我们可以返回对应两个地址解引用后做差的差值。当两个字符串相等,即进行到最后都出现\0
时,我们可以在while
循环中直接返回0。
设计的代码如下:
#include<stdio.h>
#include<assert.h>int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0')return 0;str1++;str2++;}return *str1 - *str2;
}int main()
{char ch1[] = "abq";char ch2[] = "abcdef";int ret = my_strcmp(ch1, ch2); if (ret > 0)printf("ch1 > ch2");else if (ret < 0)printf("ch1 < ch2");elseprintf("ch1 == ch2");return 0
}
2、字符分类函数和字符转换函数
都要包含头文件<ctype.h>
。
2.1、字符分类函数
以islower()
为例:
int islower(int c);
如果是小写字母,返回非0值;如果不是,返回0。
2.1、字符转换函数
C语言提供了两个字符转换函数:
int toupper(int c);//小写转大写
int tolower(int c);//大写转小写
2.3、实践
比如,将一个字符串中的小写字母,全部转换成大写字母:
#include<stdio.h>
#include<ctype.h>int main()
{char ch[] = "Hello World";char c;int i = 0;while (ch[i] != '\0'){c = ch[i];if (islower(ch[i]))//判断小写{c = toupper(ch[i]);//改成大写}putchar(c);i++;}return 0;
}
3、strlen 函数
size_t strlen(const char* p1);
3.1、使用
#include<stdio.h>
#include<string.h>int main()
{printf("%zd\n", strlen("abc"));return 0;
}
3.1、模拟实现
可利用指针遍历。
1、使用计数器
#include<stdio.h>
#include<assert.h>size_t my_strlen(const char* p)
{size_t count = 0;//计数器char* s = p;assert(s && p);while (*s != '\0'){count++;s++;}return count;
}int main()
{char ch[] = "abc";printf("%zd\n", my_strlen(ch));return 0;
}
2、使用指针运算
#include<stdio.h>
#include<assert.h>size_t my_strlen(const char* p)
{char* s = p;assert(s && p);while (*s != '\0'){s++;}return s - p;//指针运算
}int main()
{char ch[] = "abc";printf("%zd\n", my_strlen(ch));return 0;
}
3、使用函数递归
#include<stdio.h>
#include<assert.h>size_t my_strlen(const char* p)
{char* s = p;assert(s && p);if (*s == '\0')return 0;elsereturn 1 + my_strlen(p + 1);
}int main()
{char ch[] = "abc";printf("%zd\n", my_strlen(ch));return 0;
}
4、strcpy()
函数
声明
char* strcpy(char* dest, const char* src);
strcpy()
函数输入的参数为destination(目的地,相当于粘贴上的地方)和source(源头,相当于拷贝的地方),都为各自字符串数组首元素的地址。返回值是目的地字符串数组首元素的地址。
4.1、使用
#include<stdio.h>
#include<string.h>int main()
{char ch1[] = "abc";char ch2[30] = "xxxxxxxxxxxx";printf("%s\n", ch2);char* ret = strcpy(ch2, ch1);printf("%s\n", ret);return 0;
}
注意:
- 源字符串必须以
'\0'
结束。 - 会将源字符串中的
'\0'
拷贝到目标空间。 - 目标空间必须足够大,可修改。
4.2、模拟实现
#include<stdio.h>
#include<assert.h>char* my_strcpy(char* dest, const char* src)
{char* ret = dest;assert(dest && src);while ((*dest++ = *src++)){;}return ret;
}int main()
{char ch1[] = "abc";char ch2[30] = "xxxxxxxxxxxx";printf("%s\n", ch2);char* ret = my_strcpy(ch2, ch1);printf("%s\n", ret);return 0;
}
解释关键点:
- 语句
char* ret = dest;
用来保证函数最后返回的是拷贝后目标字符串(数组)首元素的地址。 - 语句
*(dest++ = *src++)
可以理解为,先分别进行取地址操作,然后赋值,再分别跳到下一个字符的地址。 while
循环内什么都不干,空语句。
5、strcat()
函数
strcat()
函数,是用来添加字符串的。
5.1、使用
char* strcat(char* dest, const char* src);
与strcpy()
函数类似,只不过拷贝变成了加在后面。
比如:
#include<stdio.h>
#include<string.h>int main()
{char ch1[30] = "abc";char ch2[] = "def";printf("%s\n", ch1);printf("%s\n", strcat(ch1, ch2));return 0;
}
注意:
- 源字符串必须以
'\0'
结束。 - 目标字符串也得有
'\0'
,否则不知道在哪里追加。 - 目标空间必须足够大,可修改。
5.2、模拟实现
#include<stdio.h>
#include<assert.h>char* my_strcat(char* dest, const char* src)
{char* ret = dest;assert(dest && src);while (*dest){dest++;}while ((*dest++ = *src++)){;}return ret;
}int main()
{char ch1[30] = "abc";char ch2[] = "def";printf("%s\n", ch1);printf("%s\n", my_strcat(ch1, ch2));return 0;
}
解释关键点:
- 第一个
while
循环是找到目标字符串的'\0'
。 - 第二个
while
循环,相当于拷贝。
6、strncpy()
从源字符串拷贝num个字符到目标空间(从目标空间的首地址开始)
6.1、使用
声明:
char* strncpy(char* destination, const char* source);
destination
: 指向目标空间。source
: 指向原字符串。num
: 要拷贝的字符数。- 该函数返回拷贝后目标空间起始地址。
代码实现:
#include<stdio.h>
#include<string.h>int main()
{char dest[100] = { "xxxxxxxxxxxxxxxxxxxx" };char src[] = "abcde";char* ret = strncpy(dest, src, 4);printf("%s\n", ret);return 0;
}
注意:
- 目标空间必须足够大,不然报错。
- 拷贝时不会将原字符串的
'\0'
拷贝进来,也就是说原字符串无需包含'\0'
。 - 若原字符串个数小于
num
,补’\0’;若大于num
,拷贝到num
个字符串为止。
7、strncat()
将源字符串首地址开始num个字符,添加到到目标空间(从目标空间的首地址开始)
7.1、使用
char* strncat(char* destination, const char* source);
destination
: 指向目标空间。source
: 指向原字符串。num
: 要添加的字符数。- 该函数返回添加后目标空间起始地址。
代码实现:
#include<stdio.h>
#include<string.h>int main()
{char dest[100] = { "xxxxxxxxx\0xxxxxxxxxxx" };char src[] = "abcd";char* ret = strncat(dest, src, 6);printf("%s\n", ret);return 0;
}
注意:
- 目标空间必须足够大。
- 添加时,会识别目标空间中
\0
的位置,并在其首地址处添加原字符串,之后以\0
结尾。 - 若原字符串个数小于
num
,只会将原字符串到\0
的内容整个拷贝过去,不会另外添加任何东西。
8、strncmp()
与strcmp()
类似,只不过限定了要比较字符的个数
8.1、使用
声明:
int strncmp(const char* str1; const char* str2; size_t num);
str1
: 指向第一个字符串。str2
: 指向第二个字符串。num
: 要比较的字符数。
返回类型的情况:
返回值 | Value |
---|---|
大于0 | 指定字符数下,第一个字符串比第二个大 |
0 | 指定字符数下,相匹配 |
小于0 | 指定字符数下,第一个字符串比第二个小 |
代码实现:
#include<stdio.h>
#include<string.h>int main()
{char ch1[] = "abcdef";char ch2[] = "abcfer";int ret = strncmp(ch1, ch2, 3);if (ret > 0)printf(">\n");else if (ret < 0)printf("<\n");elseprintf("==\n");return 0;
}
9、strstr()
在str1指向的字符串中,找到str2指向的字符串的位置。
9.1、使用
声明:
char* strstr(const char* str1, const char* str2);
str1
: 指向被查找的字符串。str2
: 指向要查找的内容。- 该函数返回被查找内容中,要查找字符串的起始地址。
代码实现:
#include<stdio.h>
#include<string.h>int main()
{char ch1[1000] = "This is a sample string.";printf("%s\n", ch1);char ch2[] = "sample";char* ret1 = strstr(ch1, ch2);printf("%s\n", ret1);char* ret2 = strncpy(ret1, "simple", 6);printf("%s\n", ch1);return 0;
}
注意:
- 若找到,返回的是第1次出现的位置;若未找到,返回
NULL
。 - 字符串的比较,不包括’\0’,以’\0’为结束标志。
9.2、模拟实现
代码及详解如下:
#include<stdio.h>char* my_strstr(const char* str1, const char* str2)
{char* p = (char*)str1;//正确位置的标记char* s1 = (char*)str1;//可移动的匹配指针char* s2 = (char*)str2;//可移动的匹配指针if (*s2 == '\0')//当要查找的内容为空,直接返回被查找内容首地址return (char*)str1;while (*p != '\0')//对于被查找内容,从开始到'\0'结束,挨个查找{s1 = p;//对于被查找内容的匹配指针,未匹配成功的每一次匹配,最后都要返回至跳过一个字节后的pchar* s2 = (char*)str2;//未匹配成功的每一次匹配后,都要返回起始位置while ((*s1 != '\0') && (*s2 != '\0') && (*s1 == *s2))//一个字节匹配成功,再匹配下一个{s1++, s2++;}if (*s2 == '\0')//要找内容遍历完了,找到了return(p);p++; //若有匹配不成功,跳出循环,p跳过一个字节,重复过程}return(NULL);//其他任何情况,都视为未找到
}int main()
{char ch1[] = "abbcd";char ch2[] = "bbc";char* ret = my_strstr(ch1, ch2);printf("%s\n", ret);return 0;
}
10、strtok()
将字符串中特定的字符,转换为\0
。
10.1、使用
声明:
char* strtok(char* str, const char* sep);
str
: 指向要被分隔的字符串。sep
: 指向分隔符。- 函数返回
\0
前字符串的首地址
代码实现:
#include<stdio.h>
#include<string.h>int main()
{char ch[] = "145440@qq.com";char sep[] = "@.";printf("%s\n", strtok(ch, sep));return 0;
}
注意:
strtok()
会直接改变原字符串,所以使用时应先复制。- 若想得到所有被分割的部分,只需在下次调用函数时,将第一个参数改为
NULL
。 - 若可转换的标记已经没有了,再调用函数,就返回
NULL
。
根据(2),可以有以下代码:
#include<stdio.h>
#include<string.h>int main()
{char ch1[] = "1404406905@qq.com";char ch2[10000];char* ret = strcpy(ch2, ch1);//clonechar sep[] = "@.";char* str;for (str = strtok(ret, sep); str != NULL; str = strtok(NULL, sep)){printf("%s\n", str);}return 0;
}
11、strerror()
找到错误码对应的错误信息。
11.1、使用
声明:
char* strerror(int errnum);
- 输入参数为错误码。
- 函数返回错误信息字符串首地址。
看看几个错误码:
#include<stdio.h>
#include<string.h>
#include<errno.h>int main()
{for (int i = 0; i <= 10; i++){printf("%d: %s\n", i, strerror(i));}return 0;
}
代码示例:
#include<stdio.h>
#include<string.h>
#include<errno.h>int main() {FILE* pFile;pFile = fopen("Data.txt", "r");if (pFile == NULL)printf("Error opening file Data.txt: %s\n", strerror(errno));return 0;
}
补充:
- C语言可以打开文件。
- 打开文件用
fopen()
函数。如果以读的形式打开,文件又不存在,fopen()
函数将错误码存放在errno
中,并返回NULL
。
如果不想像上面代码中printf()
部分那么麻烦,可以使用perror()
函数。
11.2、perror()
在该函数中,输入说明信息,函数将在屏幕上打印信息、冒号、一个空格,以及错误码对应的错误信息:
#include<stdio.h>
#include<string.h>
#include<errno.h>int main() {FILE* pFile;pFile = fopen("Data.txt", "r");if (pFile == NULL)perror("Error opening file Data.txt");return 0;
}
使用该函数,使代码更简洁,但也丧失了灵活性。