fscanf返回值0 - C.

时间:2016-11-18 16:44:54

标签: c return-value scanf

我有一个看起来像这样的文件:

  

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所以我要求你耐心等我正在学习,但如果有人能帮助我那会很棒。如果我需要提供更多信息,请与我们联系。谢谢。

3 个答案:

答案 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可以从0numOfAccounts,而不是从1numOfAccounts,因此您只有一个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有任何选择。