سؤال

I'm experiencing some difficulty with either my fscanf function or my printf function. I made the printf function to test to see if my values were being stored properly, and they are not working properly. Printf prints some very strange looking values on the output screen.

Text from 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

Source file:

#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);
    }
}
هل كانت مفيدة؟

المحلول

Using %s with scanf means to read a word. It stops when it hits a space. However, your sourcefile contains some spaces inside the things you are trying to read. For example, WASHINGTON and NEW YORK both need to be read into city.

You have to read an exact number of characters from your file, instead of using %s.

One way to do that is to, in the fscanf only, change %11s to use this specifier: %11[^\n] . That means to read the next 11 characters (unless we hit the end of the line), even if there are spaces in it.

This will actually put trailing spaces into your strings, so if you don't want the trailing spaces then you will need to make another function which deletes them from your string.

You should also check the return value of fscanf. Since you are trying to read 11 items, it should return 11. If it returns something else then your program should report a data error and stop reading.

NB. For testing purposes, in your printf, use commas or something, instead of spaces, between the items; this will make it easier to identify whether the data is being read that way you expect.

نصائح أخرى

fscsanf tokenises based on whitespace. Thus, your address will be tokenised into its various parts, and thus won't get matched as you expect.

You should have a field separator such as a , (often faulty), | (generally better, but not perfect), or \t (can be a little tricky when data gets transmitted).

Then use a function such as strtok_r to get each field.

PS. the scanf series of functions are not particularly robust for parsing (particularly for catching errors); you can quickly strike limitations.

Why not read them in directly to a struct with fgets? Or better yet if it is a Posix system and since the size is fixed 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;

Then handle any necessary conversions explicitly as needed either on the fly or to a separate struct as you have or even use unions to do it in place.

Here is an example struct (*its been a bit since I've used nested anonymous unions and struct so edit me if you catch something)

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;

After reading into each employee, you would need to run appropriate conversions for each field. This would include placing '\0' at the ends of strings, converting non string fields to short, int or float. Just keep in mind that they occupy the same memory.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top