我正在尝试解析一些简单格式化的文本,并使用数字和短字符串值创建文本/数字记录的简单数据结构。我调试并找到了问题;这是由于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问题。
谢谢!
答案 0 :(得分:4)
这里的动态分配存在问题。行char *idNumber = (char *)malloc(sizeof (char*));
为指向char
的指针分配空间,而不为char
或char
的数组指定空间。这应该是这样的:
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
添加到编译器命令中。然后,编译器将告诉您有关格式字符串不匹配的所有信息。