首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用strtol()跟踪

使用strtol()跟踪
EN

Code Review用户
提问于 2016-10-07 06:51:13
回答 1查看 177关注 0票数 1

链接到原始问题:在C中成功地使用strtol()

在收到来自代码评审社区的优秀反馈后,我尝试将我的字符串重做为长转换程序!我相信我对它做了很大的改进(大部分的想法来自我上一篇文章的答案),但我确实给它添加了我自己的“风格”,我想看看我是否遗漏了什么或者需要改变我实现解决方案的方式。

代码语言:javascript
运行
复制
#include "stdafx.h"
#include <stdio.h>
#include <stdbool.h>
#include <limits.h>
#include <stdlib.h>

#define MAXLENGTH 1024

bool readline(char** buf, const size_t buf_len);
char* str_to_long(const char* const buf, long* out);
void str_cmp(char* str);

int main() {
    char* str = malloc(sizeof(char) * MAXLENGTH);
    long cnvt_numb = 0;
    printf("Enter a number: ");
    while (!readline(&str, MAXLENGTH)) {
        printf("Try again...\n");
    }
    char* err = str_to_long(str, &cnvt_numb);
    if (err == NULL) {
        if (cnvt_numb == LONG_MAX) {
            fprintf(stderr, "INPUT OUT OF RANGE...\n");
        }
        else {
            printf("Your number was: %ld\n", cnvt_numb);
        }
    }
    else {
        fprintf(stderr, "That number '%s' was not convertable...\n", err);
    }

    free(str);

    printf("Press any key to continue...\n");
    getch();
    return EXIT_SUCCESS;
}

bool readline(char** buf, const size_t buf_len) {
    if ((fgets(*buf, buf_len, stdin)) != NULL) {
        str_cmp(*buf);
        return true;
    }
    return false;
}

void str_cmp(char* str) {
    if ((strchr(str, '\n')) != NULL) {
        str[strcspn(str, "\n")] = 0;
    }
}

//if returns anything other than NULL, conversion failed
char* str_to_long(const char* const str, long* out) {
    char* end = NULL;
    long number = strtol(str, &end, 10);
    if ((!*end) && (end != str)) {
        *out = number;
        end = NULL;
    }
    return end;
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2016-10-07 11:17:17

#include

您没有提供"stdafx.h“的内容,但是我可以通过删除该包含来编译,所以您可能不需要它。

您似乎确实缺少了<string.h>的一个必要的包含。

malloc()

main()中,可以在堆上分配一个固定长度的缓冲区。与堆栈分配相比,没有任何优势(除非您正在为一个具有很小堆栈的系统进行编译),也不需要乘以1:根据定义,sizeof (char)必须是1:

代码语言:javascript
运行
复制
char str[MAXLENGTH];

另外,我注意到支持3400位长的平台并不多,所以您可能会使输入缓冲区变得更小一些。

完成此操作后,您对readline()的调用可以是

代码语言:javascript
运行
复制
readline(&str, sizeof str)

readline()

您接受指向指针的指针,但不要更改指向值,这样您就可以在星星之间引入一个const,或者(最好)删除一个间接的级别:

代码语言:javascript
运行
复制
bool readline(char *buf, const size_t buf_len) {
    if (fgets(buf, buf_len, stdin)) {
        str_cmp(buf);
        return true;
    }
    return false;
}

另外,对于部分行的读取,您是否想返回true还不清楚;也许值得评论一下来澄清这一点。

str_cmp()

您应该记住strchr返回的值,而不是重新计算它:

代码语言:javascript
运行
复制
void str_cmp(char* str) {
    char *nl = strchr(str, '\n');
    if (nl)
        *nl = '\0';
}

我也更喜欢写'\0',而不是0,以显示我们在这里处理字符串字符。

因为它只在一个地方使用,所以我们可以内联这个函数。这是一个判断力的决定,但我认为分开没有足够的好处。

回到main():

此代码不执行它声称的操作:

代码语言:javascript
运行
复制
char* err = str_to_long(str, &cnvt_numb);
/* ... */
fprintf(stderr, "That number '%s' was not convertible...\n", err);

err返回的值不是字符串,而是可解析数字之后的部分。因此,对于10x这样的输入,您只需打印x;这并不是您想要的。我会向用户展示整个字符串:

代码语言:javascript
运行
复制
fprintf(stderr, "That number '%s' was not convertible...\n", str);

在这种情况下,您可能也不想返回EXIT_SUCCESS

您测试的是LONG_MAX的输出,而不是LONG_MIN。实际上,这两者都是合法的输出,因此,通过不测试errno,您将不必要地缩小所接受的范围。

有一个对getch()的调用,但没有在任何头中声明。也许你是说getchar()?无论哪种方式,要求额外的输入只是为了退出程序是用户的敌意,我只想切除这部分。

把所有的东西放在一起,

我的结局是:

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

#define MAXLENGTH 40            /* supports 128-bit long */


bool readline(char* buf, const size_t buf_len) {
    if (!fgets(buf, buf_len, stdin))
        return false;
    char *nl = strchr(buf, '\n');
    if (nl)
        *nl = '\0';
    return true;
}

// returns NULL on success, or the unparseable portion of input on failure
char* str_to_long(const char* const str, long* out) {
    char* end;
    errno = 0;
    *out = strtol(str, &end, 10);
    if (!*end && end != str)
        end = NULL;
    return end;
}


int main() {
    char str[MAXLENGTH];
    long cnvt_numb = 0;

    printf("Enter a number: ");
    while (!readline(str, sizeof str)) {
        printf("Try again...\n");
    }

    char* err = str_to_long(str, &cnvt_numb);
    if (err) {
        fprintf(stderr, "That number '%s' was not convertible...\n", str);
        return EXIT_FAILURE;
    } else if (errno == ERANGE) {
        fprintf(stderr, "INPUT OUT OF RANGE...\n");
        return EXIT_FAILURE;
    } else {
        printf("Your number was: %ld\n", cnvt_numb);
        return EXIT_SUCCESS;
    }
}

它接受来自-9223372036854775808的输入到9223372036854775807 (在这个系统中,long是64位),并正确地报告-92233720368547758099223372036854775808的范围错误。

12345aoeu被拒绝

那个号码‘12345 That’是不可兑换的.

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

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

复制
相关文章

相似问题

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