我一直在经历'Head First C'的过程,我发现练习创建一种反转字符串的方法。
这是我的解决方案:
void reverse_string(char s[]) {
for (int i = strlen(s) - 1; i > -1; i--) {
printf("%c", s[i]);
}
}
这是书中的解决方案:
void reverse_string(char *s) {
size_t len = strlen(s);
char *t = s + len - 1;
while (t >= s) {
printf("%c", *t);
t = t - 1;
}
puts("");
}
我从书中理解了解决方案,但是我的看起来更干净。后一种解决方案是否可取,如果可以,为什么?
答案 0 :(得分:4)
总结评论:
首先,函数名称reverse_string()
具有误导性,因为它不会反转字符串,而只会以相反的顺序打印它。
该函数应采用指向const char
的指针,而不是指向char
的指针。有些人可能会争辩说,在参数列表中使用[]
有点误导,因为它可能会使对C不太熟悉的人相信数组被传递而不是指向其第一个元素的指针。
两个函数都使用printf()
打印单个字符。这涉及解析格式字符串以仅一次输出单个字符的不必要工作。改用´putchar()or
fputc()`。
这两个功能之间的功能差异:您的版本在反向字符串后不显示换行符。本书的版本可以做到这一点,但是就像对单个字符使用printf()
一样,它以伪装的方式使用puts("")
而不是putchar('\n')
。
当将空字符串传递给函数时,本书的版本可能具有未定义的行为,因为在这种情况下,t
会指向s
所指向的数组的第一个元素之前的'不能保证工作。
您的版本使用int
eger存储strlen()
类型为size_t
的结果。 int
可能会在很长的字符串中溢出。
两种可能的解决方案:
#include <string.h> // strlen()
#include <stdio.h> // putchar()
void print_reverse(char const *str)
{
for (char const *p = str + strlen(str); p != str; putchar(*--p));
putchar('\n');
}
或使用索引:
#include <string.h> // strlen()
#include <stdio.h> // putchar()
void print_reverse(char const *str)
{
for (size_t i = strlen(str); i; putchar(str[--i]));
putchar('\n');
}
答案 1 :(得分:3)
本书中的解决方案具有未定义的行为,因为它使<ObjectIdentifier title="{users>Email}" text="last: {path: 'users>LastLoggedOnUtcDate', formatter: '.formatDateTime'}"/>
减至字符串开头之外。比较t
指向数组外部和t
具有不确定的行为。在具有分段指针的体系结构中,s
仅测试指针的偏移量部分会失败。出于相同的原因,它也会因为空字符串而失败。
带有指针的便携式解决方案如下所示:
>=
您的版本使用的索引不错,但是存在一个小问题:它不处理长度超过void reverse_string(const char *s) {
const char *t = s + strlen(s);
while (t > s) {
t--;
putchar(*t);
}
putchar('\n');
}
的字符串。字符串的长度为INT_MAX
类型,可能大于size_t
,甚至在int
和int
具有相同大小(size_t
为无符号的值可能大于size_t
。
更改类型INT_MAX
是不够的,因为您依靠i
变成负数。这是减少索引之前进行测试的一种优雅方法:
i
一些滑稽的程序员编写此比较void reverse_string(char s[]) {
for (size_t i = strlen(s); i-- > 0;) {
putchar(s[i]);
}
putchar('\n');
}
并将i --> 0
称为 downto 运算符...这是一个笑话,该表达式被解析为-->
{ {1}} i
--
,中间的空格无关紧要。
答案 2 :(得分:1)
首先,没有一种解决方案可以反转字符串。他们以相反的顺序打印它,但这与反向打印不同。
您的解决方案看起来更好,更简洁,而且不会降低可读性,这很好。
我不会说书中的解决方案是可取的。