字符函数和字符串函数的介绍 ---- 学习笔记分享

⽬录:

(1)字符分类函数

(2)字符转换函数

(3)strlen的使用和模拟实现

(4)strcpy的使用和模拟实现

(5)strcat的使用和模拟实现

(6)strcmp的使用和模拟实现

(7)strncpy函数的使用

(8)strncat函数的使用

(9)strncmp函数的使用

(10)strstr的使用和模拟实现

(11)strtok函数的使用

(12)strerror函数的使用

(13)perror函数的使用

在编程的过程中,我们经常要处理字符和字符串,为了⽅便操作字符和字符串,C语⾔标准库中提供了 ⼀系列库函数,接下来我们就学习⼀下这些函数。

先区别一下各种0:

0 --- 数字0;

'0' --- 数字字符0 --- ASCII码值是48

\0 --- \ddd形式 --- 特殊转义字符 --- ddd表示1~3个8进制数字 --- \0 --- 就是一个八进制0 --- 就是0 --- ASCII码值为0

NULL --- 指针专属的0

1. 字符分类函数

C语言中有⼀系列的函数是专门做字符分类的,也就是⼀个字符是属于什么类型的字符的。 这些函数的使⽤都需要包含⼀个头文件是 ctype.h

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

这些函数的使用方法非常类似,我们就讲解⼀个函数的事情,其他的非常类似:

int islower ( int c );//传递的是字母或者字母的ASCII码值

islower 是能够判断参数部分的 c 是否是小写字母的。 通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0;

//写一个代码,将字符串中的小写字母转大写,其他字符不变
#include <stdio.h>
#include <ctype.h>
int main ()
{
    int i = 0;
    char str[] = "Test String.\n";
    char c;
    while (str[i])
    {
        c = str[i];
        if (islower(c)) 
            c -= 32;
        putchar(c);
        i++;
    }
    return 0
}
2. 字符转换函数

C语言提供了两个字符转换函数

int tolower(int c);//将参数传进去的大写字母转小写字母
int toupper(int c);//将参数传进去的小写字母转大写字母

用例:

#include <stdio.h>
#include <ctype.h>
int main ()
{
    int i = 0;
    char str[] = "Test String.\n";
    char c;
    while (str[i])
    {
        c = str[i];
        if (islower(c)) 
            c = toupper(c);
        putchar(c);
        i++;
    }
    return 0;
}

接下来的都是字符串函数

3. strlen的使用和模拟实现
3.1 strlen的使用
size_t strlen ( const char * str );

1.字符串以'\0'作为结束标志,strlen函数返回的实在字符串中'\0'前面出现的字符个数(不包含'\0')

2.参数指向的字符串必须要以'\0'结束

3.注意函数的返回值为size_t,是无符号的(易错)

4.strlen的使用必须包含头文件string.h

3.2 strlen的模拟实现

方式1:

//计数器⽅式
int my_strlen(const char * str)
{
    int count = 0;
    assert(str != NULL); //包含assert.h头文件
    while(*str)
    {
        count++;
        str++;
    }
    return count;
}

方式2:递归

//不能创建临时变量计数器
int my_strlen(const char * str)
{
    assert(str != NULL);
    if(*str == '\0')
        return 0;
    else
        return 1+my_strlen(str+1);
 }

方式3:

//指针-指针的⽅式
int my_strlen(char *s)
{
    assert(str != NULL);
    char *p = s;
    while(*p != '\0' )
        p++;
    return p-s;
 }
4. strcpy的使用和模拟实现
4.1 strcpy的使用
char * strcpy ( char * destination, const char * source );

复制字符串

source 指向的 C 字符串复制到 destination 指向的数组中,包括终止 null 字符(并在该点停止)。

为避免溢出,destination 指向的数组的大小应足够长,以包含与 source 相同的 C 字符串(包括终止 null 字符),并且不应在内存中与 source 重叠。

strcpy函数返回的是目标空间的起始地址。

注意:

(1)源头的字符串中必须包含\0,没有\0的话,strcpy不能结束!

(2)目标空间必须足够大,避免溢出

例:

#include <stdio.h>
#include <string.h>
int main ()
{
    char str1[]="Sample string";
    char str2[40];
    char str3[40];
    strcpy (str2,str1);
    strcpy (str3,"copy successful");
    printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);
    return 0;
}

易错类型:

int main()
{
    char arr1 = "hello world";
    char* p = "xxxxxxxxxxxxxxxxxxxxxx";//常量字符串不能被修改,否则程序会崩
    strcpy(p,arr1);//err
    printf("%s\n",p);
    return 0;
}
​
4.2 strcpy的模拟实现
char* my_strcpy(char *dest, const char*src)
{        
    char *ret = dest;
    assert(dest != NULL);
    assert(src != NULL);
    while((*dest++ = *src++))// '\0'的ASCII值是0
    {
        ;
    }
    return ret;//strcpy函数返回的是目标空间的起始地址
}
​
int main()
{
    char arr1[] = "abcdef";
    char arr2[20] = {0};
    my_strcpy(arr2,arr1);
    printf("%s\n",arr2);//打印abcdef
    printf("%s\n",my_strcpy(arr2,arr1));//打印abcdef
    return 0;
}
5. strcat的使用和模拟实现
5.1 strcat的使用
char * strcat ( char * destination, const char * source );

连接字符串

字符串的副本附加到目标字符串。destination 中终止的 null 字符将被 source 的第一个字符覆盖,并且 null 字符包含在 destination 中由两者串联形成的新字符串的末尾。

destinationsource 不得重叠。

  • destination

    Pointer to the destination array, which should contain a C string, and be large enough to contain the concatenated resulting string.

    指向目标数组的指针,该数组应包含 C 字符串,并且足够大以包含串联的结果字符串。

  • source

    C string to be appended. This should not overlap destination.

    C 字符串。这不应与 destination 重叠。

注意:

(1)返回的也是目标空间的起始地址

(2)目标空间必须足够大,要能再容纳下源字符串的内容

(3)源字符串必须以\0结束

(4)目标字符串也得有\0,否则没办法知道追加从哪里开始

(5)目标空间必须可以修改(不能是常量字符串)

例:

#include <stdio.h>
#include <string.h>
​
int main ()
{
    char str[80];
    strcpy (str,"these ");
    strcat (str,"strings ");
    strcat (str,"are ");
    strcat (str,"concatenated.");
    puts (str);//打印these strings are concatenated.
    return 0;
}
3.2 strcat的模拟实现
char *my_strcat(char *dest, const char*src)
{
    char *ret = dest;
    assert(dest != NULL);
    assert(src != NULL);
    //1.找到目标空间的\0
    while(*dest)
    {
        dest++;
    }
    //2.拷贝
    while((*dest++ = *src++))
    {
        ;
    }
    return ret;//返回目标空间的起始地址
}
​
int main()
{
    char arr1[20] = "hello ";
    char arr2[] = "world";
    my_strcat(arr1,arr2);//字符串追加
    printf("%s\n",arr1);
    return 0;
}

易错点:不能strcat(arr,arr); \0被覆盖了,某些编译器会死循环,strcat不保证自己给自己追加能顺利完成

6. strcmp的使用和模拟实现
6.1 strcmp的使用
int strcmp ( const char * str1, const char * str2 );

比较两个字符串

将 C 字符串 str1 与 C 字符串 str2 进行比较。

此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续处理以下对,直到字符不同或到达终止 null 字符。注意:比较的不是字符串的长度,而是字符串对应位置上的字符(ASCII码值)的大小

此函数执行字符的二进制比较。有关考虑特定于区域设置的规则的函数,请参阅 strcoll

  • str1

    要比较的 C 字符串。

  • str2 的

    要比较的 C 字符串。

返回一个整数值,该值指示字符串之间的关系:

返回值表明
<0第一个不匹配的字符在 PTR1 中的值低于 PTR2 中的值
0两个字符串的内容相等
>0第一个不匹配的字符在 PTR1 中的值大于 PTR2 中的值

用例:

#include <stdio.h>
#include <string.h>
int main ()
{
    char key[] = "apple";
    char buffer[80];
    do {
        printf ("Guess my favorite fruit? ");
        fflush (stdout);
        scanf ("%79s",buffer);
    } while (strcmp (key,buffer) != 0);
    puts ("Correct answer!");
    return 0;
}

• 标准规定:

(1)第⼀个字符串大于第⼆个字符串,则返回大于0的数字

(2)第⼀个字符串等于第⼆个字符串,则返回0

(3)第⼀个字符串小于第⼆个字符串,则返回小于0的数字

(4)那么如何判断两个字符串?比较两个字符串中对应位置上字符ASCII码值的大小

6.2 strcmp的模拟实现
int my_strcmp (const char * str1, const char * str2)
{
    int ret = 0 ;
    assert(str1 != NULL);
    assert(str2 != NULL);
    while(*str1 == *str2)
    {
        if(*str1 == '\0')
            return 0;
        str1++;
        str2++;
    }
    return *str1-*str2;
}
​
int main()
{
    char arr1[] = "abcdef";
    char arr2[] = "abcde";
    int ret = my_strcmp(arr1,arr2);
    printf("%d\n",ret); 
    return 0;
}
对于7 8 9中
strncpy strncat strncmp是长度受限制的字符串函数;
strcpy strcat strcmp是长度不受限制的字符串函数
7. strncpy函数的使用
char * strncpy ( char * destination, const char * source, size_t num );

从字符串中复制字符

的前 number 个字符复制到目标。如果在复制 num 个字符之前找到 C 字符串的末尾(由 null 字符表示),则目标将填充零,直到写入总数 num 个字符为止。

如果 source 长于 num,则不会在 destination 的末尾隐式附加 null 字符。因此,在这种情况下, destination 不应被视为以 null 结尾的 C 字符串(因此读取它会溢出)。

destinationsource 不应重叠(参见 memmove 了解重叠时更安全的替代方案)。

destination:指向要复制内容的目标数组的指针。

source:要复制的 C 字符串。

num:要从source复制的最大字符数。size_t 是无符号整型。

用例:

#include <stdio.h>
#include <string.h>
​
int main ()
{
    char str1[]= "To be or not to be";
    char str2[40];
    char str3[40];
​
    /* copy to sized buffer (overflow safe): */
    strncpy ( str2, str1, sizeof(str2) );
​
    /* partial copy (only 5 chars): */
    strncpy ( str3, str2, 5 );
    str3[5] = '\0';   /* null character manually added */
​
    puts (str1);
    puts (str2);
    puts (str3);
​
    return 0;
}

如果source里面的内容不够num,拷贝完源字符串之后,在目标的后边追加0,直到num个

8. strncat函数的使用
char * strncat ( char * destination, const char * source, size_t num );

从字符串附加字符

source 的前 num 个字符附加到 destination外加一个终止 null 字符

char arr[20] = "abcdef\0yyyyy";
char arr1[20] = "xxxxxxxx";
strncat(arr,arr1,3);//arr1 变成"abcdefxxx\0yy"(xxx后面带了\0,yy最后也有\0)

如果 source 中 C 字符串的长度小于 num,则仅复制终止 null 字符之前的内容。

destination:指向目标数组的指针,该数组应包含 C 字符串,并且足够大以包含串联的结果字符串,包括其他 null 字符。

source:C 字符串。

num:要附加的最大字符数。size_t 是无符号整型。

用例:

#include <stdio.h>
#include <string.h>
​
int main ()
{
    char str1[20];
    char str2[20];
    strcpy (str1,"To be ");
    strcpy (str2,"or not to be");
    strncat (str1, str2, 6);
    puts (str1);
    return 0;
}
9. strncmp函数的使用
int strncmp ( const char * str1, const char * str2, size_t num );

比较两个字符串的字符

比较 C 字符串 str1 的字符数与 C 字符串 str2 的字符数。 此函数开始比较每个字符串的第一个字符。如果它们彼此相等,则继续处理以下对,直到字符不同;到到达终止 null 字符;或者直到两个字符串中的 num 个字符匹配,以先发生者为准。

str1:要比较的 C 字符串。

str2:要比较的 C 字符串。

num:要比较的最大字符数。size_t 是无符号整型。

返回一个整数值,该值指示字符串之间的关系:

返回值表明
<0第一个不匹配的字符在 str1 中的值低于 str2 中的值
0两个字符串的内容相等
>0第一个不匹配的字符在 str1 中的值大于在 str2 中的值

用例:

#include <stdio.h>
#include <string.h>
​
int main ()
{
    char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
    int n;
    puts ("Looking for R2 astromech droids...");
    for (n=0 ; n<3 ; n++)
    if (strncmp (str[n],"R2xx",2) == 0)
    {
        printf ("found %s\n",str[n]);
    }
    return 0;
}

上述函数会有若干函数被vs2022认为不安全,指定了num,但目标空间可能不足,存在危险

10. strstr的使用和模拟实现
10.1 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.

(函数返回字符串str2在字符串str1中第⼀次出现的位置)。

The matching process does not include the terminating null-characters, but it stops there.

(字符 串的⽐较匹配不包含 \0 字符,以 \0 作为结束标志)。

功能:在str1中找str2这个字符串,第一次出现的位置;

如果找到了,就返回第一次出现的起始地址;

如果找不到,就返回NULL;

#include<stdio.h>
#include<string.h>
int main()
{
    char arr[] = "abcdefabcdef";
    char* p = "efab";
    char* p1 = "cdef";
    char* ret = strstr(arr,p);
    char* ret1 = strstr(arr,p1);
    printf("%s\n",ret);//打印efabcdef
    printf("%s\n",ret);//打印cdefabcdef
    return 0;
}
10.2 strstr的模拟实现
const char *my_strstr (const char * str1, const char * str2)
{
    char *cp = (char*) str1;
    char *s1, *s2;
    if (!*str2)
        return((char*)str1);
    while (*cp)
    {
        s1 = cp;
        s2 = (char *) str2;
        while ( *s1 && *s2 && !(*s1-*s2) )
            s1++, s2++;
        if (!*s2)
            return(cp);
        cp++;
    }
    return(NULL);
}//当前写的模拟实现不是最优算法
//KMP算法 —— 字符串中找字符串
11. strtok函数的使用(用起来很奇怪很抽象的一个函数)
char * strtok ( char * str, const char * sep );
  • sep参数指向⼀个字符串,定义了用作分隔符的字符集合

  • 第⼀个参数指定⼀个字符串,它包含了0个或者多个由sep字符串中⼀个或者多个分隔符分割的标 记。

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

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

  • strtok函数的第⼀个参数为 NULL ,函数将在同⼀个字符串中被保存的位置开始,查找下⼀个标记。

  • 如果字符串中不存在更多的标记,则返回 NULL 指针

返回值

如果找到令牌,则为指向令牌开头的指针。 否则,为 null 指针。 当在正在扫描的字符串中到达字符串的末尾(即 null 字符)时,始终返回 null 指针

用例:

#include <stdio.h>
#include <string.h>
int main ()
{
    char arr[] = "sadlkfjlas@sadf.net";
    char buf[256] = {0};
    srecpy(buf,arr);
    char* sep = "@.";
    char* ret = strtok(buf,sep);//sadlkfjlas\0sadf\0net
    printf("%s\n",ret);//打印sadlkfjlas
    ret = strtok(NULL,sep);
    printf("%s\n",ret);//打印sadf
    ret = strtok(NULL,sep);
    printf("%s\n",ret);//打印net
    return 0;
}

一个巧妙的写法:

#include <stdio.h>
#include <string.h>
int main ()
{
    char arr[] = "sadlkfjlas@sadf.net";
    char buf[256] = {0};
    srecpy(buf,arr);
    char* sep = "@.";
    char* ret = NULL;
    for(ret=strtok(buf,sep);ret != NULL;ret=strtok(NULL,sep))
    {
        printf("%s\n",ret);
    }
    return 0;
}

这个函数有记忆功能,每次调用完之后会保存一个地址(有static修饰的变量)

12. strerror函数的使用
char * strerror ( int errnum );

strerror 函数可以把参数部分错误码对应的错误信息的字符串地址返回来。 在不同的系统和C语言标准库的实现中都规定了⼀些错误码,⼀般是放在 errno.h 这个头文件中说明 的,C语言程序启动的时候就会使用⼀个全局的变量errno来记录程序的当前错误码,只不过程序启动 的时候errno是0,表⽰没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应 的错误码,存放在errno中,而⼀个错误码的数字是整数很难理解是什么意思,所以每⼀个错误码都是 有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。

errno —— c语言的全局变量

调用c语言的库函数

用例1:

#include <stdio.h>
#include <string.h>
#include <errno.h>
​
int main ()
{
    FILE * pFile;
    pFile = fopen ("unexist.ent","r");
    if (pFile == NULL)
        printf ("Error opening file unexist.ent: %s\n",strerror(errno));
    return 0;
}

用例2:

int main()
{
    int i = 0;
    for(i = 0;i <= 10;i++)
    {
        printf("%d:%s\n",i,strerror(i));
    }
    return 0;
}

用例3:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
    //打开文件
    FILE* pf = fopen("data.txt","r");//"r" - 读,以文件的形式,打开文件,如果文件不存在就打开失败
    if(pf == NULL)
    {
        printf("打开文件失败,原因是:%s",strerror(errno));
        return 1;
    }
    else
    {
        printf("打开文件成功\n");
        //...
        fclose(pf);
        pf = NULL;
    }
    return 0;
}

strerror —— 将错误码对应的错误信息的字符串的起始地址返回

perror —— 将errno中错误对应的错误信息直接打印出来

13. perror函数的使用
void perror ( const char * str );

打印错误消息

perror 函数先打印str函数指向的字符串,再打印冒号,再打印一个空格,再打印错误对应的错误信息

errno 的值解释为错误消息,并将其打印到 stderr(标准错误输出流,通常是控制台),可选择在其前面加上 str 中指定的自定义消息。

errno 是一个整型变量,其值描述调用库函数产生的错误条件或诊断信息(C 标准库的任何函数都可以为 errno 设置值,即使此引用中未明确指定,即使没有发生错误),请参阅 errno 了解更多信息。

perror 生成的错误消息取决于平台。

如果参数 str 不是 null 指针,则打印 str 后跟冒号 (:) 和空格。然后,无论 str 是否为空指针,都会打印生成的错误描述,后跟换行符 ('\n')。

perror 应在产生错误后立即调用,否则它可能会被对其他函数的调用覆盖。

用例:

#include <stdio.h>
int main ()
{
    FILE * pFile;
    pFile=fopen ("unexist.ent","rb");
    if (pFile==NULL)
        perror ("The following error occurred");
    else
    fclose (pFile);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值