humid1ch blogs

本篇文章

手机用户建议
PC模式 或 横屏
阅读


C语言 2022 年 2 月 9 日

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

strlen、strcpy、strcat……

字符串函数

1. strlen

size_t strlen(const char* str );
作用:求字符串中'\0'前的字符串的长度
要求:字符串必须以'\0' 结束
示例
模拟实现 strlen
/* 可创建临时变量 */
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;
}
在MSDN中, strlen函数的返回值是size_t, 也就是 unsigned int无符号整型。返回值是无符号整型,我们在使用函数的时候,如果没有注意到,就可能写出下面这样的代码:
#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 类型,就不会出现如果不小心写出错误的代码的问题。

2. strcpy

char* strcpy(char* destination, const char* source );
作用:将 source 字符串中的内容(包括'\0'),拷贝至destination字符串中
要求:被拷贝的字符串(soure)中必须有 '\0'; destination空间必须足够大且可变(不被 const 修饰)
示例
模拟实现 strcpy
char* my_strcpy(char* dest, const char* src)
{
    char* ret = dest;
    assert(dest && src);
    
    while(*dest++ = *scr++)
    {
        ;
    }
    
    return ret;
}

3. strcat

char* strcat (char* destination, const char* source);
作用:将 字符串source的内容,追加到字符串destination
要求:字符串source必须以'\0'结束;字符串destination空间足够大且可修改
示例
模拟实现 strcat
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;
}

4. strcmp

int strcmp (const char* str1, const char* str2);
作用:比较两个字符串,对应位置上字符的大小

str1 > str2: 返回一个正数

str1 < str2: 返回一个负数

str1 == str2: 返回零

示例
模拟实现 strcmp
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;
}

5. strncpy

char* strncat (char* destination, const char* source, size_t num);
受长度限制的字符串拷贝函数
作用:将 字符串source中的前 num 个字符,拷贝到 字符串destination中。
(如果 num 大于 字符串 source 的长度,多出的部分均存入 '\0')

6. strncat

char* strncat (char* destination, const char* source, size_t num);
受长度限制的字符串追加函数
作用:将 字符串source中的前 num 个字符,追加到 字符串destination后(从第一个'\0'开始算),并在末尾放入'\0'
(如果 num 大于 字符串 source 的长度,则只追加已有的source字符串及末尾的 '\0')

7. strncmp

int strncmp (const char* str1, const char* str2, size_t num);
受长度限制的字符串比较函数
作用:比较 字符串 str2str1 对应的前 num 个字符的大小

8. strstr

char* strstr(const char* string, const char* strCharSet);
作用:在 字符串string中,查找第一个strCharSet字符串;若strCharSet指向长度为零的字符串(即,strCharSet为空),则返回原字符串,没找到返回空指针,找到了返回找到的字符串的首字符地址。
示例
模拟实现 strstr
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;
}

9. strtok

char * strtok ( char * str, const char * sep );
作用:将字符串分割成一个个片段(自己设定分隔符)
  • sep参数是个字符串,定义了用作分隔符的字符集合第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。

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

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

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

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

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

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

    例:

    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);
    }

10. strerror

char * strerror ( int errnum );
作用:返回错误码,所对应的错误信息。
int main()
{
   int i = 0;
   for(int i = 0; i < 10; i++)
       printf(" %s\n", strerror(i));
   
   return 0;
}
// 此段代码可测试输出各错误码表示的错误信息

实际操作:

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

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

// 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;
}

字符分类、字符转换函数

字符分类函数如果他的参数符合下列条件就返回真
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小写字母转大写字母