Thread: Maximum of the real numbers found into the input

  1. #1
    Registered User
    Join Date
    Oct 2020
    Posts
    52

    Maximum of the real numbers found into the input

    Write a function that reads data from standard input until EOF is found and returns the maximum of the real numbers found into the input.
    We consider a real number as a number composed of two numbers in base-10, joined by a comma.
    The numbers must be separated from other words by at least one whitespace.
    All the numbers are guaranteed to be positive and to fit in "unsigned" and "double" data types.
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdlib.h>
    #define MAX 100
    unsigned checkWord(char *word)
    {
        int i, j=0,k=0, comma, len = strlen(word);
        char firstHalf[MAX], secondHalf[MAX];
        if(!isdigit(word[0]) || !isdigit(word[len-1]))
            return 0;
        for(i = 1; i < len-1; i++)
        {
            if(word[i] == ',')
            {
                comma = i;
                for(i = 1; i < comma; i++)
                {
                    if(!isdigit(word[i]))
                        return 0;
                }
                for(i = comma+1; i < len-1; i++)
                {
                    if(!isdigit(word[i]))
                        return 0;
                }
            }
        }
        return 1;
    }
    float maximum(float a, float b)
    {
        if(a > b)
            return a;
        else
            return b;
    }
    char *firstHalfNumber(char *word)
    {
        int i, j=0, comma, len = strlen(word);
        char firstHalf[MAX];
        for(i = 1; i < len-1; i++)
        {
            if(word[i] == ',')
            {
                comma = i;
                for(i = 1; i < comma; i++)
                {
                        firstHalf[j++] = word[i];
                }
            }
        }
    }
    char *secondHalfNumber(char *word)
    {
        int i, k=0, comma, len = strlen(word);
        char secondHalf[MAX];
        for(i = 1; i < len-1; i++)
        {
            if(word[i] == ',')
            {
                comma = i;
                for(i = comma+1; i < len-1; i++)
                {
                        secondHalf[k++] = word[i];
                }
            }
        }
    }
    int main()
    {
        char s[MAX];
        float a, b;
        float maxi;
        while(fgets(s, MAX, stdin))
        {
            s[strlen(s)-1] = '\0';
            char *word = strtok(s, " ");
            while(word != NULL)
            {
                //printf("word: %s\n", word);
                if(checkWord(word) == 1)
                {
                    a = atoi(firstHalfNumber(word));
                    b = atoi(secondHalfNumber(word));
                    maxi = maximum(a, b);
                }
            }
        }
        printf("The maximum is %lf.\n", maxi);
        return 0;
    }

    So my idea was to break each line into words, check if the word is a number and then separately break each number into firstHalf(until the comma) and secondHalf(after comma), then use atoi on each and compare them. But I made a lot of mistakes and I'm getting segmentation fault when running the program. Could you give me some ideas?

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,068
    You need to maximize the warning level of your compiler, pay attention to the warnings, and fix them. You have four unused variables in checkWord and you don't return anything from firstHalfNumber or secondHalfNumber functions. If you want to "return" the local char arrays then you will need to make them static.

    you need a second call to strtok at the end in the inner while loop in main in order to move on to the next number. Remember in that call that s needs to be replaced with NULL.

    I don't see why you start your loop at 1 and go up to < len - 1 in the "half" functions. You'll miss the first and last digits.

    I don't see why you are looking for the maximum of the two halves. Aren't they two parts of the same real number? I'm assuming that the comma is being used for the same purpose as the period for Americans, to separate the two parts of a single real number.

    I can think of some other potential problems, but that should be enough to get you going.
    Philosophy is a battle against the bewitchment of our intelligence by means of language. - Wittgenstein

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,231
    Instead of parsing the number yourself, I wonder if it will be easier to "cheat" by replacing the comma, if one exists, with a period, then calling something like strtod.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Oct 2020
    Posts
    52
    Quote Originally Posted by laserlight View Post
    Instead of parsing the number yourself, I wonder if it will be easier to "cheat" by replacing the comma, if one exists, with a period, then calling something like strtod.
    Haha, that's actually what I wanted to do so I would spare myself of all the work but I thought I'd solve it the way it was stated first

  5. #5
    Registered User
    Join Date
    Oct 2020
    Posts
    52
    Quote Originally Posted by john.c View Post
    You need to maximize the warning level of your compiler, pay attention to the warnings, and fix them. You have four unused variables in checkWord and you don't return anything from firstHalfNumber or secondHalfNumber functions. If you want to "return" the local char arrays then you will need to make them static.
    Okay I have no more warnings:
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <stdlib.h>
    #define MAX 100
    unsigned checkWord(char *word)
    {
        int i, comma, len = strlen(word);
        if(!isdigit(word[0]) || !isdigit(word[len-1]))
            return 0;
        for(i = 1; i < len-1; i++)
        {
            if(word[i] == ',')
            {
                comma = i;
                for(i = 1; i < comma; i++)
                {
                    if(!isdigit(word[i]))
                        return 0;
                }
                for(i = comma+1; i < len-1; i++)
                {
                    if(!isdigit(word[i]))
                        return 0;
                }
            }
        }
        return 1;
    }
    float maximum(float a,float b)
    {
        if(a > b)
            return a;
        else
            return b;
    }
    char *firstHalfNumber(char *word)
    {
        int i, j=0, comma, len = strlen(word);
        char *firstHalf = calloc(MAX, sizeof(char));
        for(i = 0; i < len; i++)
        {
            if(word[i] == ',')
            {
                comma = i;
                for(i = 1; i < comma; i++)
                {
                        firstHalf[j++] = word[i];
                }
            }
        }
        free(firstHalf);
        return firstHalf;
    }
    char *secondHalfNumber(char *word)
    {
        int i, k=0, comma, len = strlen(word);
        char *secondHalf = calloc(MAX, sizeof(char));
        for(i = 0; i < len; i++)
        {
            if(word[i] == ',')
            {
                comma = i;
                for(i = comma+1; i < len-1; i++)
                {
                        secondHalf[k++] = word[i];
                }
            }
        }
        free(secondHalf);
        return secondHalf;
    }
    int main()
    {
        char s[MAX];
        float a, b;
        float maxi;
        while(fgets(s, MAX, stdin))
        {
            s[strlen(s)-1] = '\0';
            char *word = strtok(s, " ");
            while(word != NULL)
            {
                //printf("word: %s\n", word);
                if(checkWord(word) == 1)
                {
                   // a = atoi(firstHalfNumber(word));
                   // b = atoi(secondHalfNumber(word));
                   // maxi = maximum(a, b);
                }
                word = strtok(NULL, " ");
            }
        }
        printf("The maximum is %lf.\n", maxi);
        return 0;
    }
    I don't see why you are looking for the maximum of the two halves. Aren't they two parts of the same real number? I'm assuming that the comma is being used for the same purpose as the period for Americans, to separate the two parts of a single real number.
    I'm not, I realised I called the maximum function to check the max of the two halves, but that's not my intention. What I wanna do is: compare the first halves of the first 2 floats, if they are equal also compare the second halves, if they're also equal the numbers are equal and I compare the next one and so on.

  6. #6
    Registered User
    Join Date
    Sep 2020
    Posts
    55
    Wouldn't it be possible to set the locale to a country that uses the comma as decimal separator and read the input as a flaot ?

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    1,068
    Two problems. It makes your program dependent on the user having that locale on their system. Also, using something like sscanf("%f",...) or strtod will allow a value without a fractional part (which seems to be against your directions) as well as forms like 1,2e3.
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <locale.h>
     
    int main() {
        if (!setlocale(LC_NUMERIC, "en_DK.utf8")) {
            printf("setlocale failed\n");
            return 1;
        }
     
        char line[1000];
        const char *const Seps = " \t\r\n";
     
        while (fgets(line, sizeof line, stdin)) {
            char *tok = strtok(line, Seps);
            while (tok) {
                double f;
                int n;
                if (sscanf(tok, "%lf%n", &f, &n) == 1 && !tok[n])
                    printf("%f\n", f);
                tok = strtok(NULL, Seps);
            }
        }
     
        return 0;
    }
    EDIT: The second problem can be solved with an additional test.
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    #include <locale.h>
     
    int okay(const char *s) {
        int commas = 0;
        for (const char *p = s; *p; ++p)
            if (*p == ',') {
                // error if more than 1 comma or it's first or last char
                if (++commas > 1 || p == s || !p[1])
                    return 0;
            }
            else if (!isdigit(*p))
                return 0;
        return 1;
    }
     
    int main() {
        if (!setlocale(LC_NUMERIC, "en_DK.utf8")) {
            printf("setlocale failed\n");
            return 1;
        }
     
        char line[1000];
        const char *const Seps = " \t\r\n";
     
        while (fgets(line, sizeof line, stdin)) {
            char *tok = strtok(line, Seps);
            while (tok) {
                double f;
                if (okay(tok) && sscanf(tok, "%lf", &f) == 1)
                    printf("%f\n", f);
                tok = strtok(NULL, Seps);
            }
        }
     
        return 0;
    }
    Last edited by john.c; 01-18-2021 at 08:06 AM.
    Philosophy is a battle against the bewitchment of our intelligence by means of language. - Wittgenstein

  8. #8
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    764
    Can you use sscanf to split each "word" in a line into numbers?

    Code:
    double a, b;
    char *word = line;
    int n, offset;
    while ((n = sscanf(word, "%lf,%lf%n", &a, &b, &offset)) == 2) {
        word += offset;
        // do something with a and b
    }
    Edit: on second thought, there's no need to use both fgets and sscanf. You can use scanf by itself (and you don't need "offset" and %n in the format string) to do the same thing.

  9. #9
    Registered User
    Join Date
    Dec 2017
    Posts
    1,068
    @christop, I think the input is a mixture of words and numbers, e.g.:
    Code:
    alpha beta 3,14 gamma 145,70 delta epsilon 0012,34 zeta
    Your variable n is unused in your code.

    There's no reason to use double (in fact it's wrong since it would allow 1.2,3.4). Use unsigned int instead. Although a problem with an input spec like "%u,%u" is that it would allow "1, 2" since %u skips whitespace first.

    The assignment can be done with only unsigned ints, avoiding floating point entirely.

    Here's the original assignment description:
    Write a function that reads data from standard input until EOF is found and returns the maximum of the real numbers found in the input. We consider a real number as a number composed of two numbers in base-10, joined by a comma. The numbers must be separated from other words by at least one whitespace. All the numbers are guaranteed to be positive and to fit in "unsigned" and "double" data types.
    E.g. of valid numbers: 3,14 145,70 0012,34 etc.
    Philosophy is a battle against the bewitchment of our intelligence by means of language. - Wittgenstein

  10. #10
    Registered User
    Join Date
    Oct 2020
    Posts
    52
    Quote Originally Posted by thmm View Post
    Wouldn't it be possible to set the locale to a country that uses the comma as decimal separator and read the input as a flaot ?
    I'm kind of a newbie in C and I haven't learned about setlocale yet

  11. #11
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    764
    Quote Originally Posted by john.c View Post
    @christop, I think the input is a mixture of words and numbers, e.g.:
    Code:
    alpha beta 3,14 gamma 145,70 delta epsilon 0012,34 zeta
    Ah, I read the description as if a comma-separated pair of numbers was called a "word". I suppose the assignment could be intended to have actual words on the input as you described. That definitely is more challenging than my simple approach (but if I were the OP I'd ask the instructor for clarification on this point).
    Last edited by christop; 01-18-2021 at 02:49 PM. Reason: accidentally a word

  12. #12
    Registered User
    Join Date
    Sep 2020
    Posts
    55
    Wouldn't it be possible to set the locale to a country that uses the comma as decimal separator and read the input as a flaot ?
    Two problems. It makes your program dependent on the user having that locale on their system. Also, using something like sscanf("%f",...) or strtod will allow a value without a fractional part (which seems to be against your directions) as well as forms like 1,2e3.
    You are right. Thanks for pointing it out.

  13. #13
    Registered User
    Join Date
    Dec 2017
    Posts
    1,068
    @christop, You're right that the word "word" is ambiguous. I just assumed it had it's "normal" meaning, but it could just mean "token" and the input could just be all numbers of the given form. I was also assuming that their could be numbers in the wrong form: starting or ending with a comma, having no comma or more than one comma, etc. But who knows.
    Philosophy is a battle against the bewitchment of our intelligence by means of language. - Wittgenstein

  14. #14
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,231
    It sounds like this is the problem text rather than a paraphrase: "The numbers must be separated from other words by at least one whitespace."

    If so, "word" in this context is used to mean "token", but the fact that "number" is also used seems to imply that there are "words" that are not "numbers". Otherwise, it'll make more sense to just stick to "number" as used in the preceding text.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 0
    Last Post: 01-10-2021, 06:01 AM
  2. Replies: 2
    Last Post: 05-28-2009, 09:58 PM
  3. Displaying Minimum and Maximum values from input
    By mgardnertech in forum C Programming
    Replies: 1
    Last Post: 06-29-2008, 08:47 PM
  4. real random numbers
    By mewatC in forum C Programming
    Replies: 7
    Last Post: 09-01-2006, 01:39 PM
  5. Real and Imaginary numbers
    By tetra in forum C++ Programming
    Replies: 13
    Last Post: 02-03-2003, 11:49 AM

Tags for this Thread