简体   繁体   中英

Fscanf to read a mixture of float and characters in c

So I have a .txt file which is as following:

** Paris ** Flight,5 days,visiting various monuments. | 2999.99 |
** Amsterdam ** By bus,7 days, local art gallery. | 999.99 |
** London ** Flight,3 days,lots of free time. | 1499.99 |

I want to get the information stored into 3 variables, city, description and price, but I can't get it to save the lines at all.

   #include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fp;
    char city[256],desciption[256];
    float temp;
    if(fp=fopen("Ponuda.txt","rt")==NULL){
        printf("ERROR\n");
        exit(1);
    }

    while(fscanf(fp,"** %s ** %s | %f |",city,description,&temp)==3){

        printf("** %s ** %s |%f|\n",city,description,temp);
    }
    return 0;

IMO it is much easier to read each file line with fgets , and then use strtok to split each line with the delimiter string "*|" .

Then I use strdup to duplicate the text strings into the struct, and sscanf to extract the fare from the third token. I should have tested the return value from strdup , as it calls malloc internally.

I also use double instead of float (which I will only use if there are constraints).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX  10

typedef struct {
    char *city;
    char *descrip;
    double fare;
} flight_t;

int main()
{
    FILE *fp;
    flight_t visit[MAX] = {0};
    char buffer [1024];
    char *tok;
    int records = 0, i;
    if((fp = fopen("Ponuda.txt", "rt")) == NULL) {
        printf("Error opening file\n");
        exit(1);
    }

    while(fgets(buffer, sizeof buffer, fp) != NULL) {
        if((tok = strtok(buffer, "|*")) == NULL) {
            break;
        }
        if(records >= MAX) {
            printf("Too many records\n");
            exit(1);
        }
        visit[records].city = strdup(tok);          // add NULL error checking

        if((tok = strtok(NULL, "|*")) == NULL) {    // pass NULL this time
            break;
        }
        visit[records].descrip = strdup(tok);       // add NULL error checking

        if((tok = strtok(NULL, "|*")) == NULL) {    // pass NULL this time
            break;
        }
        if(sscanf(tok, "%lf", &visit[records].fare) != 1) {     // read a double
            break;
        }
        records++;
    }

    fclose(fp);

    // print the records
    for(i = 0; i < records; i++) {
        printf("** %s ** %s |%.2f|\n", visit[i].city, visit[i].descrip, visit[i].fare);
    }

    // free the memory given by strdup
    for(i = 0; i < records; i++) {
        free(visit[i].city);
        free(visit[i].descrip);
    }
    return 0;
}

Program output:

**  Paris  **  Flight,5 days,visiting various monuments.  |2999.990000|
**  Amsterdam  **  By bus,7 days, local art gallery.  |999.990000|
**  London  **  Flight,3 days,lots of free time.  |1499.990000|

This is very difficult to do with a single fscanf statement, since, as @Barmar pointed out, the city name may be more than one word. It is much easier to read the entire line (using fgets) and then parsing the line yourself. To parse it:

  1. Find the first non-blank character after "**"
  2. Find the last non-blank character after that, that precedes " **'
  3. The text between those indices will be the city name (it may contain spaces)
  4. The description is the text between the " **" found in step 2, and the index of the next '|' after that.
  5. The cost is the string following that '|'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM