4. strlib.h接口
- 隐含原型(implicit prototype)
是一个函数调用实例,包括参数的名字。
例如,RandomInteger
的隐含原型为RandomInteger(low, high)
。
4.1 确定字符串的长度
- 字符串的长度(length)
字符串包含的字符总数(包括所有的字母、数字、空格、标点符号和特殊字符)。
该功能可以通过调用strlib.h
接口的StringLength(s)
函数实现:
StringLength("Hello, world.\n")
从用户读入一行文本,计算其长度,代码实现如下:
#include <stdio.h>
#include "strlib.h"
main() {
string s;
s = malloc(1000); // 分配所需内存空间,并返回一个指向它的指针。
printf("Input a sentence: ");
scanf("%[^\n]", &s[0]); // replace "%s" with "%[^\n]" to support blank space
printf("Length of sentence is: %d\n", StringLength(s));
}
4.2 从一个字符串中选择字符
在C语言中,字符串中的位置是从0开始编号的。
strlib.h
接口的IthChar
函数支持返回指定下标位置的字符。
例如,IthChar(str, 5)
返回下标位置为5的字符,是字符串中的第6个字符。
定义函数LastChar
,返回str中的最后一个字符:
#include <stdio.h>
#include "strlib.h"
/* Get the last character in an inputted word. */
/* Function Prototype */
char LastChar(string s);
/* Main Program */
main() {
string s;
s = malloc(1000);
printf("Input a word: ");
scanf("%s", &s[0]);
printf("The last char is: %c\n", LastChar(s));
}
/* Function */
char LastChar(string s) {
return IthChar(s, StringLength(s) - 1);
}
4.3 连接
strlib.h
接口的Concat
函数支持两个字符串的连接(concatenation)操作。
Concat
函数每次只能取两个参数。为了连接三个或更多的字符串,必须多次调用Concat
。
定义函数ConcatNCopies(s, n)
,返回一个由n个str拷贝连接的字符串:
#include <stdio.h>
#include "strlib.h"
/* Return a new string composed of n copies of an inputted string. */
/* Function Prototype */
string ConcatNCopies(string s, int n);
/* Main Program */
main() {
string s;
int n;
s = malloc(1000);
printf("Input a string: ");
scanf("%s", &s[0]);
printf("Input a positive integer: ");
scanf("%d", &n);
printf("Concat %d copies %s is: %s\n", n, s, ConcatNCopies(s, n));
}
/* Function */
string ConcatNCopies(string s, int n) {
string result;
int i;
result = "";
for (i = 1; i <= n; i++)
{
result = Concat(result, s);
}
return result;
}
4.4 将字符转换为字符串
strlib.h
库包含函数charToString(ch)
。
定义函数ReverseString(str)
,返回一个按str相反次序排列的新字符串:
#include <stdio.h>
#include "strlib.h"
/* Return a reversed string of inputted string. */
/* Function Prototype */
string ReverseString(string s);
/* Main Program */
main() {
string s;
s = malloc(1000);
printf("Input a string need to reverse: ");
scanf("%s", &s[0]);
printf("Reversed result is: %s\n", ReverseString(s));
}
/* Function */
string ReverseString(string s) {
int uplimit, i;
string result;
result = "";
uplimit = StringLength(s) - 1;
for (i = uplimit; i>=0; i--) {
result = Concat(result, CharToString(IthChar(s, i)));
}
return result;
}
4.5 抽取字符串的一部分
strlib.h
库提供了一个函数SubString(s, p1, p2)
,支持从s中抽取从位置p1到p2之间的字符,包括p1和p2。
例如,函数调用SubString("Hello there!", 1, 3)
返回字符串"ell"
。
定义函数SecondHalf(s)
,返回一个由s中后半部分字符组成的子串,如果字符串长度是奇数,则包括中间的字符:
#include <stdio.h>
#include "strlib.h"
/* Return the second half of an inputted string. */
/* Function Prototype */
string SecondHalf(string s);
/* Main Program */
main() {
string s;
s = malloc(1000);
printf("Input a string: ");
scanf("%s", &s[0]);
printf("%s\n", SecondHalf(s));
}
/* Function */
string SecondHalf(string s) {
int length;
length = StringLength(s);
return (SubString(s, length / 2, length - 1));
}
4.6 比较两个字符串
strlib.h
接口提供的StringCompare
函数比较两个字符串的ASCII代码。
StringCompare
有两个字符串参数s1和s2,它返回一个整数,该整数的符号指出了两个字符串的关系:
按字母顺序,若s1出现在s2前面,则返回一个负整数;
按字母顺序,若s1出现在s2后面,则返回一个正整数;
若两个字符串完全相同,则返回0。
确定按字母顺序s1是否出现在s2的前面,判断语句如下:
if (StringCompare(s1, s2) < 0) ...
常见错误:
当比较字符串的值时,需要使用StringEqual
和StringCompare
,不要使用关系运算符。
C编译器检测不到这个错误,但程序会给出一个完全无法预计的结果。
4.7 在一个字符串内搜索
strlib.h
接口提供了两个函数Findchar
和Findstring
,支持搜索一个字符串,看它是否包含某一特定的字符或子串。
4.7.1 FindChar
FindChar
的原型是
int Findchar(char ch, string text, int start);
该函数搜索字符串text,从start指定的下标位置开始,寻找字符ch的第一次出现。
如果发现了该字符,返回这个字符的下标位置。
如果在text结束前没有发现这个字符,返回值-1。
例如:
#include <stdio.h>
#include "strlib.h"
/* Main Program */
main() {
printf("%d\n", FindChar('l', "Hello there", 0));
printf("%d\n", FindChar('l', "Hello there", 3));
printf("%d\n", FindChar('l', "Hello there", 4));
printf("%d\n", FindChar('h', "Hello there", 0));
}
2
3
-1
7
值得注意的是,和字符串比较一样,搜索字符串的函数对大小写是区别对待的。
用Findchar
实现一个产生首字母缩写(acronym) 的函数,它按次序取一系列单词的首字母形成一个新的单词。
例如,调用函数Acronym("self contained underwater breathing apparatus")
将返回"scuba"
。
#include <stdio.h>
#include <stdbool.h>
#include "strlib.h"
/* Return a new word composed of the first letter of each word. */
/* Function Prototype */
string Acronym(string sentence);
/* Main Program */
main() {
string sentence;
sentence = malloc(1000);
printf("Input a sentence: ");
scanf("%[^\n]", &sentence[0]);
printf("%s\n", Acronym(sentence));
}
/* Function */
string Acronym(string sentence) {
int idx;
string word;
idx = FindChar(' ', sentence, 0);
word = SubString(sentence, 0, 0);
while (true) {
word = Concat(word, SubString(sentence, idx + 1, idx + 1));
idx = FindChar(' ', sentence, idx + 1);
if (idx == -1) break;
}
return word;
}
4.7.2 FindString
函数FindString(str, text, start)
与Findchar
相似,区别在于第一个参数是字符串。
定义函数ReplaceFirst(str, pattern, replacement)
搜索字符串str
,将字符串pattern
的第一次出现用字符串replacement
来取代,将整个新字符串作为函数的返回值返回。如果pattern
没有出现,则返回原来的字符串。
具体代码实现如下:
#include <stdio.h>
#include <stdbool.h>
#include "strlib.h"
/* Replace the pattern first time appeared with a inputted word. */
/* Function Prototype */
string ReplaceFirst(string str, string pattern, string replacement);
/* Main Program */
main() {
string str, pattern, replacement;
char tmp[100];
str = malloc(1000);
pattern = malloc(100);
replacement = malloc(100);
printf("Enter the string to be edited: ");
scanf("%[^\n]", &str[0]);
printf("Enter the pattern string: ");
scanf("%s", &pattern[0]);
printf("Enter the replacement string: ");
scanf("%c", &tmp); // temporary statement to clear buffer
scanf("%[^\n]", &replacement[0]);
printf("%s\n", ReplaceFirst(str, pattern, replacement));
}
/* Function */
string ReplaceFirst(string str, string pattern, string replacement) {
string prefix, suffix, result;
int idx, length;
idx = FindString(pattern, str, 0);
if (idx != -1) {
length = StringLength(str);
prefix = SubString(str, 0, idx - 1);
suffix = SubString(str, idx + 1, length - 1);
result = Concat(Concat(prefix, replacement), suffix);
} else {
result = str;
}
return result;
}
4.8 大小写转换
strlib.h
库中包含两个函数,ConvertToUpperCase(s)
和ConvertToLowerCase(s)
,它们将任何字母字符转换为指定的大小写。
例如,调用函数ConvertToUpperCase("Hello, world.")
将返回字符串"HELLO, WORLD."
。
注意,字符串中的任何非字母的字符(如本例中的逗号、空格、句号)不受影响。
4.9 数值转换
4.9.1 IntegerToString / RealToString
strlib.h
接口导出两个函数,IntegerToString
和RealToString
,它们将一个数值转换为字符串表示。
例如,调用IntegerToString(-4)
将返回字符串"-4"。
RealToString(d)
函数将浮点数d
转换为字符串,该字符串的格式类似于由printf
用格式码%G
的显示结果,有时会产生一个以科学记数法表示的数字。
例如,调用RealToString(3.14)
返回“3.14”,而调用RealToString(0.00000000015)
将返回"1.5E-10"。
4.9.2 StringToInteger / StringToReal
strlib.h
接口还导出了函数StringToInteger
和StringToReal
,将表示数值的字符串转换为数值。
例如,调用StringToInteger("42")
返回整数42。
调用StringToReal("3.14159")
返回浮点数3.14159。
如果函数的参数不是合法的数字串,将会报告一个错误。
这两个函数主要用于输入操作。
4.10 效率和strlib.h库
本章中所有函数的实现都是以清晰,而不是以效率作为目标。
许多实现的效率都是相当低的,低得无法适应一些重大的应用。
然而,它们是简明的、可行的、容易理解的。当用这种形式的函数工作时,可以从概念上了解字符串工作的过程。
参考
《C语言的科学和艺术》 —— 第9章 字符串和字符