arrayscstringstruct

How can I correctly write code in C language to accept input containing spaces in between and ending with a newline?


here is my input:

3
Programming in C
21.5
Programming in VB
18.5
Programming in Delphi
25.0

and here is my code:

#include<stdio.h>
#include<string.h>
struct book{
    char name[30];
    double price;
};
int main(){
    int i,n,max=0,min=0;
    scanf("%d",&n);
    struct book bo[10];
    for(i=0;i<n;i++){
        fgets(bo[i].name,sizeof(bo[i].name),stdin);
        strtok(bo[i].name,"\n");
        scanf("%lf\n",&bo[i].price);
        if(bo[i].price>bo[max].price)
            max=i;
        if(bo[i].price<bo[min].price)
            min=i;
    }

    printf("%.2f, %s\n",bo[max].price,bo[max].name);
    printf("%.2f, %s",bo[min].price,bo[min].name);
    return 0;
}

I don't know why i always get the operation answer like: 21.50, Programming in C 0.00,

I have try to use “fgets” to read the spaces and use "strtok" like strtok(bo[i].name,"\n"); or "strcspn" like bo[i].name[strcspn(bo[i].name,"\n")]='\0'; to replace '\n' with '\0',but it is still incorret.


Solution

  • You want to clear the newline from the stdin steam after reading number field (n and price) before reading a string after name). I used scanf("%*[\n]") below. I switched to using scanf() to read a line of text to show you a different option than the other options.

    Another really good option is to read a line of input with gets() or getline() then use sscanf() to parse that line of text. This separates I/O and parsing.

    In any case always check the return value from I/O calls otherwise you may be operating on uninitialized variables. Instead of hard-coding the number of records use a variable length array (vla) but check that the number of records are reasonable.

    #include <stdio.h>
    #include <string.h>
    #define NAME_LEN 29
    #define str(s) str2(s)
    #define str2(s) #s
    
    // increase as needed
    #define MAX_N 10
    
    struct book{
        char name[NAME_LEN+1];
        double price;
    };
    
    int main(void) {
        int n;
        if(scanf("%d", &n) != 1) {
            fprintf(stderr, "failed reading number of records\n");
            return 1;
        }
        if(scanf("%*[\n]") != 0) {
            fprintf(stderr, "failed reading number of records terminator\n");
            return 1;
        }
        if(n <= 0 || n > MAX_N) {
            fprintf(stderr, "too few or too many records\n");
            return 1;
        }
        int max=0;
        int min=0;
        struct book bo[n];
        for(int i=0; i<n; i++) {
            if(scanf("%" str(NAME_LEN) "[^\n]", bo[i].name) != 1) {
                fprintf(stderr, "Failed reading name\n");
                return 1;
            }
            if(scanf("%lf", &bo[i].price) != 1) {
                fprintf(stderr, "failed reading price\n");
                return 1;
            }
            if(scanf("%*[\n]") != 0) {
                fprintf(stderr, "failed reading price terminator\n");
                return 1;
            }
            // pick first book if several have the same price;
            // use >= or <= if you want the last.  If you want
            // to keep all then you need to keep an array of 
            // worst case min[n] and max[n] values.
            if(bo[i].price>bo[max].price)
                max=i;
            if(bo[i].price<bo[min].price)
                min=i;
        }
        printf("%.2f, %s\n", bo[min].price, bo[min].name);
        printf("%.2f, %s\n", bo[max].price, bo[max].name);
        return 0;
    }
    

    and output:

    $ ./a.out < input.txt
    18.50, Programming in VB
    25.00, Programming in Delphi