C语言 K&R练习1-21 -心理不理解

relj7zay  于 2024-01-06  发布在  其他
关注(0)|答案(9)|浏览(312)

不可能的K&R练习。
“写一个程序entab,用最少的制表符和空格来替换空格字符串,以达到相同的间距。使用相同的制表位,比如每n列。n应该是一个变量还是一个符号参数?”
我遇到的问题是,我不确定如何正确地做到这一点。我知道这不是很好的解释,但这几乎是这里的问题。我见过的大多数例子都计算了一些空白,并将这些系列替换为制表符,但这不是它所要求的,我想我理解它的要求,但目前感觉无法做到这一点。
有人可以帮忙吗:)
编辑:到目前为止我写的代码是can be found here

6jjcrrmo

6jjcrrmo1#

如果你的问题是“这是要求我做什么?”我想我可以通过解释原始问题(以不同的方式提出相同的问题)来提供帮助。
写一个程序,输入带有空格的文本,输出尽可能使用制表符的视觉等效文本。
例如,制表符每隔8个字符,空格显示为“.”,制表符显示为“-”;

  1. input;
  2. ".foo:...bar;......#comment"
  3. output;
  4. ".foo:-bar;-..#comment"
  5. input;
  6. ".......-foo:.....bar;......#comment"
  7. output;
  8. "-foo:-.bar;-...#comment"

字符串
编写程序,使tabstop参数n可以变化,即允许n的值不为8。准备好证明你的决定,使n为常数,或者变量。

  • 编辑 * 我看了你的代码,我认为它比它需要的更复杂。我的建议是一次一个字符。没有必要缓冲一整行。在读取每个字符时保持列计数。('\n'将其重置为零,'\t'将其增加1或更多,其他字符将其递增)。当您看到空格(或制表符)时,不要立即发出任何内容,开始你的entabbing过程,发出零个或多个制表符,然后空格(在'\n'或非空格字符,以先到者为准)。

最后一个提示是,状态机可以使这种算法更容易编写、验证、测试和读取。

  • 编辑2* 为了让OP接受我的答案,我现在已经开始自己编写解决方案,基于我上面提供的提示和我在讨论中的评论。
  1. // K&R Exercise 1-21, entab program, for Stackoverflow.com
  2. #include <stdio.h>
  3. #define N 4 // Tabstop value. Todo, make this a variable, allow
  4. // user to modify it using command line
  5. int main()
  6. {
  7. int col=0, base_col=0, entab=0;
  8. // Loop replacing spaces with tabs to the maximum extent
  9. int c=getchar();
  10. while( c != EOF )
  11. {
  12. // Normal state
  13. if( !entab )
  14. {
  15. // If whitespace goto entab state
  16. if( c==' ' || c=='\t' )
  17. {
  18. entab = 1;
  19. base_col = col;
  20. }
  21. // Else emit character
  22. else
  23. putchar(c);
  24. }
  25. // Entab state
  26. else
  27. {
  28. // Trim trailing whitespace
  29. if( c == '\n' )
  30. {
  31. entab = 0;
  32. putchar( '\n' );
  33. }
  34. // If not whitespace, exit entab state
  35. else if( c!=' ' && c!='\t' )
  36. {
  37. entab = 0;
  38. // Emit tabs to get close to current column position
  39. // eg base_col=1, N=4, col=10
  40. // base_col + 3 = 4 (1st time thru loop)
  41. // base_col + 4 = 8 (2nd time thru loop)
  42. while( (base_col + (N-base_col%N)) <= col )
  43. {
  44. base_col += (N-base_col%N);
  45. putchar( '\t' );
  46. }
  47. // Emit spaces to close onto current column position
  48. // eg base_col=1, N=4, col=10
  49. // base_col -> 8, and two tabs emitted above
  50. // base_col + 1 = 9 (1st time thru this loop)
  51. // base_col + 1 = 10 (2nd time thru this loop)
  52. while( (base_col + 1) <= col )
  53. {
  54. base_col++;
  55. putchar( ' ' );
  56. }
  57. // Emit buffered character after tabs and spaces
  58. putchar( c );
  59. }
  60. }
  61. // Update current column position for either state
  62. if( c == '\t' )
  63. col += (N - col%N); // eg col=1, N=4, col+=3
  64. else if( c == '\n' )
  65. col=0;
  66. else
  67. col++;
  68. // End loop
  69. c = getchar();
  70. }
  71. return 0;
  72. }

展开查看全部
b5buobof

b5buobof2#

我有点晚了,但这是我自己解决这个问题的方法。这是一个不同于上面分享的方法,所以如果你有任何意见/反馈,请分享。
查看my public gist on Github的源代码,这里有代码注解,文件顶部解释了方法,但我将复制并粘贴到这里,以便从一开始就清楚逻辑。
方法:

  • 我们将跟踪遇到的空格数(在非制表符/非空格字符之间)
  • 我们将跟踪每个输入行的字符(不是制表符/空格/换行符
  • 我们将通过以下方式来评估空格产生的“间隙”:
  • 计算这些字符之间的空格数。
  • 当空格数>= TABSIZE时,间隙将“足够大”
  • 然后,对于我们的“缓冲区”中所有剩余的空格,我们将单独打印出来

最后,我们打印出读入的字符(不是制表符/空格)
以及更新空间计数和字符计数(如有必要)。
我仍然是一个新手程序员在所有意义上,所以我不知道如何将比较与其他解决方案张贴在这里,但逻辑似乎更容易遵循(至少对我来说)。
希望这对以后的人有所帮助!

展开查看全部
sg3maiej

sg3maiej3#

我同意你的评估。用制表符替换每n个空格是不够的;例如,如果n == 4,“hi blank blank blank”不应该被替换为“hi tab”,而是“hi tab blank blank”。
听起来你需要做的是在阅读每一行时跟踪当前位置,并使用这些信息来确定你需要多少个标签。这有帮助吗?如果你需要更多细节,请告诉我!
至于“变量与符号参数”部分,两者都是可行的,但我能想到使用变量的一个显著优点:你可以在不重新编译的情况下为不同的n值运行程序。

bjp0bcyl

bjp0bcyl4#

让我提供另一个至少处理提供顶级答案的情况。它只处理一个字符串。
假设列表是至少包含2个空格的事物。
1.让我们跟踪尾随空格的数量。
1.如果最后一个符号和当前符号都是空格,则可能有一个表格。
1.当尾随空格的数量等于制表停止时:将主计数器设置为counter -tablation stop - 1(就像我们使用数组一样),然后将位置分配给\t
1.将计数器变量移位后,其他符号将照常写入

  1. /*
  2. Write a program that takes as input text with spaces
  3. and produces as output visually equivalent text using tabs to the maximum extent possible.
  4. f.e. tab=4
  5. input:
  6. ".foo:...bar;......#comment"
  7. output:
  8. ".foo:-bar;-..#comment"
  9. input:
  10. ".......-foo:.....bar;......#comment"
  11. output:
  12. "-foo:-.bar;-...#comment"
  13. */
  14. #include <stdio.h>
  15. #define MAXLINE 24
  16. #define TABSTOP 4
  17. int entab(char s[]);
  18. int main() {
  19. char s[MAXLINE];
  20. entab(s);
  21. printf("%s\n", s);
  22. return 0;
  23. }
  24. int entab(char s[]) {
  25. int i;
  26. int j;
  27. char c;
  28. for (i = 0, j = 1; i < MAXLINE - 1 && ((c = getchar()) != '\n'); ++i) {
  29. // entab state
  30. if (i > 0 && s[i - 1] == ' ' && c == ' ') {
  31. ++j;
  32. if (j == TABSTOP) {
  33. i -= TABSTOP - 1;
  34. j = 1;
  35. s[i] = '\t';
  36. } else
  37. s[i] = c;
  38. }
  39. // Normal state
  40. else
  41. s[i] = c;
  42. }
  43. if (c == '\n') {
  44. s[i] = c;
  45. ++i;
  46. }
  47. s[i] = '\0';
  48. return 0;
  49. }

字符串

展开查看全部
olhwl3o2

olhwl3o25#

我的理解是,你不必真的知道问题是什么或者如何解决它来回答这个问题。这个问题似乎是在问你是否理解何时使用变量而不是“符号参数”。我实际上不确定“符号参数”是什么意思;它似乎是过时的术语。
话虽如此,解决问题的第一部分(用制表符代替空格)是相当直接的。

tuwxkamq

tuwxkamq6#

我粗略地看了一下你的代码,没有什么明显的错误。
因此,我的建议是,要么在调试器中单步调试几个输入示例,一边调试一边检查变量值,要么添加一大堆调试打印语句。无论哪种情况,您的目标都是找到程序状态开始偏离预期或意图的点。

m3eecexj

m3eecexj7#

我正在浏览KnR,看到了这个页面:
Answers to Exercises
您的练习位于以下位置:

  • 解决方案
  • 第1章第一次见面
  • Ex No 21 Pg No 34

users.powernet.co.uk/eton/kandr2/krx121.html
希望你觉得这有用。
真诚的,Morpfh
1http://users.powernet.co.uk/eton/kandr2/index.html“C编程语言”,第2版,Kernighan和里奇-练习答案

kpbpu008

kpbpu0088#

在上面的最佳答案中,程序过于复杂。为了简化这部分答案,我附上了一段简单得多的代码,希望是以K&R的风格编写的(主要是通过++内联递增)。

包含

define TAB 4

int main()函数{

  1. char newsentence[255],c;
  2. int spacecount = 0, oldsentencepointer = 0, newsentencepointer = 0;
  3. printf("Give me a sentence please:\n");
  4. while ((c = getchar()) != '\n') {
  5. if ((oldsentencepointer != 0) && (oldsentencepointer % TAB == 0) && (spacecount > 0))
  6. {
  7. newsentencepointer -= spacecount; //if at tabstop, and spaces and not
  8. first, go back to 1st space, set tab.
  9. newsentence[newsentencepointer++] = '\t';
  10. spacecount = 0;
  11. }
  12. if (c == ' ') {
  13. newsentence[newsentencepointer++] = ' ';
  14. spacecount++; //keep track of spaces before tab stop
  15. }
  16. else if (c == '\t') {
  17. newsentence[newsentencepointer++] = '\t' ;
  18. oldsentencepointer = TAB; //set old pointer to TAB (does not matter if actual,
  19. only cadence important)
  20. continue; //continue from here so as not to increment
  21. old sentence counter.
  22. }
  23. else {
  24. newsentence[newsentencepointer++] = c ; //write whatever was old into new.
  25. spacecount = 0; //reset space counter.
  26. }
  27. oldsentencepointer++;
  28. }
  29. newsentence[newsentencepointer] = '\0'; //cap it off.
  30. puts(newsentence);
  31. return 0;

字符串
}

展开查看全部
vptzau2j

vptzau2j9#

还有一个更简洁的解决方案,尽管它没有采用可用的最佳代码实践(滥用短路评估,通过continue进行笨拙的控制流,有点奇怪的“空间”循环)。

  1. #include <stdio.h>
  2. #define TS 8
  3. int main(int arg, char *argv[]) {
  4. int counter = 0, space_counter = 0, c;
  5. while ((c = getchar()) != EOF) {
  6. ++counter;
  7. if (c == ' ' && ++space_counter && (counter % TS) == 0) {
  8. space_counter = 0;
  9. c = '\t';
  10. } else if (c == '\t') {
  11. counter = space_counter = 0;
  12. } else if (c != ' ') {
  13. while (space_counter--)
  14. putchar(' ');
  15. space_counter = 0;
  16. if (c == '\n')
  17. counter = 0;
  18. } else {
  19. continue; /* don't call putchar(c) */
  20. }
  21. putchar(c);
  22. }
  23. return 0;
  24. }

字符串
除了空格之外,读取的每一个字符都被逐字打印。空格被计数。如果程序遇到一个非空格字符,它将打印之前计数过的空格,然后重置计数器。如果遇到一个空格,它将通过第二个计数器进行检查如果光标在制表位上,则打印(从行首/最后一个制表位开始的打印字符)。如果是,则打印制表符,否则仅计算空白。
输入中的一个制表符被处理为重置空格计数器并输出该制表符,从而消除该过程中的任何多余空格。

展开查看全部

相关问题