链接到原始问题:在C中成功地使用strtol()
在收到来自代码评审社区的优秀反馈后,我尝试将我的字符串重做为长转换程序!我相信我对它做了很大的改进(大部分的想法来自我上一篇文章的答案),但我确实给它添加了我自己的“风格”,我想看看我是否遗漏了什么或者需要改变我实现解决方案的方式。
#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;
}发布于 2016-10-07 11:17:17
#include您没有提供"stdafx.h“的内容,但是我可以通过删除该包含来编译,所以您可能不需要它。
您似乎确实缺少了<string.h>的一个必要的包含。
malloc()在main()中,可以在堆上分配一个固定长度的缓冲区。与堆栈分配相比,没有任何优势(除非您正在为一个具有很小堆栈的系统进行编译),也不需要乘以1:根据定义,sizeof (char)必须是1:
char str[MAXLENGTH];另外,我注意到支持3400位长的平台并不多,所以您可能会使输入缓冲区变得更小一些。
完成此操作后,您对readline()的调用可以是
readline(&str, sizeof str)readline()您接受指向指针的指针,但不要更改指向值,这样您就可以在星星之间引入一个const,或者(最好)删除一个间接的级别:
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返回的值,而不是重新计算它:
void str_cmp(char* str) {
char *nl = strchr(str, '\n');
if (nl)
*nl = '\0';
}我也更喜欢写'\0',而不是0,以显示我们在这里处理字符串字符。
因为它只在一个地方使用,所以我们可以内联这个函数。这是一个判断力的决定,但我认为分开没有足够的好处。
main():此代码不执行它声称的操作:
char* err = str_to_long(str, &cnvt_numb);
/* ... */
fprintf(stderr, "That number '%s' was not convertible...\n", err);err返回的值不是字符串,而是可解析数字之后的部分。因此,对于10x这样的输入,您只需打印x;这并不是您想要的。我会向用户展示整个字符串:
fprintf(stderr, "That number '%s' was not convertible...\n", str);在这种情况下,您可能也不想返回EXIT_SUCCESS。
您测试的是LONG_MAX的输出,而不是LONG_MIN。实际上,这两者都是合法的输出,因此,通过不测试errno,您将不必要地缩小所接受的范围。
有一个对getch()的调用,但没有在任何头中声明。也许你是说getchar()?无论哪种方式,要求额外的输入只是为了退出程序是用户的敌意,我只想切除这部分。
我的结局是:
#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位),并正确地报告-9223372036854775809和9223372036854775808的范围错误。
12345aoeu被拒绝
那个号码‘12345 That’是不可兑换的.
https://codereview.stackexchange.com/questions/143496
复制相似问题