C 读取中间带逗号的整数

C 读取中间带逗号的整数,c,strtok,C,Strtok,由于输入的格式,我认为使用strtok是最好的。 但我在尝试检测错误时遇到了一些问题: 程序将读取的一行示例: .data 123,456,89 .data 12, 34, 53 , 64 这些都可以 我的问题是输入不正确,例如: .data 200 4000 // no comma speration .data 1, ,3 // ,3 should be an error .data 4, // the extra , should be an erro

由于输入的格式,我认为使用strtok是最好的。 但我在尝试检测错误时遇到了一些问题:

程序将读取的一行示例:

 .data 123,456,89 
 .data     12,   34,   53   ,   64
这些都可以

我的问题是输入不正确,例如:

 .data 200 4000 // no comma speration
 .data 1, ,3 // ,3 should be an error
 .data 4, // the extra , should be an error
 .data 12.2 // the .2 should be an error
 and so on
我的代码(SIZE表示缓冲区SIZE=30,valid_num通过令牌查看是否所有字符都是数字),其思想是首先检查令牌的有效性并将其添加到缓冲区,如果所有数字都有效,则将数字添加到我的数据库:

 while((sptr = strtok(NULL, ", \t\n")) != NULL){ //this is after reading using strtok before.
    if(i < SIZE && valid_num(sptr)){ //buffer is not full and the token contains only numbers
        temp_num = atoi(sptr);
        if(temp_num >= MIN_VAL && temp_num <= MAX_VAL){ //number is within the required size
            buffer[i] = temp_num; /*fill buffer*/
            i++;
        }
        else{
            fprintf(stderr, "(%d) Error: %d is out of bounds. Valid numbers are between %d and %d\n", line_count, temp_num, MIN_VAL, MAX_VAL);
        }
    }
    else{
        fprintf(stderr, "(%d) Error: %s is not a valid number\n",line_count, sptr);
    }
    tok_count++;
}

if(i == tok_count){ //if all tokens were read correctly, add the data to database.
    DC += add_data(buffer, tok_count, DC, data_Table);
}
else{
    if(sptr != NULL){
    fprintf(stderr, "(%d) Error: %s is not a digit, .data can only be used for integers\n", line_count, sptr);
    }

}
while((sptr=strtok(NULL,,\t\n))!=NULL){//这是在读取之前使用strtok之后。
如果(i=MIN_VAL&&temp_num,则有许多方法可以解析该行

OP的
temp_num=atoi(sptr);
没有检测到溢出,因为1)未定义
atoi()的溢出,2)没有错误返回值


我相信下面的代码将处理所有恶意输入。它不使用
strtok()
,而是使用
strtol()
查找非数字输入

使用辅助函数可以清晰地显示每个步骤

#include <ctype.h>
#include <errno.h>
#include <stdlib.h>

void consume_whitespace(char **input) {
  while (isspace((unsigned char ) **input))
    (*input)++;
}

int parse_int(char **input, int *dest) {
  char *endptr;
  errno = 0;
  long y = strtol(*input, &endptr, 10);
  if (*input == endptr) return -1; // no conversion
  if (errno) return -1;  // overflow
  #if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
    if (y < INT_MIN || y > INT_MAX) return -1;  // overflow
  #endif
  *input = endptr;
  *dest = (int) y;
  return 0;
}

int parse_data_line(char *input, const char *prefix, int *dest, int n) {
  size_t prefix_length = strlen(prefix);
  if (memcmp(input, prefix, prefix_length)) return -1;
  input += prefix_length;

  int i;
  for (i = 0; i < n; i++) {
    consume_whitespace(&input);
    if (*input == '\0') break;
    if (i > 0 && *input++ != ',') return -1;
    if (parse_int(&input, &dest[i])) return -1;
  }
  consume_whitespace(&input);
  if (*input) return -1;  // extra text
  return i;
}
#包括
#包括
#包括
空白字符(字符**输入){
while(isspace((无符号字符)**input))
(*输入)++;
}
int parse_int(字符**输入,int*dest){
char*endptr;
errno=0;
长y=strtol(*输入和结束,10);
if(*input==endptr)返回-1;//无转换
if(errno)返回-1;//溢出
#如果LONG_MININT_MAX
如果(yINT_MAX)返回-1;//溢出
#恩迪夫
*输入=endptr;
*dest=(int)y;
返回0;
}
int parse_data_行(字符*输入,常量字符*前缀,int*dest,int n){
大小\前缀\长度=strlen(前缀);
if(memcmp(输入,前缀,前缀长度))返回-1;
输入+=前缀长度;
int i;
对于(i=0;i0&&*input++!=',')返回-1;
if(parse_int(&input,&dest[i])返回-1;
}
使用_空格(&input);
if(*input)返回-1;//额外文本
返回i;
}
示例用法

#define SIZE 30
int main() {
  int numbers[SIZE];
  char *input = foo();
  int count = parse_data_line(input, ".data", numbers, SIZE);
  if (count < 0) puts("Fail");
  else bar(numbers, count);
}
#定义尺寸30
int main(){
整数[大小];
char*input=foo();
int count=解析数据行(输入“.data”、数字、大小);
如果(计数<0)放入(“失败”);
else条(数字、计数);
}

>……你想分析无效的输入吗?为什么?你想要完成什么?对数字列表的鲁棒解析是困难的,特别是如果你不知道列表中包含了多少。通常你在STROTD(上)写一段很难的代码,并在主循环中搜索分离逗号。考虑使用<代码> STRT()
而不是
atoi()
将子字符串解析为数字。前者的一个关键优点是,它允许您确定输入的转换量(如果有)。@JohnBollinger的注释+1,并且只需添加一点,
strtol
几乎可以替代
strtok
,因为它允许您迭代string并拉出数字。您需要添加的唯一逻辑是吃空格的东西,然后如果找到逗号,则下一次调用
strtol
会发现一些东西。任何不是逗号或空格的东西都将是错误的。
scanf
甚至所有strxxx函数都只能构建一个穷人的解析器。它将处理语法正确的数据很好,但是如果您希望能够发出相关的错误消息,那么您应该考虑手工构建解析器(一次循环处理一个字符),如果问题足够简单,或者使用好的旧lex+yacc(或flex+bison)构建健壮的解析器。