[C语言] 字符串函数的相关介绍与模拟实现
Table of Contents

字符串函数 Link to 字符串函数

strlen Link to strlen

C
1
size_t strlen(const char* str );

作用:

​ 求字符串中'\0'前的字符串的长度

要求:

​ 字符串必须以'\0' 结束

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* 可创建临时变量 */
int my_strlen(const char* str) {
    assert(str);
    int count = 0;
    
    while(*str++)
  		count++;
    
    return count;
}

/* 不可创建临时变量 (递归)*/
int my_strlen(const char* str) {
	if(!(*str))
		return 0;
	else
		return 1+my_strlen(str+1);
}

/* 指针相减 */
int my_strlen(char* str) {
	char *pstr = str;
	while(*pstr)
		pstr++;
    
	return pstr-str;
}

标准库中, strlen()的返回值是size_t, 也就是 unsigned int无符号整型

在使用函数的时候, 如果没有注意到, 就可能写出下面这样的代码:

C
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#include <string.h>

int main() {
	if(strlen("asd") - strlen("asdasd") > 0)
           printf(">\n");
    else
           printf("<=\n");

	return 0;
}

这段代码最终输出的是 >

因为两个无符号整型相减, 结果肯定也是无符号整型, 所以结果肯定是大于 0

模拟实现的my_strlen返回值是 int 类型, 不会出现如果不小心写出错误的代码的问题

strcpy Link to strcpy

C
1
char* strcpy(char* dest, const char* source );

作用:

​ 将 source 字符串中的内容, 包括'\0', 拷贝至dest字符串中

要求:

source中必须存在 '\0'; dest空间必须足够大且可修改, 即不被 const 修饰

C
1
2
3
4
5
6
7
8
9
char* my_strcpy(char* dest, const char* src) {
    char* ret = dest;
    assert(dest && src);
    
    while(*dest++ = *scr++)
        ;
    
    return ret;
}

strcat Link to strcat

C
1
char* strcat (char* dest, const char* source);

作用:

​ 将 字符串source的内容, 追加到字符串dest

要求:

​ 字符串source必须以'\0'结束;dest指向空间足够大且可修改

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
char* my_strcat(char* dest, const char* src) {
    char* ret = dest;
    assert(dest && src);
    
    while(*dest) {
        // 注意: 循环里的"++" 不能放入循环条件里: 
        // 若放至 dest 后, 会跳过原 dest 中的 '\0';若放至 dest 前, 如果 dest 首字符为'\0'也会被跳过
        dest++;
    }
    while(*dest++ = *src++)
        ;
  	
    return ret;
}

strcmp Link to strcmp

C
1
int strcmp (const char* str1, const char* str2);

作用:

​ 比较两个字符串, 对应位置上字符的大小

str1 > str2: 返回一个正数

str1 < str2: 返回一个负数

str1 == str2: 返回零

C
1
2
3
4
5
6
7
8
9
10
11
12
13
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;
}

strncpy Link to strncpy

C
1
2
/* 受长度限制的字符串拷贝函数 */
char* strncat (char* dest, const char* source, size_t num);

作用:

​ 将 字符串source中的前 num 个字符, 拷贝到 字符串dest

​ 如果num大于 字符串 source 的长度, 多出的部分均存入'\0'

strncat Link to strncat

C
1
char* strncat (char* dest, const char* source, size_t num);

受长度限制的字符串追加函数

作用: 将 字符串source中的前 num 个字符, 追加到 字符串dest后(从第一个'\0'开始算), 并在末尾放入'\0'

(如果 num 大于 字符串 source 的长度, 则只追加已有的source字符串及末尾的 '\0')

strncmp Link to strncmp

C
1
int strncmp (const char* str1, const char* str2, size_t num);

受长度限制的字符串比较函数

作用: 比较 字符串 str2str1 对应的前 num 个字符的大小

strstr Link to strstr

C
1
char* strstr(const char* string, const char* strCharSet);

作用: 在 字符串string中, 查找第一个strCharSet字符串;若strCharSet指向长度为零的字符串(即, strCharSet为空), 则返回原字符串, 没找到返回空指针, 找到了返回找到的字符串的首字符地址

模拟实现 strstr()

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char* my_strstr(const char* str, const char* substr) {
    assert(str && substr);
    
    if(*substr == '\0')
        return str;
    
    char* flag = (char*)str;	// 记录本次查找的起始地址
    char* str1;
    char* str2;					// 记录 查找的字符串
    
    while(*flag) {
        str1 = flag;			// 因本次查找中 起始位置需要一直知道, 所以将 flag 存入另一个指针变量
        str2 = (char*)substr;	// 每次循环从 查找字符串的首字符开始查找
        while(*st1 && *str2 && (*str1 == str2)) {
            /*在此循环中查找, str1 与 str2 指向的字符都不为'\0', 且 相等时, 继续查找下一个字符str2指向的字符为'\0'时, 查找成功*/
            str1++;
            str2++;
        }
        
        if(*str2 == '\0')
            return flag;
        
        flag++;
	}
    
    return NULL;
}

strtok Link to strtok

PLAINTEXT
1
char * strtok ( char * str, const char * sep );

作用: 将字符串分割成一个个片段(自己设定分隔符)

  • sep参数是个字符串, 定义了用作分隔符的字符集合第一个参数指定一个字符串, 它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。

  • strtok函数找到str中的下一个标记, 并将其用 \0 结尾, 返回一个指向这个标记的指针。(注: strtok函数会改变被操作的字符串, 所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

  • strtok函数的第一个参数不为 NULL , 函数将找到str中第一个标记, strtok函数将保存它在字符串中的位置。

  • strtok函数的第一个参数为 NULL, 函数将在同一个字符串中被保存的位置开始, 查找下一个标记。如果字符串中不存在更多的标记, 则返回 NULL 指针。

    即:

    1. strtok函数在使用的时候, 因为会改变参数, 所以第一个参数需要是目标参数的临时拷贝

    2. strtok函数在找第一个标记的时候, 函数的第一个参数不是NULL

    3. strtok函数在找非第一个标记的时候, 函数的第一个参数不是NULL

    例:

    C
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const char* p = "@.";
    char arr[] = "July3@blog.csdn.net";
    char arr_copy[50] = { 0 };
    strcpy(arr_copy, arr);
    char* str = NULL;
    for(str = strtok(buf, p); str != NULL; str = strtok(NULL, p))
    {
      printf("%s\n", str);
    }
    

##. strerror

C
1
char * strerror ( int errnum );

作用: 返回错误码, 所对应的错误信息。

C
1
2
3
4
5
6
7
8
9
int main()
{
   int i = 0;
   for(int i = 0; i < 10; i++)
       printf(" %s\n", strerror(i));
   
   return 0;
}
// 此段代码可测试输出各错误码表示的错误信息

实际操作:

在执行某些操作时, 可能会遇到一些错误, 这时候就需要到这个函数了

例如: C语言操作文件时, 遇到错误时

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// fopen 函数可以操作文件(返回值, 参数, 头文件等具体问题, 看MSDN)
// 当库函数使用错误时, 会将 errno(C语言提供的全局变量,可直接使用, 需要头文件 errno.h) 赋值为此次库函数使用错误时的错误码
#include <errno.h>

int main()
{
   //打开文件
   FILE* pf = fopen("july3.txt", "r");
   if(NULL == pf)
   {
       printf("%s\n", strerror(errno));
       return 0;
   }
   //读文件
   
   //关闭文件
   fclose(pf);
   pf = NULL;
   
   return 0;
}

字符分类、字符转换函数 Link to 字符分类、字符转换函数

字符分类函数如果他的参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符: 空格' ', 换页'\f', 换行'\n', 回车'\r', 制表符'\t'或者垂直制表符 '\v'
isdigit十进制数字 0~9
isxdigit十六进制数字, 包括所有十进制数字, 小写字母a~f, 大写字母A~F
islower小写字母a~z
isupper大写字母A~Z
isalpha字母a~zA~Z
isalnum字母或者数字, a~z,A~Z,0~9
ispunct标点符号, 任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符, 包括图形字符和空白字符
字符转换函数作用
tolower大写字母转小写字母
toupper小写字母转大写字母
Thanks for reading!

[C语言] 字符串函数的相关介绍与模拟实现

Wed Feb 09 2022
2028 字 · 12 分钟

© 哈米d1ch | CC BY-SA 4.0