我看了C(还在学习)已经有一段时间了,我刚刚回到K& R书中。
我刚刚去了练习5-3 (p107)。
编写我们在第2章中展示的函数strcat的指针版本:strcat(s,t)将字符串t复制到s的末尾。
我想出了this ......
void strcat(char *s, char *t);
void strcat(char *s, char *t) {
while (*s++ != '\0');
s--;
while (*t != '\0') {
*s++ = *t++;
}
*--t = '\0';
}
int main() {
char str[] = "Hey, hello";
char str2[] = " are you?";
strcat(str, str2);
printf("%s\n", str);
return 0;
}
似乎有效。
我想知道的是,K& R书经常用尽可能少的线条写练习 - 我希望他们为上面提供了自己的代码示例,你会得到类似this的内容...
void strcat(char *s, char *t) {
while (*s++ != '\0');
s--;
while ((*s++ = *t++) != '\0');
*--t = '\0';
}
对我来说,这个可读性较差(也许这个例子不太好,但我经常看看他们的代码并想一想如果将它分成几行,我会更好地理解)。本书中提供的示例似乎主张在循环的条件部分中进行这种赋值,事实上每行尽可能多地编写代码。
即使可读性受到影响,本书是否正确尽可能地尽可能地做到了?
这只是 The C Way 吗?
答案 0 :(得分:13)
通过K& R中作为例子给出的strcpy()
的迭代 - 他们解释了他们的简洁与清晰的哲学,并谈论习语。
答案 1 :(得分:5)
您不应该期望您的程序能够正常工作,因为您正在调用未定义的行为。
定义两个特定大小的缓冲区(str
长度为11个字节,str2
长度为10个字节)。然后,在strcat
期间,您尝试写入不存在的str[11]
。从这一点开始,无法保证程序的执行。它可能会崩溃,它可能会达到您的预期,或者它可能只是打印“42”并让您想知道原因。
此外,您不应更改*t
中的strcat
,因为在较新版本的C t
中,类型为const char *
。
第三,当重新实现也由您的环境提供的功能时,请给它另一个名称。否则,您的编译器可能会用一些与函数调用等效的内置代码替换它。例如,GCC有__builtin_strlen
,有时会替换对strlen
的调用。
代码的固定版本如下所示:
#include <stdio.h>
/* renamed strcat to str_cat to avoid confusing the compiler */
void str_cat(char *s, const char *t) { /* added the const qualifier to t */
while (*s++ != '\0');
s--;
while (*t != '\0') {
*s++ = *t++;
}
/* removed the needless modification of *t */
*s = '\0'; /* edit: added this line after the comment from Jonathan Leffler */
}
int main() {
char str[80] = "Hey, hello"; /* note the large array size here */
char str2[] = " are you?";
str_cat(str, str2);
printf("%s\n", str);
return 0;
}
答案 2 :(得分:0)
请特别注意Android和BSD的源代码,作为strcat
更现代C实现的好例子。
除了strcat
之外,您还应该编写strlcat
和many examples的实现,而不是{{1}}。