【问题标题】:What am I doing wrong with fscanf and printf?我在 fscanf 和 printf 上做错了什么?
【发布时间】:2014-05-12 01:32:32
【问题描述】:

我在使用 fscanf 函数或 printf 函数时遇到了一些困难。我制作了 printf 函数来测试我的值是否被正确存储,并且它们不能正常工作。 Printf 在输出屏幕上打印一些看起来很奇怪的值。

payfile.txt 中的文本:

ADA     A AGUSTA    33 BABBAGE ROAD  LOVELACE    GB 19569 28 F 2 350.50
ISSAC   A ASIMOV    99 FICTION WAY   AMHERST     MA 63948 58 M 6 423.88
HUMPHRY R BOGART    71 SAM STREET    HOLLYWOOD   CA 48482 56 M 5 366.00
ALBERT  G EINSTEIN  94 ENERGY WAY    PRINCETON   NJ 47474 67 M 8 780.00
EMMYLOU L HARRIS    66 COUNTRY ROAD  NASHVILLE   TN 72647 38 F 2 767.42
JAMES   T KIRK      11 SPACE STREET  VULCAN      CA 82828 46 M 1 235.70
TED     L KOPPEL    55 ABC PLACE     WASHINGTON  DC 37376 48 M 9 909.44
DAVID   T LETTERMAN 14 WNBC AVENUE   NEW YORK    NY 19338 47 M 5 445.65
STEVIE  R NICKS     31 MUSIC ROAD    CHICAGO     IL 23459 38 F 8 460.88
MONTY   P PYTHON    76 SILLY STREET  LONDON      GB 80939 44 M 2 320.50
ROGER   R RABBIT    15 LOONEY TOONS  HOLLYWOOD   CA 91343 24 M 4 259.53
SALLY   W RIDE      21 COLUMBIA WAY  HOUSTON     TX 91123 30 F 9 707.80
ROD     Q SERLING   11 TWLIGHT ZONE  SAN DIEGO   CA 93939 56 M 1 440.00
LUKE    R SKYWALKER 43 MILKY WAY     NEW YORK    NY 12343 35 M 5 660.00

源文件:

#include <stdio.h>

typedef struct {
    char first[8];
    char initial;
    char last[10];
    char street[17];
    char city[12];
    char state[3];
    char zip[6];
    int age;
    char sex;
    int tenure;
    double salary;
} Employee;

void readData(Employee *number);

int main(void){
    Employee number[14];

    readData(number);
    getchar();
    return 0;
}

void readData(Employee *number){
    int i;
    FILE *f = fopen("payfile.txt", "r");
    for (i = 0; i < 14; i++) {
        fscanf(f, "%7s %c %9s %16s %11s %2s %5s %d %c %d %lf\n", number[i].first, &number[i].initial, number[i].last, number[i].street, number[i].city, number[i].state, number[i].zip, &number[i].age, &number[i].sex, &number[i].tenure, &number[i].salary);
        printf("%s %c %s %s %s %s %s %d %c %d %f\n", number[i].first, number[i].initial, number[i].last, number[i].street, number[i].city, number[i].state, number[i].zip, number[i].age, number[i].sex, number[i].tenure, number[i].salary);
    }
}

【问题讨论】:

  • 你遇到了什么错误?
  • 总是检查*scanf的返回值!它应该等于您希望匹配的项目数。
  • 输出的值很奇怪,所以我知道出了点问题。还有 Jonathon,我不太清楚这意味着什么,我只是第一次编程的学生,我犯了一个错误,参加了在线课程。

标签: c printf scanf


【解决方案1】:

使用%sscanf 意味着读取一个单词。当它碰到一个空格时它会停止。但是,您的源文件在您尝试阅读的内容中包含一些空格。比如WASHINGTONNEW YORK都需要读入city

您必须从文件中读取确切数量的字符,而不是使用%s

一种方法是,仅在 fscanf 中,将 %11s 更改为使用此说明符:%11[^\n]。这意味着读取接下来的 11 个字符(除非我们到达行尾),即使其中有空格。

这实际上会将尾随空格放入您的字符串中,因此如果您不想要尾随空格,那么您将需要创建另一个函数将它们从您的字符串中删除。

您还应该检查fscanf 的返回值。由于您正在尝试阅读 11 个项目,因此它应该返回 11。如果它返回其他内容,那么您的程序应该报告数据错误并停止读取。

注意。出于测试目的,在您的printf 中,在项目之间使用逗号或其他东西,而不是空格;这将使您更容易识别数据是否以您期望的方式读取。

【讨论】:

    【解决方案2】:

    fscsanf 基于空格的标记。因此,您的地址将被标记为各个部分,因此不会像您期望的那样匹配。

    您应该有一个字段分隔符,例如 ,(经常出错)、|(通常更好,但并不完美)或 \t(在传输数据时可能有点棘手)。

    然后使用strtok_r等函数获取各个字段。

    PS。 scanf 系列函数对于解析不是特别健壮(特别是对于捕获错误);您可以快速突破限制。

    【讨论】:

    • 感谢您的回复,但 strtok_r 对我来说是陌生的。我快要放弃这个项目了。
    • 对此展开:OP可以用fgets将整行读入内存,然后插入字段分隔符:line[7] = line[9] = line[18] = line[21] = .... = '|';,再用strtok就行了。但他还需要做一些 string-int 和 string-double 转换以及这个。
    • @ShaneBird。如果这就是您所需要的,那么 C 不太可能是完成这项工作的最佳工具。你可能会在 Python 之类的东西上做得更好。使用 C 有什么真正令人信服的理由吗?尽管我很喜欢它,但它不是我进行文本处理的首选。
    • 是的,不幸的是,我现在正在上课,我有点希望我在这一点上会失败,因为这样我就可以重新参加并且没有在线课程,我可能能够获得 A。
    【解决方案3】:

    为什么不用 fgets 直接将它们读入结构?或者如果它是 Posix 系统并且由于大小是固定的 read() 更好。

    typedef struct {
      char first[8];
      char initial[2];
      char last[10];
      char street[17];
      char city[12];
      char state[3];
      char zip[6];
      char age[3]
      char sex[2];
      char tenure[2];
      char salary[6];
      char pad[128-71]; // pad to a factor of 2
    } Employee;
    

    然后根据需要显式地处理任何必要的转换,或者像你拥有的那样处理到单独的结构,甚至使用联合来完成它。

    这是一个示例结构(*它有点因为我使用了嵌套匿名联合和结构,所以如果你发现了什么,请编辑我)

    typedef struct {
      char first[8];
      char initial[2];
      char last[10];
      char street[17];
      char city[12];
      char state[3];
      union{
        char zip_in[6];
        struct{
        int zip;
        char pad_zip[2];
        }
      }
      union{
        char age_in[3]
        struct{
          short age;
          char pad_age;
        }
      }
      char sex[2];
      char tenure[2];
      union{
        char salary_in[6];
        struct{
          float salary;
          char pad_salary[2];
        }
      }
      char pad[128-71]; // pad to a factor of 2
    } Employee;
    

    阅读每位员工后,您需要为每个字段运行适当的转换。这包括将 '\0' 放在字符串的末尾,将非字符串字段转换为 short、int 或 float。请记住,它们占用相同的内存。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 2019-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多