字符函数和字符串函数

字符函数和字符串函数

前言:

C语言中对字符和字符串的处理很频繁,但C语言本身是没有字符串类型的,字符串通常放在常量字符串和字符数组中。

常量字符串适用于那些不做修改的字符串函数

函数介绍:

1.1strlen

size_t  strlen ( const  char*  ptr );

专门用来计算字符串的长度的

size_t是sizeof的返回类型,本质上是unsigned int 类型,返回值类型为int和unsigned int各有各的的作用

例如计算strlen("abc")-strlen("abcedf")时,如果返回类型为unsigned int,那么当-3被当做unsigned int时会是一个非常大的数,会造成条件判断的不正确。在函数前加上强制转换符会让函数的返回值强制转换为对应类型

1.2strcpy

char* strcpy (char *  destination , const  char* source);

会将源字符串拷贝到目标空间,

源字符串必须包含\0。不包含会导致程序崩溃。

会将源字符串的\0拷贝到目标空间。

目标空间必须足够大以确保能存放源字符串。

目标空间必须可变,destination指向的不能是常量空间。

1.3strcat

char* strcat (char *  destination , const  char* source);

会将源字符串接到目标字符串的后面。

源字符串必须以\0结束。

目标空间必须足够大,能够容纳源字符串的内容。

目标空间必须可修改。

strcat模拟实现:

char* my_strcat (char *  dest , const  char* src)

{

    char* ret = dest;

    assert(dest && src);

    while(*dest)

    {

        dest++;//++如果放到while括号内会出问题,前置++无法解决空字符串类型,后置++会导致跳过\0。

    }

    while(*dest++=*src++)

    {

        ;

    }

    return ret;

}

可以查找相关参考代码(不是真正的库函数实现方式)

在查找时可能会遇到__cdecl,这是一个函数调用约定,即函数在调用时参数如何传,从左向右传还是从右向左传。

1.4strcmp

int  strcmp (const  char * str1 , const  char* str2)

字符串比较。比较的不是长度,而是对应位置上的字符大小。对应位置字符如果相等,则比较下一个位置字符的大小。全都相等则返回0。若*str1大于*str2则返回大于0的数,若*str1小于*str2则返回小于0的数。

strcmp模拟实现:

int  strcmp (const  char * str1 , const  char* str2)

{

    assert(str1 && str2);

    while(*str1 == *str2)

    {

        if(*str1 == '\0')

            return  0;

        str1++;

        str2++;

    }

    if(*str1 > *str2)

        return  1;

    else

        return  -1;//可以优化为return *str1-*str2;

}

如果"abc"=="abe"这样进行比较,比较的其实是字符串的首地址。

strcmp,strcat,strcpy是长度不受限制的字符串函数

下面介绍长度受限制的字符串函数:strncpy,strncat,strncmp

1.5strncpy

char*  strncpy (char *strdest , const char* strsource , size_t  count);

限定字符串拷贝,strdest为目标地址,strsource是待拷贝的字符串,size_t是拷贝的字符串长度,函数返回字符串首地址。在限定字符串拷贝中,不会自动将\0拷贝。如果待拷贝的的个数大于待拷贝的量,余下的字符串自动拷贝为\0。

//练习一下模拟实现

1.6strncat

char*  strncat (char *strdest , const char* strsource , size_t  count);

限定字符串接续,strdest是目标地址,会从目标字符串第一个\0位置开始接续,strsource是待接续字符串,count是接续数量,返回目标字符串首地址。接续完成后自动将下一位赋\0。若待接续字符串数不够接续数量,也停止接续。即字符串world\0接续到字符串hello\0xxxxxxxxx上时,(空间大小满足条件),若接续数为3,则地址字符串变为hellowor\0xxxxxx,若接续数为7,则地址字符串变为helloworld\0xxxx。当count大于字符串长度时会发生这样的情况。

//练习一下模拟实现

1.7strncmp

int  strncat (const  char *str1 , const  char* str2 , size_t  count);

限定字符串比较。比较前count数量的字符串大小,返回值规则同strcmp。比较字符串1abcdef\0和字符串2abceeeee\0时,若比较数字为3,则两字符串相等,返回0。若比较数字为4,则字符串1小于字符串2,返回一个负数值。

//练习模拟实现

1.8strstr

字符串查找函数

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

在string字符串中查找strC9harSet字符串,如果找到,返回第一次出现位置的起始地址。如在字符串abcdefabcdef\0中找bcd,返回的是字符串abcdefabcdef\0中第一个bcd的起始位置,即第一个b的地址。如果找不到,则返回一个空指针。若string为空字符串,则找不到。若strCharSet为空字符串,也找不到

//练习模拟实现(完成)//较难

1.9strtok

字符串分割函数

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

将字符串按分割符切分为几个字符串。

1.sep参数是个字符串,定义了用作分割符的字符集合。

2.第一个参数指定一个字符串,它包含零个或多个由sep中一个或多个分隔符分割的标记。(标记指由分隔符分割的一段)

3.strtok会查找str中的一个标记,并将其用\0结尾(分隔符会改为\0),返回指向这个标记的指针。(strtok会改变被操作的字符串,所以strtok操作的字符串一般都是临时拷贝并且可修改的)

4.strtok的第一个参数不为NULL,函数将找到str的第一个标记,strtok将保存它在字符串中的位置(保存的是分隔符的位置)。

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

6.如果字符串中不存在更多标记,则返回NULL。

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

strtok函数找非第一个标记时,函数的第一个参数是NULL

strtok的使用示例:

int  main()

{

    const  char* p = "@.";

    char  arr[] = "zpengwei@yeah.net";

    char  buf[50] = {0};

    strcpy(buf , arr);

    char* str = strtok(buf , p);

    printf("%s\n", str);//zpengwei

    str = strtok(NULL , p);

    printf("%s\n", str);//yeah

    str = strtok(NULL , p);

    printf("%s\n", str);//net

    return 0;

}

所以分隔符字符串集合的顺序不重要。分割字符串聚在一起会都变为\0,即空字符串,在打印时会自动忽略。

这种strtok的使用方式十分低级,当我们不知道具体字符串,但是要分割时这种写法就不合适了。

进阶方案如下:

int  main()

{

    const  char* p = "@.";

    char  arr[] = "zpengwei@yeah.net";

    char  buf[50] = {0};

    strcpy(buf , arr);

    char* str = NULL;

    for( str = strtok(buf , p) ; str != NULL ; str = strtok(NULL , p))

    {

        printf("%s\n", str);

    }

    return 0;

}

1.10strerror

错误码翻译函数。

char*  strerror (int errnum);

返回错误码,所对应错误信息。

在C语言中规定了一些错误信息,错误信息由两部分组成,错误码和对应的错误信息(对应的错误信息是一些常量字符串)。

例如错误码0对应的错误信息是No  erroor(即常量字符串"No error")

通常我们只知道错误码,不知道对应的错误,strerror的作用就是翻译错误码。

实际应用时是C语言文件操作时用到

C语言可以操作文件,例如fopen函数是打开文件。

FILE*  fopen (const char* filename , const char* mode),其中filename是文件名,mode是打开方式。

打开方式有如下几种:

"r"

Opens for reading. If the file does not exist or cannot be found, the fopen call fails.

"w"

Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"

Opens for writing at the end of the file (appending) without removing the EOF marker before writing new data to the file; creates the file first if it doesn’t exist.

"r+"

Opens for both reading and writing. (The file must exist.)

"w+"

Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"

Opens for reading and appending; the appending operation includes the removal of the EOF marker before new data is written to the file and the EOF marker is restored after writing is complete; creates the file first if it doesn’t exist.

由"r"的说明可知,如果没有相关文件会调用失败,这个有没有的判断条件是看工程所在路径,如在test_2_11路径下创建的工程,就看test_2_11路径下有没有相关文件。

fopen调用成功会返回指向打开文件的指针,调用失败会返回空指针。所以strerror使用示范如下:

int  main()

{

    FILE* fp = fopen("test.txt" , "r");//已知text.txt不存在

    if(NULL == fp)

    {

        printf("%s" , strerror(errno));//errno是C语言提供的一个放在errno.h文件中的全局变量,可以直接使用

        //库函数使用的时候,发生错误会把errno这个全局的错误码变量设置为本次执行库函数所产生的错误码。

        return 0;//打开失败的话就不能再执行读取和关闭文件的部分了

    }

    (文件读取和关闭的部分省略)

}

字符分类函数:引用头文件#include<ctype.h>

函数

如果它的参数满足下列条件就返回真

iscntrl

任何控制字符

isspace

空白字符:空格' ',换页'\f',换行'\n',回车'\r',水平制表符'\t',垂直制表符'\v'

isdigit

十进制数0~9

isxdigit

十六进制数字,包括所有十进制数,小写字母a~f,大写字母A~F

islower

小写字母a~z

isupper

大写字母A~Z

isalpha

字母a~z或A~Z

isalnum

字母或数字0~9,a~z,A~Z

ispunct

标点符号,任何不属于数字或字母的图形字符(可打印)

isgraph

任何图形字符

isprint

任何可打印字符,包括图形字符和空白字符

字符转换函数:

int  tolower (int  c)——大写字母转小写字母

int  toupper (int  c)——小写字母转大写字母

const修饰是不能通过指针修改对应空间,不是空间从此不能修改

内存相关函数——头文件#include<string.h>或#include<memory.h>

1.11memcpy

内存拷贝函数

void* memcpy (void* destination , const void* source , size_t num);

strcpy只能拷贝字符串,如果整型需要拷贝,则使用内存函数。num是待拷贝的字节个数。

在C语言中memcpy只要求满足拷贝不重叠的内存空间,部分编译器可以满足重叠内存空间的拷贝。

强制类型转换是暂时的,语句结束后原变量类型不变

//练习自主实现

1.12memmove

重叠内存拷贝函数

void* memmove (void* destination , const void* source , size_t num);

在拷贝内存数据时可以重叠。例如将数组arr[10] = {1,2,3,4,5,6,7,8,9,10}改为arr[10] = {1,2,1,2,3,4,5,8,9,10},如果使用memcpy拷贝则会变成arr[10] = {1,2,1,2,1,2,1,8,9,10}

//自主实现memmove

1.13memcmp

内存比较函数

int  memcpy (const  void* ptr1 , const  void*  ptr2 , size_t  num);

num是比较的字节数。ptr1大于ptr2返回一个正数,ptr1小于ptr2返回一个负数,相等返回0。

1.14memset

内存设置函数

void*  memset (void* dest , int c , size_t count);

dest指针指向的目的地,c是指定内存设置的内容,count是设置的个数,单位是字节。

使用示范:arr1[20] = {0};memset(arr1 , 'x' , 10);则arr1数组中前十个字节都是字符x的ascall码值120

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值