我有一个看起来像这样的文件:
Kathryn 1561 2589.98
Hollie 2147 2496.36
Sherlock 3574 2514.65
和我的fscanf相关的代码如下:
int load_data(char* fileName, char** accountNames, int* accountNumbers, float* amounts, int numOfAccounts)
{
FILE *fPtr = fopen(fileName, "r");
int counter = 1, test;
if(fPtr == NULL)
{
fclose(fPtr);
return 0;
}
else
{
test = fscanf(fPtr,"%20s%d%f", *accountNames, accountNumbers, amounts);
printf("%d\n", test);
while(counter < numOfAccounts)
{
test = fscanf(fPtr,"%20s%d%f", *accountNames, accountNumbers, amounts);
printf("%d\n", test);
counter++;
}
fclose(fPtr);
return 1;
}
}
这是调用代码:
int main(int argc, char** argv)
{
int numOfAccounts = atoi(*(argv + 2));
char* fileName = *(argv + 1);
char** accountNames = malloc(sizeof(char) * 20 * numOfAccounts);
int* accountNums = malloc(sizeof(int) * numOfAccounts);
float* amounts = malloc(sizeof(float) * numOfAccounts);
int dataload = load_data(fileName, accountNames, accountNums, amounts, numOfAccounts);
dataload++;
return 0;
}
if语句有效,文件被识别。然而,fscanf只返回0.我真的很擅长C和fscanf所以我要求你耐心等我正在学习,但如果有人能帮助我那会很棒。如果我需要提供更多信息,请与我们联系。谢谢。
答案 0 :(得分:1)
您的char **accountNames
应该是类型为numOfAccounts
的长度为char *
的一维数组; accountNames
的内存分配是分两个步骤完成的,而不是一个步骤:
int anlen, ai;
accountNames = (char **) malloc (numOfAccounts * sizeof (char *));
anlen = 20;
for (ia=0; ia<numOfAccounts; ia++)
{
numOfAccounts[ia] = (char *) malloc (anlen * sizeof (char));
}
您的counter
可以从0
到numOfAccounts
,而不是从1
到numOfAccounts
,因此您只有一个fscanf
语句,包含在您的while (count<numOfAccounts)
循环中。
您的fscanf
语句中的字符串应为" %19s %d %f"
。注意这里的空格,意思是“忽略任何前导空格”。如果正确使用,这就是使fscanf如此强大而有用的功能之一。另外,您在*accountNames
语句中的fscanf
现在应该是*(accountNames + count)
或accountNames[count]
。
您可能想添加一个检查是否已读取每个名称的方法,例如,通过在fscanf
中插入%c
来读取数据文件每一行上紧随该名称之后的字符,然后使用isspace()
检查此字符。如果显示错误,则可能需要使用讨论here来启用fscanf
来读取超过19个字符的名称。
答案 1 :(得分:0)
我不是在提倡这种方法,但它似乎是你目前代码的目标:
#include <stdio.h>
#include <stdlib.h>
#define NAME_SIZE 20
int load_data(char *fileName, char *accountNames, int *accountNumbers, float *amounts, int numOfAccounts)
{
FILE *fPtr = fopen(fileName, "r");
if (fPtr == NULL)
{
return 0;
}
int count = 0;
for (int counter = 0; counter < numOfAccounts; counter++)
{
if (fscanf(fPtr, "%19s %d %f", accountNames + (counter * NAME_SIZE), accountNumbers + counter, amounts + counter) == 3)
{
count++;
}
}
fclose(fPtr);
return count;
}
void unload_data(char *accountNames, int *accountNumbers, float *amounts, int numOfAccounts)
{
for (int counter = 0; counter < numOfAccounts; counter++)
{
printf("%s %d %8.2f\n", &accountNames[counter * NAME_SIZE], accountNumbers[counter], amounts[counter]);
}
}
int main(int argc, char *argv[])
{
int numOfAccounts = atoi(argv[2]);
char *fileName = argv[1];
char *accountNames = calloc(numOfAccounts, NAME_SIZE);
int *accountNums = calloc(numOfAccounts, sizeof(int));
float *amounts = calloc(numOfAccounts, sizeof(float));
int datacount = load_data(fileName, accountNames, accountNums, amounts, numOfAccounts);
printf("%d\n", datacount);
unload_data(accountNames, accountNums, amounts, datacount);
free(accountNames);
free(accountNums);
free(amounts);
return 0;
}
输出
% ./a.out test.dat 3
3
Kathryn 1561 2589.98
Hollie 2147 2496.36
Sherlock 3574 2514.65
%
只要您的代码依赖于并行数组,就会错过正确的数据结构。
答案 2 :(得分:0)
OP的代码在内存分配方面存在问题,并且显示在文件输入中。
最好是隔离这两个代码函数。
鉴于每行有3个项目:名称,数量和金额,让我们先做。
使用fscanf()
@William Pursell有很多弱点
,直接转到fgets()
以阅读文本的行。然后解析它。
而不是OP的"%20s%d%f"
,(应该是"%19s%d%f"
,下面的代码使用更复杂的解析,但是如果名称大小限制发生变化则更灵活。而不是检查{{1}的返回值这段代码检查最后解析的字段。代码可以检查两者。
sscanf()
要为int Read_Record(FILE *istream, char *name, size_t name_size, int *number, double *amount) {
// No need to be stingy
#define LINE_SIZE 256
char line[LINE_SIZE];
if (fgets(line, sizeof line, istream) == NULL) {
return EOF;
}
// %n saves the offset of scanning at that point.
int n1;
int n2;
int n3 = -1;
sscanf(line, " %n%*s%n%d%lf %n", &n1, &n2, number, amount, &n3);
// If scanning did not complete or had extra junk on the line, fail
if (n3 < 0 || line[n3] != '\0') {
return 1; // parse failure
}
if (n2 - n1 >= name_size) {
return 2; // name too long
}
memcpy(name, line + n1, n2-n1);
name[n2-n1] = '\0';
return 0; //success
}
条记录分配内存,最好使用结构。由于OP是学习者,让我们在没有numOfAccounts
的情况下执行此操作。
struct
unsigned numOfAccounts = ...;
// TBD: Add test to insure numOfAccounts > 0
// Notice this style of defining the size needed - simple and clean
char **accountNames = malloc(sizeof *accountNames * numOfAccounts);
int *accountNums = malloc(sizeof *accountNums * numOfAccounts);
double *amounts = malloc(sizeof *amounts * numOfAccounts);
// TBD: Add allocation checks
for (unsigned i = 0; i < numOfAccounts; i++) {
#define NAME_SIZE 20
char name[NAME_SIZE];
int rv = Read_Record(istream, name, sizeof name, &accountNums[i],
&amounts[i]);
if (rv != 0) Handle_Error();
accountNums[i] = strdup(name);
}
// Use data
// free when done.
是钱的弱选择。 float
更好。 Many issues有任何选择。