第九章:字符串、字符和字节
GitHub
链接:ch09. 字符串、字符和字节
本章比较基础,介绍了字符串相关函数,但实现方式却只字未提。毕竟这是一个入门级的书,可以理解。面试过程中,不论是 strlen()
函数还是 memcpy()
函数等等都是面试手写的大热点,这点需要额外注意。
本章总结及注意点
部分课后习题解答
9.13 问题
-
我个人感觉,是缺点。把各种事物混到一起或许效率能够大大提高,但出错几率也随之上升。就现代编程语言看来,语法的孤立性是很重要的。即一件事情就对应一种解决方法就行了,搞太多方法容易混淆、出错。并且很显然,开发一个完整的字符串类型,并不影响传统的字符数组、字符串常量的使用。参考答案:
-
无符号更合适。从定义出发,长度怎么可能是负值呢?且无符号数表示正数范围比有符号大。但是无符号数的算术表达式可能会产生意外结果,而长度的优势在这体现的不明显。仁者见仁智者见智。
-
后续的链式操作就能很方便的完成,不需要再次查找字符串结尾标志。
-
memcpy(y, x, 50);
-
不能。当且仅当数组中的最后一个字符已经为
NUL
才为有效字符串。strncpy()
不会为最后添加NUL
。 -
可移植性更好。
-
toupper()
函数会进行合法性判断。islower()
是不必要的。 -
如果
buffer
中包含一个有效字符串,那么两个都能找到字符串末尾的NUL
,仅是返回值类型不同,前者为有符号类型,而后者为无符号类型。如果不包含一个有效字符串,那么memchr()
函数将返回一个NULL
指针,用其来减去buffer
是没有意义的。而strlen
则一直向后寻找,最终可能程序崩溃,结果也没有意义。
9.14 编程练习
-
主要使用字符分类函数配合计算器即可。直接复制的答案代码,见
demo01.c
。 -
实现了个寂寞?如果在长度内找到了
'\0'
,那么直接strlen()
即可,如果没找到'\0'
,那么就返回该长度就行了。那么直接调用memchr()
函数按字节查找'\0'
是否出现不就行了?不过按循环来做,确实比较简洁!见demo02.c
。 -
其实就是
strncpy()
的应用,函数需要传递数组大小,并在最后对字符数组最后一位赋值为NUL
。 -
也需要传递数组的长度,并计算
dst
的长度,并且在dst
中不要使用strlen()
函数来确定其长度,因为不知道里面是否包含有效字符。故可以使用demo02.c
中的my_strlen()
函数,在已知数组大小的时候能返回正确的字符串长度。最后使用strncat()
函数将字符串拼接过来,最终保证数组的最后一位元素是NUL
。在此按理说strncat()
函数应该是要保证其末尾为NUL
的。难道是在恰好拼接的情况下就不保证了吗? -
需要先计算
dest
的长度,得到dest_len
的实际可用长度,并且给NUL
留出一个空,最后直接调用strncat()
即可。 -
两种实现方式,
strlen()
方法和register
方法均可,其中后者不调用库函数,register
声明使得效率更高。见demo06.c
。 -
用一个指针记录上次找到的位置即可。见
demo07.c
。 -
strchr()
函数的应用,关键在于不能只写which --
,因为如果which < 0
的话,怎么减也没有用,所以一开始要进行--which
大于等于 0 的特判。让which
前置--
,当which
至少为 1 时,才有意义。见demo08.c
。 -
strpbrk()
函数的应用。其找到第一次在str
中出现的且在chars
字符集合中的位置,并返回该位置的字符指针。循环处理即可,令str
每次找到后往后移一位继续找就行了。见demo09.c
。 -
<ctype.h>
头文件的应用。使用isalpha()
及tolower()
函数。能很方便的处理大小写的情况。 -
strtok()
函数的应用。用其来找到以一个或多个空格结束的字符,strtok()
会将其末尾置为NUL
,循环来做,该函数会保存正在处理的字符串的局部信息,第一个参数传为NULL
继续处理即可。见demo11.c
。 -
将整个字符串去重,全部变大写 / 小写,然后由
'A'~'Z'
进行遍历,查找将没有在字符串中出现过的字母插到该字符串后面,注意每次插入后面的位置有'\0'
。见demo12.c
。 -
映射关系:
*data=key[*data - 'a'];
,注意检查大小写字母并保留。见demo13.c
。 -
遍历得到
*data
,运用strchr()
函数找到在key
中的出现位置,直接对 26 个字母进行下标映射即可。注意大小写字母的映射关系!利用<ctype.h>
中的字符分类函数进行判断、转换。见demo14.c
。 -
挺不错的一道模拟题。从前往后依次处理,首先是
'$'
符号,再求出字符串总长度,如果长度大于等于 3,则说明有整数部分,共有len-2
项个整数,处理三个整数,需要添加一个','
。整数处理完毕后在后面添加一个'.'
。小数部分处理简直绝了,如果len
小于 2,则说明没有整数部分,小数部分第一项添加 0,否则添加*src
的倒数第二项。如果len
小于 1,则说明没有整合素部分,小数部分第二项也为 0,否则添加*src
的最后一位。最后一定要记得将*dst = 0
,令其成为一个有效字符串。见demo15.c
。 -
今天处理的是在是太多了。本题考阅读理解,跳过了…
-
同上!
随笔
字符串的处理在编程中都是很常见且重要的,本章也比较基础,比较容易理解,还是得多写、多用,才能踩坑,才能掌握。
疑问
-
strtok()
函数,用来查找标记。这个函数我在学习过程中没遇见过,起初看书的时候感觉很难理解。找标记是很简单的事情,拿集合中的字符进行匹配即可,但是,它找到标记之后会将该标记位置置成NUL
?这还直接修改原字符串了…并且它的第一个参数还能是NULL
?结果最后讲的是它能保存它所处理的函数的局部状态信息,所以不能同时用它来解析两个字符串。那么是不是可以推断得到,其不能出现在同一个代码块中,不能嵌套使用,该strtok()
函数的作用域中,不能再给其另一个字符串了?我猜应该是这个样子的。 -
手撕
memcpy()
函数是非常重要的,秋招面试的时候,都不知道被考了多少回了…注意memmove()
函数处理内存重叠时的方式。 -
strncat()
函数不会检查dst
剩余空间是否足够,就直接从src
中向后拼接len
个再加上一个NUL
字符到dst
后面。故很有可能会造成数组越界,将后面的位置空间给侵占成拼接字符串了。