为什么我不能用C中的sscanf()用简单的格式字符串将值读入简单变量?

时间:2017-12-03 02:16:35

标签: c scanf

我正在尝试解析一些简单格式化的文本,并使用数字和短字符串值创建文本/数字记录的简单数据结构。我调试并找到了问题;这是由于sscanf()没有使用特定的格式字符串将值读入我的变量(程序中的其他格式字符串工作得很好)。我创建了一个简单的文本文件来查看发生了什么。

代码如下:

char *idNumber = (char *)malloc(sizeof (char*));
  char *partNumber = (char *)malloc(sizeof (char*));
  int amountItems = 0;
  double unitPrice = 0;

  char *line1 = "Govan, Guthrie (N210) AX299 x 6 $149.94";
  char *line2 = "Mustaine, Dave (N106) AX350N x 2 $63.98";
  char *line3 = "Van Halen, Edward (N1402) AV2814 x 10 $34.90";


  sscanf(line1, "%*s, %*s (%s) %s x %d $%lf",  idNumber, partNumber,
     &amountItems, &unitPrice);

  printf("%s, %s, %d, %f\n", idNumber, partNumber, amountItems,     unitPrice);


  sscanf(line2, "%*s, %*s (%s) %s x %d $%lf", idNumber, partNumber,
     &amountItems, &unitPrice);
  printf("%s, %s, %d, %lf\n", idNumber, partNumber, amountItems,     unitPrice);

  sscanf(line3, "%*s, %*s (%s) %s x %d $%lf", idNumber, partNumber,
     &amountItems, &unitPrice);
  printf("%s, %s, %d, %lf\n", idNumber, partNumber, amountItems,     unitPrice);

我对以下字段感兴趣,其余字段被忽略。例如,在记录中:

“Govan,Guthrie(N210)AX299 x 6 $ 149.94”

我想在我的变量中依次使用N210,AX299,6和149.94。

结果如下:

andrew@levin-Inspiron-3650:~/Desktop/schoolwork/project2$ ./a.out

, , 0, 0.000000
, , 0, 0.000000
, , 0, 0.000000

预期输出为:

N210, AX299, 6, 149.94
N106, AX350N, 2, 63.98
N1402, AV2814, 10, 34.90

请分享帮助!

这不是直接来自我的程序的代码,而是我在旁边创建的“帮助”文件,只是为了调试这个问题,而不必调用整个应用程序!

以下类似的代码适用于不同的格式: 记录为:

N210 AX299 6 24.99

在以下代码中:

struct record *current = malloc(sizeof(struct record *));
current->idNumber = (char *)malloc(sizeof (char *) * 8);
current->partNumber = (char *)malloc(sizeof (char *) * 10);
sscanf(line, "%s %s %d %lf", current->idNumber, current->partNumber,
 &(current->amountItems), &(current->unitPrice));

我不希望这段代码成为C美女的丰富资源,我是一名Java开发人员,这是社区大学的C项目。但是你可以帮我调试这个sscanf问题。

谢谢!

2 个答案:

答案 0 :(得分:4)

这里的动态分配存在问题。行char *idNumber = (char *)malloc(sizeof (char*));为指向char的指针分配空间,而不为charchar的数组指定空间。这应该是这样的:

char *idNumber = malloc(sizeof (char) * 256);

或:

char *idNumber = malloc(sizeof *idNumber * 256);

请注意,不需要在C中转换malloc()的结果。第二个版本是在C中执行此操作的非常惯用的方法。通过避免在操作数中使用显式类型{{1这在编码中更容易且更不容易出错,并且在代码生命周期中类型发生变化时更容易维护。但是,由于sizeof在C中始终为1,因此也可能是:

sizeof (char)

分配时没有任何意义,256提供了足够的输入空间。并且请记住在尝试使用已分配的内存之前始终检查分配是否成功;完成后不要忘记释放char *idNumber = malloc(256); 内存。

但是,这并没有造成麻烦。问题是格式字符串告诉malloc匹配第一个字符串后面的逗号,但在输入中此逗号由sscanf()使用。没有进一步的匹配,所以%*s返回。 sscanf()在输入字符串的末尾消耗%s)还有一个问题,在格式字符串中没有任何关闭父级匹配。 )转换说明符会将字符串读取为空白字符,因此%s会消耗"Van Halen,"%*s %*s会尝试与"Edward"匹配。这些错误是可以检测到的;一个人总是检查调用(%s)族函数返回的值,以确保输入符合预期。

可以在此处使用scanset指令。该指令:scanf()告诉%*[^(](匹配任何字符,直到遇到scanf(),抑制分配,并在继续之前匹配(。然后,(指令告诉%255[^)])最多匹配255个字符,直到遇到scanf(),将结果存储在数组中,并在最后匹配)持续。请注意此处指定最大宽度以防止缓冲区溢出,并注意必须留出)终结符的空间,该终结符将始终由\0添加。

这是一个经过修改的程序,可以按预期工作:

scanf()

节目输出:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *idNumber = malloc(256);
    if (idNumber == NULL) {
        perror("Allocation failure");
        exit(EXIT_FAILURE);
    }
    char *partNumber = malloc(256);
    if (idNumber == NULL) {
        perror("Allocation failure");
        exit(EXIT_FAILURE);
    }

    int amountItems = 0;
    double unitPrice = 0;

    char *line1 = "Govan, Guthrie (N210) AX299 x 6 $149.94";
    char *line2 = "Mustaine, Dave (N106) AX350N x 2 $63.98";
    char *line3 = "Van Halen, Edward (N1402) AV2814 x 10 $34.90";

    if (sscanf(line1, "%*[^(]( %255[^)]) %255s x %d $%lf",
               idNumber, partNumber, &amountItems, &unitPrice) < 4) {
        fprintf(stderr, "Input error in line1\n");
    } else {
        printf("%s, %s, %d, %f\n",
               idNumber, partNumber, amountItems, unitPrice);
    }

    if (sscanf(line2, "%*[^(]( %255[^)]) %s x %d $%lf",
               idNumber, partNumber, &amountItems, &unitPrice) < 4) {
        fprintf(stderr, "Input error in line2\n");
    } else {
        printf("%s, %s, %d, %f\n",
               idNumber, partNumber, amountItems, unitPrice);
    }

    if (sscanf(line3, "%*[^(]( %255[^)]) %s x %d $%lf",
               idNumber, partNumber, &amountItems, &unitPrice) < 4) {
        fprintf(stderr, "Input error in line3\n");
    } else {
        printf("%s, %s, %d, %f\n",
               idNumber, partNumber, amountItems, unitPrice);
    }

    free(idNumber);
    free(partNumber);

    return 0;
}

答案 1 :(得分:0)

您的格式字符串与参数类型不匹配。而不是一个一个地试图指出每个错误,防止这种情况的方法是启用编译器警告。例如,如果您正在使用GCC或Clang,请将-Wall -Wextra -Werror添加到编译器命令中。然后,编译器将告诉您有关格式字符串不匹配的所有信息。