十六进制计算器,使用scanf解析字符串

时间:2014-12-19 17:33:12

标签: c hex calculator scanf 8051

这是我的代码:

char a[18], b[18];
char oper, clear;
char *test;
init_8051();

    test="0x1234567890123456 + 0x1234567890123456\0";
    printf("Please enter an equation: %s \n",test );

    sscanf(test,"0x%s %c 0x%s",a,&oper,b);

    printf(" a= %s \n" ,a);
    printf(" oper= %s \n" ,oper);
    printf(" b= %s \n" ,b);

我想接受带有操作字符串的十六进制数字,并且能够将这两个数字分成2个单独的字符数组,但它不想工作,这里是以下代码的输出:

   Please enter an equation: 0x1234567890123456 + 0x1234567890123456  
 a= 1234567890123456 
 oper= Ò 
 b= 1234567890123456

正如你所看到的那样,操作无法识别,而且我必须使用我希望我不必使用的空格我希望它的格式为0x1234567890123456 + 0x1234567890123456 在加号和数字之间没有空格。

由于

2 个答案:

答案 0 :(得分:1)

来自sscanf手册

   s      Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the
          terminating null byte ('\0'), which is added automatically.  The input string stops at white space or at the maximum field width, whichever occurs first.

这意味着%s会消耗+和其他字符,boper未经注册,abd溢出a,因为它只有18个字符的空格。

因此,当输入字符串缺少第一个操作数之后的空格时,sscanf将继续读取,直到找到空格字符。因此,当字符串不包含操作数和运算符之间的分隔空间时,sscanf会消耗所有输入。

我会在这里附加一个与您的问题解决方案不同的方法

  1. 我们复制字符串,这是strtok所要求的,你不能传递一个不可变的字符串,有很多方法可以复制这个字符串,你只需要为你的情况选择合适的字符串

    input = strdup("0x1234567890123456 + 0x1234567890123456\0");
    
  2. 现在,我们使用strpbrk来查找运算符

    pointer = strpbrk(input, "+-*/" /* here go the operators */);
    if (pointer != NULL)
        oper = *pointer; /* this will contain the operator ascii value */
    
  3. 创建一个包含运算符作为分隔符的字符串

    operstr[0] = oper;
    operstr[1] = '\0'; /* strings must be null terminated */
    
  4. 现在,我们使用strtok来标记字符串,并找到操作数

    pointer = strtok(input, operstr);
    if (pointer != NULL)
        fprintf(stderr, "first operand: %s\n", pointer); /* you can copy this string if you need to */
    printf("Operator: %s \n", operstr);
    
  5. 第二次调用strtok需要NULL第一个参数

    pointer = strtok(NULL, operstr);
    if (pointer != NULL)
        fprintf(stderr, "second operand: %s\n", pointer); /* you can copy this string if you need to */
    
  6. 最后free输入字符串的副本。

    free(input);
    
  7. 最好使用strtok_r可重入版本。但是现在你可以测试我的建议,可能是你需要的。

    即使这适用于这种特殊情况,它也不是做这种事情的首选方式,你可以尝试编写解析器并使用Reverse Polish Notation,或者你可以尝试使用词法分析器和解析器生成器如flexbison

答案 1 :(得分:0)

我之前的回答被低估了,并没有解决所有OP的要求,所以我重写了这个答案。

OP需要灵活的输入,空格或空格。我建议不要使用sscanf(),而是使用以下方法。首先,程序使用strcspn()找到一个有效的运算符,然后在运算符和空格上使用strtok()中断字符串。但是在字符串文字上使用strtok()是UB,所以我首先将“等式”复制到另一个字符串。

我还更正了运算符的printf()字段规范,并使ab不同 - 在示例中对不同变量使用相同的值总是一个坏主意。< / p>

#include <stdio.h>
#include <string.h>

#define  OPERATORS "+-*/"
#define  DELIMS    " \t\n" OPERATORS

int parse (char *test)
// return 1 if parsed successfully
{
    char a[50], b[50];
    char oper;
    char *ptr;
    int opind;
    opind = strcspn (test, OPERATORS);  // find operator
    if (opind < 1) return 0;            // fail
    oper = test[opind];                 // collect operator
    ptr = strtok (test, DELIMS);        // find a
    if (ptr == NULL) return 0;          // fail
    strcpy (a, ptr);                    // collect 1st arg
    ptr = strtok (NULL, DELIMS);        // find b
    if (ptr == NULL) return 0;          // fail
    strcpy (b, ptr);                    // collect 2nd arg
    printf(" a    %s \n" ,a);
    printf(" oper %c \n" ,oper);        // corrected format
    printf(" b    %s \n" ,b);
    return 1;
}

int main (void)
{
    char test[100];
    strcpy (test, "0x123456789ABCDEF0+0xFEDCBA9876543210");
    if (!parse (test))
        printf("Failed\n");
    printf("\n");

    strcpy (test, "0x123456789ABCDEF0 + 0xFEDCBA9876543210");
    if (!parse (test))
        printf("Failed\n");
    return 0;
}

节目输出

a    0x123456789ABCDEF0
oper +
b    0xFEDCBA9876543210

a    0x123456789ABCDEF0
oper +
b    0xFEDCBA9876543210