我最近决定学习C,所以我开始学习K& R,但是我在第1章中遇到了问题21.你应该编写一个程序,它给出一个没有标签的字符串和一定的tabwidth,转换使用制表符和空格将所有空白区域转换为等效间距。
到目前为止,我已经有了这个:
void entab (char from[], char to[], int length, int tabwidth)
{
int i, j, tabpos, flag, count;
j = tabpos = flag = count = 0;
for (i = 0; from[i] != '\0' && j < length - count - 2; i++) {
if (from[i] == ' ') {
// If you see a space, set flag to true and increment the
// whitespace counter. Don't add any characters until you reach the
// next tabstop.
count++;
tabpos = (tabpos + 1) % tabwidth;
flag = 1;
if (count >= tabwidth - tabpos) {
to[j] = '\t';
j++;
count = count - tabwidth + tabpos;
tabpos = 0;
}
} else {
if (flag == 1) {
// if you see something other than a space and flag is true,
// there weren't enough spaces to reach a tabstop. Add count
// spaces to the string.
flag = 0;
tabpos = (tabpos + count + 1) % tabwidth;
while (count > 0) {
to[j] = ' ';
j++;
count--;
}
} else {
tabpos = (tabpos + 1) % tabwidth;
}
count = 0;
to[j] = from[i];
j++;
}
}
to[j] = '\0';
return;
}
不幸的是,它似乎产生了比预期更大的间距。关于我搞砸的地方的任何想法?
PS我已经在线查看了其他解决方案,我知道有更好的解决方法,但我真的想修复我的错误。
编辑:设置tabwidth = 4并使用:
foobar
foo bar foo bar
foo bar
作为输入,我得到:
/t/tfoobar
/t/t/t/tfoo bar/t/t/t foo bar
/t/tfoo/t/t bar
作为输出,而正确的输出将是:
/tfoobar
/t/tfoo/t bar/t/t foo bar
/tfoo/t/tbar
答案 0 :(得分:4)
这个代码在单个函数中并且具有很多嵌套(四个级别深)很难正确,甚至更难维护。
我建议你首先重构你有更多可管理的部分。例如:
这些只是一些想法。您最终会得到的是一些更短,更易于管理的功能,并且很可能会发现您的错误!
顺便说一下,我试着快速搜索一些C重构文章,但是空手而归。目前,重构都是关于OOP语言,如Java,C#和C ++。不过,一些经验法则对你来说还有很长的路要走:if
语句和for
&amp; while
循环祝你好运,欢迎来到SO!
答案 1 :(得分:2)
if (count >= tabwidth - tabpos)
这会很快开始输出标签。考虑输入字符串:
"aa "
以8作为tabwidth。当tabpos变为5时,你得到角色5(我将是4,计数将是3),因此触发条件。您不希望在i变量达到tabwidth之前输出制表符。
我也不会修复你的代码。但是,我可以指出一个明显的错误,而不是像“重构代码”这样的一般性陈述,这只是21世纪的“重写代码”的方式。您不需要tabpos变量。只需使用(i%tabwidth)。从这里开始,事情应该开始落实到位。
答案 2 :(得分:0)
对您的代码非常怀疑的一件事是增加tabpos的方式。你为每个空间增加它(mod tabwidth
)两次。在递增count
之后,再次递增flag == 1
。
在调试时,尤其是具有影响循环未来迭代的条件的代码时,最好考虑不变量。这些语句在执行特定代码行时应始终为true。
另一件事:给你的变量更好的名字。 flag
和count
特别糟糕,但tabpos
也有点令人困惑。我的第一个想法是“哪个标签的位置?”但看起来你真的希望它是自上一个制表符停止后的字符单元格数(或者等效地,你在制表符列中的当前位置)。
无论如何,他们应该有更清晰的名字。如果这个概念太难以命名,那么这可能是您需要重新考虑算法的标志,或者您至少应该对变量进行评论。通常也很好地找出变量的不变量,比如“tabpos是自上一个制表符停止后的字符单元格数”(您的代码违反了== bug)。
最后,您可以尝试在调试器中单步执行代码,或者甚至使用printf调试来查看它在某些输入上行为异常的原因。