C-字符串、字符和字节(下)

06

高级字符串查找

    接下来的一组函数简化了从一个字符串中查找和抽取一个子串的过程。

1.查找一个字符串前缀

    strspn和strcspn函数用于在字符串的起始位置对字符计数。它们的原型如下:

size_t strspn(char const *str, char const *group);size_t strcspn(char const *str, char const *group);

    group字符串指定一个或多个字符。strspn返回str第一个不在字符串 group中出现的字符下标。例如,如果group包含了空格、制表符等空白字符。

下面例子,

int len1, len2;char buffer[] = "25.142.330,Smith,J,239-4123";​len1 = strspn(buffer, "0123456789");len2 = strspn(buffr, ".0123456789");

    变量len1将被置为2,变量len2将被置为11。下面的代码将计算第一个指向字符串中第一个非空白字符的指针。

ptr = buffer + strspn(buffer, "\n\r\f\t");

    strcspn函数和strspn函数正好相反,它将返回第一个在group中的字符的下标。strcspn这个词中的字母c来源于对一组字符求补这个概念。

2.查找标记

    一个字符串常常包含了几个有意义的部分,它们被分隔符分隔开来。每次为了处理这些部分,你首先必须把它们从字符串中抽取出来。

    这个任务正是strtok函数所实现的功能。它从字符串中隔离各个单独的称为标记(token)的部分,并丢弃分隔符。它的原型如下:

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

    sep参数是个字符串,定义了用作分隔符的字符集合。第1参数指定一个字符串,它包含零个或多个由sep字符串中一个或多个分隔符分隔的标记。strtok找到str的下一个标记,并将其用NUL结尾,然后返回一个指向这个标记的指针。若没有可检索的字符串,则返回一个空指针。

    下面是一个简短的例子,

char str[80] = "This is - cxsjcrmdjt - official account";const char sep[2] = "-";char *token;/* 获取第一个子字符串 */token = strtok(str, sep);/* 继续获取其他子字符串 */while(token != NULL){    printf("%s\n", token);    token = strtok(NULL, s);}

    编译并运行上面程序,这将产生以下结果:

This is

cxsjcrmdjt

official account

    如果你愿意,你可以在每次调用strtok函数时使用不同的分隔符集合。当一个字符串的不同部分由不同的字符集合分隔的时候,这个技巧很管用。

警告:

    由于strtok函数保存它处理的函数的局部状态信息,所以你不能用它同时解析两个字符串,因此,如果while循环体内调用了一个在内部调用strtok函数的函数,上述代码将会失败。

07

错误信息

    当你调用一些函数,请求操作系统执行一些功能如打开文件时,如果出现错误,操作系统是通过设置一个外部的整型变量errno进行错误代码报告的。strerror函数把其中一个错误代码作为参数并返回一个指向用于描述错误的字符串的指针。这个函数的原型如下:

char *strerror(int error_number);

08

字符操作

    标准库包含了两组函数,用于操作单独的字符,它们的原型位于头文件ctype.h。第一组函数用于对字符分类,而第二组用于转换字符。

1.字符分类

    每个分类函数接受一个包含字符值的整型参数。函数测试这个字符并返回一个整型值,表示真或假。下表列出了这些分类函数以及它们每个所执行的测试。

2.字符串转换

    转换函数可将大小写字母相互转换。

int tolower(int ch);int toupper(int ch);

    如其函数名一样,toupper函数返回对应的大写形式,tolower函数返回对应的小写形式。如果函数的参数并不是一个可以大小写转换的字符,函数将不修改参数直接返回。

提示:

    或许你会认为这些函数的实现简单,可以很轻易地被自己的实现替代,但是直接操控字符将会降低程序的可移植性,考虑以下例子,它试图测试ch是否是一个大写字符。

if (ch >= 'A' && ch <= 'Z')

    这条语句在使用ASCII字符集的机器上能够运行,但在使用EBCDIC字符集的机器上将会失败。若使用下面这条语句:

if (isupper(ch))

    无论机器使用哪种字符集,它都能顺利执行。

09

内存操作

    根据定义,字符串由一个NUL字节结尾,所以字符串内部不能包含任何NUL字符。但是,非字符串数据内部包含零值的情况并不罕见,你无法使用字符串函数来处理这种类型的数据,因为当它们遇到第一个NUL字节时将停止工作。

    不过,我们可以使用另外一组相关的函数,它们的作用于字符串函数类似,但这些函数能够处理任意的字节序列。下面是它们的原型。

void *memcpy(void *dst, void const *src, size_t length);void *memmove(void *dst, void const *src, size_t length);void *memcmp(void const *a, void const *b, size_t length);void *memchr(void const *a, int ch, size_t length);void *memset(void *a, int ch, size_t length);

    每个原型都包含一个显式的参数说明需要处理的字节数。但和strn开头的函数不同,它们在遇到NUL字节时并不会停止操作。

    memcpy从src的起始位置复制length个字节到dst的内存起始位置。你可以用这种方法复制任何类型的值,第三个参数指定复制值的长度(以字节计)。如果src和dst以任何形式出现了重叠,它的结果是未定义的。

例如,

char temp[SIZE], values[SIZE];...memcpy(temp, values, SIZE);

    它从数组values复制SIZE个字节到数组temp。

    但是,如果两个数组都是整型数组该怎么办?下面的语句可以完成这项任务:

memcpy(temp, values, sizeof(values));

    前两个参数并不需要使用强制类型转换,因为在函数的原型中,参数的类型是void*型指针,而任何类型的指针都可以转换为void*型指针。

    如果数组只有部分内容需要被复制,那么需要复制的数量必须在第三个参数中指明。对于长度大于一个字节的数据,要确保把数量和数据类型的长度相乘,如:

memcpy(dst, array, count * sizoef(array[0]));

    你也可以使用这种技巧复制结构体或者结构体数组。

    memmove函数的行为和memcpy差不多,只是它的源和目的操作数可以重叠。虽然它不需要以下面这种方式实现,不过memmove的过程和这种方法的过程相同:把源操作数复制到一个临时位置,这个临时位置不会与源或目标操作数重叠,然后再把它从这个临时位置复制到目标操作数。memmove通常无法使用某些机器所提供的特殊的字节-字符串处理指令来实现,所以它可能比memcpy慢一些。但是,如果源和目标参数真的可能存在重叠,就应该使用memmove。

    memcmp对两端内存的内容进行比较,这两端内存分别起始于a和b,共比较length个字节。这些值按照无符号字符逐字节进行比较,函数的返回类型和strcmp函数一样----负值表示a小于b,正值表示a大于b,零表示a等于b。由于这些值是根据一串无符号字节进行比较的,所以如果memcmp函数用于比较不是单字节的数据如整数或浮点数时可能会出现不可预料的结果。

    memchr从a的起始位置开始查找字符ch第一次出现的位置,并返回一个指向该位置的指针,它共查找length个字节。如果在这length个字节中未找到该字符,函数就返回一个NULL指针。

    memset函数把从a开始的length个字节都设置为值ch。如:

memset(buffer, 0, SIZE);

    把buffer的前SIZE个字节都初始化为0。

10

总结

    字符串就是零个或多个字符的序列。该序列以一个NUL字节结尾,字符串的长度就是它所包含的字符的数目。标准库提供了处理字符串的函数,它们的原型位于头文件string.h中。

    strlen函数用于计算一个字符串的长度,它的返回值是一个无符号整数,所以把它用于表达式时应该小心。strcpy函数把一个字符串从一个位置复制到另一个位置,而strcat函数把一个字符串的一份拷贝添加到另一个字符串的后面。这两个函数都假定它们的参数是有效的字符串,而且如果源字符串和目标字符串出现重叠,函数的结果是未定义的。strcmp对两个字符串进行词典序的比较。它的返回值提示第1个字符串是大于、小1还是等于第2个字符串。

    长度受限的函数strncpy, strncat和 strncmp都类似它们对应的不受限制版本,区别在于这些函数还接受一个长度参数。在strncpy中,长度指定了多少个字符将被写入到目标字符数组中。如果源字符串比指定长度更长,结果字符串将不会以NUL字节结尾。strncat函数的长度参数指定从源字符串复制过来的字符的最大数目,但它的结果始终以一个NUL字节结尾, strcmp函数的K度参数用于限定字符比较的数目。如果两个字符串在指定的数日里不存在区别,它们便被认为是相等的。

    用于查找字符串的函数有好几个. strchr函数查找一个字符申中某个字符第1次出现的位置。strrchr函数查找一个字符串中某个字符最后-次出现的位置。strpbrk在一个字符串4查找一个指定字符集中任意字符第1次出现的位置。strstr函数在一个字符串中查找另一个字符申第1次出现的位置。

    标准库还提供了了一些更高级的字符串查找函数。strspn函数计算一个字符串中第一个不在指定字符集出现的字符下标。strtok函数把一个字符串分隔成几个部分,每次调用它都返回一个指向下一个标记位置的指针。

    sterror把一个错误码作为它的参数。它返回一个指向字符串的指针,该字符串用于描述这个错误。

    标准库还提供了检验和转换字符的函数。具体查表。

    memxxx函数提供了内存操作的功能。​

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容