【问题标题】:converting from string to int using strtol() : \0' or '\n'?使用 strtol() 从字符串转换为整数:\0' 还是 '\n'?
【发布时间】:2014-07-02 09:47:44
【问题描述】:

我对从字符串到整数的转换有疑问。 我通过函数 fgets 得到一个字符串,然后我使用 strtol 函数将其转换为 int。 这是代码:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h>
#include <limits.h>

int main(void)
{
  char buf[BUFSIZ];
  char *p = NULL;
  long int val;
  int numero;
  int temp;

  do
  {
temp=0;
printf ("Enter a number: ");
if (fgets(buf, sizeof(buf), stdin) != NULL)
{
    val = strtol(buf, &p, 10);
    if(buf==p)
    {
        printf(" no digits \n");
        temp=1;
    }
    if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val   == 0)) 
    {
        perror("strtol");
        temp=1;
    }
    if (*p != '\0')
    {
        printf("you have insert any char character \n");
        temp=1;
    }
 }
else
 {
    printf("Error\n");
    temp=1;
 }   
}
while(temp == 1);

 /* If we got here, strtol() successfully parsed a number */
 numero=(int)val;
 printf("***** The number is : %d ******* \n",numero);

return 0;
}

这个代码不起作用,但是如果我替换这个控件,它就可以工作

if (*p != '\0')
    {
        printf("you have insert any char character \n");
        temp=1;
    }

有了这个:

if (*p != '\n')
    {
        printf("you have insert any char character \n");
        temp=1;
    }

你知道为什么吗? :)

编辑: 这是我最终功能版本的代码 :) 感谢所有 :) 现在看来一切正常:

int readIN(int *numero)  
{
   long int val;
   char buf[BUFSIZ];
   char *p = NULL;

   if (fgets(buf, sizeof(buf), stdin) != NULL)
   {
      val = strtol(buf, &p, 10);
      if(buf==p)
      {
        return 1;
      }
    if ( (val > INT_MAX || val < 0) || (errno != 0 && val == 0)) 
    {
           return 1;
            }
    if (*p != '\n' && *p != '\r' && *p != '\0')
    {
         return 1;
    }
  }
  else
  {
    return 1;
  }  

  *numero=(int)val;
  return 0;  
}

【问题讨论】:

  • fgets\n 留在缓冲区中。 strtolp 留在它成功处理的最后一个数字之后的下一个字符处,如果您输入了一些数字并按 Enter,则为 \n
  • 并且因为我使用 fgets 来获取字符串,如果一切正常,因此 strtol 留在 p \n 中!在 man strtol 我读到:“如果 endptr 不是 NULL,strtol() 将第一个无效字符的地址存储在 *endptr。如果根本没有数字,strtol() 将 nptr 的原始值存储在 *endptr (并返回 0)。特别是,如果 *nptr 不是 '\0' 但 **endptr 在返回时是 '\0',则整个字符串都是有效的。”而且我认为 strtol 留在 p '\0' 而不是它成功处理的最后一个数字之后的下一个字符! :D
  • 第一个无效字符是\nstrtol 不改变任何字符,它使p 指向您输入中的某个位置
  • 1) 在strtol() 呼叫之前需要errno = 0。小问题:2)if (errno == ERANGE)就足够了,不需要测试返回值。 3) 不确定为什么您的最终代码使用 val &lt; 0 而不是 val &lt; INT_MIN, just want non-negative numbers? 4) (errno != 0 && val == 0)` 可能是错误的。建议(errno)

标签: c strtol


【解决方案1】:

您的代码运行良好。它已正确识别出数字后有尾随字符。正如马特所说,gets 返回一整行,包括尾随换行符(旁白:为什么人们坚持将实际答案作为评论发布?)。

鉴于您的字符串几乎总是有这个换行符,您的简单修复可能是正确的做法。

但有两个例外:

  1. 文件结束
  2. 在行尾使用回车的操作系统。

更彻底的解决方案是:

if (*p != '\n' && *p != '\r' && *p != '\0')
    {
        printf("error: unexpected trailing characters in input\n");
        temp=1;
    }

【讨论】:

  • 谢谢 :) 根据您的建议,我正确地解决了问题 :D 而且我知道当函数离开 '\n' 或离开 '\0' 时,我必须学习得更好!
  • 当文件在text模式下运行时,操作系统的行结束符,无论是'\n''\r''\r\n'等都被翻译成@ 987654326@。如果代码正在读取具有每个操作系统的备用 EOL 的文本文件,则可能会出现问题。
  • 是的。不过最好确定一下。
猜你喜欢
  • 2016-10-23
  • 1970-01-01
  • 2019-05-29
  • 1970-01-01
  • 2013-01-10
  • 2016-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多