首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >K&R练习5-11。修改"detab“-接受作为参数的制表符列表

K&R练习5-11。修改"detab“-接受作为参数的制表符列表
EN

Code Review用户
提问于 2022-09-23 09:40:50
回答 2查看 161关注 0票数 3

到目前为止,我已经读到了K&R书,第2版的第5章,从中我学到了C。我花了几天时间思考这个项目的解决方案。我写了两个或三个版本的同一个程序,事实是,我无法为这个练习想出更好的解决方案:

练习5-11.修改程序"恩塔布“和"德塔普”(作为第1章的练习编写)。若要作为参数接受制表符列表,请执行以下操作。如果没有参数,则使用默认选项卡设置。

我以为这是我写过的最好的一本。以下是这项工作的解决办法(第5章,Ex-5.11):

我想知道如何改进它,使它“更进一步?”或者如果我采取了正确的方法:

代码语言:javascript
运行
复制
/*-
 *      detab.c - expand tabs to equivalent spaces
 *
 *      The-C-Programming-Language Book 2nd Edition.
 *
 *      Created by jr.chavez on 9/22/22.
 */
#include <stdio.h>
#include <stdlib.h>

#define DTAB_STOP       8       /* DEFAULT TAB STOP */
#define MAX_TAB_STOP    100

enum escapes { BACKSPACE = '\b', TAB = '\t', NEWLINE = '\n', RETURN = '\r' };

static int
getstops(char *cp)
{
        int n;
        
        n = 0;
        while (*cp) {
                if (*cp < '0' || *cp > '9')
                        return -1;
                if (*cp >= '0' && *cp <= '9')
                        n = n * 10 + *cp - '0';
                cp++;
        }
        return n;
}


int
main(int argc, char *argv[])
{
        int ch;
        int n, col;        /* n, columns */

        int nstops;
        int tabstops[MAX_TAB_STOP];

        nstops = argc - 1;
        if (nstops >  MAX_TAB_STOP) {
                fprintf(stderr, "error: too many args.\n");
                exit(EXIT_FAILURE);
        }
        for (int indx = 1; indx < argc; indx++) {
                tabstops[indx - 1] = getstops(argv[indx]) - 1;
        }

        col = 0;
        while ((ch = getchar()) != EOF) {
                switch (ch) {
                case TAB:
                        if (nstops == 0) {
                                while (col < DTAB_STOP) {
                                        printf("\u25A0");
                                        col++;
                                }
                                continue;
                        }
                        for (n = 0; n < nstops; n++)
                                if (col < tabstops[n])
                                        break;
                        if (n == nstops) {
                                printf("\u25A0");
                                col++;
                                continue;
                        }
                        while (col < tabstops[n]) {
                                printf("\u25A0");
                                col++;
                        }
                        break;
                case BACKSPACE:
                        if (col > 0)
                                --col;
                        putchar(BACKSPACE);
                        break;
                case RETURN:
                case NEWLINE:
                        putchar(ch);
                        col = 0;
                        continue;
                default:
                        putchar(ch);
                        break;
                }
        }
        if (ferror(stdin)) {
                perror("stdin");
                return EXIT_FAILURE;
        }
        return 0;
}

我做了一些“测试”:

代码语言:javascript
运行
复制
cat test.txt | ./bin/detab 4 9 29

输入文件:

代码语言:javascript
运行
复制
#           #       #
#               #       #
#           #   #           #   #
#   #           #

输出:

代码语言:javascript
运行
复制
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■#■■#                                                                                                 
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■■#■■#                                                                                                
#■■■■■■■■■■■■■■■■■■■■■■■■■■■■#■#■■■#■#      
#■■■#■■■■■■■■■■■■■■■■■■■■■■■■■■#

这些是我使用展开命令得到的结果:(当然,我从一开始就没有想过结果是准确的--但现在我只想改进它。)

代码语言:javascript
运行
复制
cat test.txt | expand -t 4,9,29

产出:

代码语言:javascript
运行
复制
#                            #  #
#                             #  #
#                            # #   # #
#   #                         #

注意:

  • 我现在只编写了detab程序。
  • 我专注于做一些“类似”"扩展“命令所做的事情。(我没有得到相同的输出,但有些类似的输出)。我也没有添加标志或从文件中读取。(我还没有达到第七章。)
EN

回答 2

Code Review用户

回答已采纳

发布于 2022-09-23 17:20:50

如何改进它,使其“更进一步”?

用户输入是邪恶的.

getstops(char *cp) (应该是getstops(const char *cp) )不会检测到无效的转换。最好使用strtol()并测试可接受的范围。输入错误时出错。

迂腐:黑客强化

getstops(argv[indx]) - 1;getstops()返回INT_MIN时调用未定义的行为。显然,这不是一个预期的返回值,更好的做法是在计算之前测试有效的用户值范围。

黑方

而不是printf("\u25A0");,考虑#define BLACK_SQUARE "\u25A0"fputs(BLACK_SQUARE, stdout);等。

更多信息消息

代码语言:javascript
运行
复制
// fprintf(stderr, "error: too many args.\n");
fprintf(stderr, "error: More than %d args.\n", MAX_TAB_STOP + 1);
// or 
fprintf(stderr, "error: More than %d tab stops.\n", MAX_TAB_STOP);

良好的检错

不错:if (ferror(stdin)) {

是慷慨的

我可以看到自动工具使许多点击停止。

代码语言:javascript
运行
复制
// #define MAX_TAB_STOP    100
#define MAX_TAB_STOP    4096

更好的代码将简单地允许argc制表符。大小为int tabstops[]argc

无用代码

if (*cp >= '0' && *cp <= '9')没有用。人们已经知道cp在范围内。

代码语言:javascript
运行
复制
#include <stdlib.h>

// Parse for positive int
static int getstops(const char *cp) {
  errno = 0;
  char *endptr;
  long val = strtol(cp, endptr, 0);
  if (cp == endptr || *endptr) {
    fprintf(stderr, "Non-numeric conversion <%s>\n", cp);
    exit(EXIT_FAILURE); // or alternative handling
  }
  if (errno || val < 0 || val > INT_MAX) {
    fprintf(stderr, "Invalid tab stop %ld>\n", val);
    exit(EXIT_FAILURE); // or alternative handling
  }
  return (int) val;
}
票数 4
EN

Code Review用户

发布于 2022-09-23 13:25:03

一般观测

代码大部分是可读的。

命令行可能包含标志,因此命令行处理应该检查它们。

可能有更多的错误条件是您没有检查的。

其中一些变量是优秀的,如tabstops,变量名(如ncolcp )可以改进。

复杂性

luser droog你的最后一个问题中的另一个答案中包含了这一点。

函数main()大约有60行代码,取决于您正在使用的编辑器或IDE,这可能是太多的代码行。在编辑器中不能容纳一个屏幕的函数通常被认为太大了。维护一个您无法同时看到的函数变得非常困难。

函数main()太复杂(做得太多)。随着程序规模的增加,main()的使用应限于调用解析命令行的函数、调用为处理设置的函数、调用执行程序所需功能的函数以及调用函数以清理程序的主要部分。

这里也有一个叫做单一责任原则的编程原则。单一责任原则指出:

每个模块、类或函数都应该对软件提供的功能的单个部分负责,而该责任应该完全由该模块、类或函数封装。

main()中至少有3种可能的功能。

  • 处理命令行
  • 获取输入
  • 在开关语句中,要处理的代码选项卡应该是一个函数。

使用exit(status)函数

main()函数中,没有理由调用exit()函数。只应在操作系统不执行的函数中调用退出函数

而不是

代码语言:javascript
运行
复制
                exit(EXIT_FAILURE);

代码应该是

代码语言:javascript
运行
复制
                return EXIT_FAILURE;
票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/279914

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档