LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Why doesn't this program terminate properly? c++ (https://www.linuxquestions.org/questions/programming-9/why-doesnt-this-program-terminate-properly-c-4175641154/)

TheEzekielProject 10-25-2018 09:43 PM

Why doesn't this program terminate properly? c++
 
Hello all,

I am teaching myself C++ with the help of Programming Principles and Practice Using C++ by Bjarnes Stroustrup but I am having trouble with a drill exercise.


The step of the drill is to create a program in which you enter two numbers and the program states which is smaller and which is larger, or if they are equal. And it is supposed to terminate on entering the '|' character.


The program works so far, except for when entering the '|' character, it infinitely repeats the last larger/smaller lines e.g.
Code:

23 is the smaller number.
32 is the larger number.
23 is the smaller number.
32 is the larger number.
23 is the smaller number.
32 is the larger number.
23 is the smaller number.
32 is the larger number.
23 is the smaller number.
...

I'm sure I'm missing something simple. But I can't quite figure out what! A hint in the right direction would be appreciated


Code:

#include <iostream>
#include <cmath>
#include <vector>
#include <string>

int main ()
{
    double x, y;
    std::cout <<"Enter 2 integers, terminate with '|'\n";
    std::cin>> x >> y;
    while(x !='|' && y != '|')
    {

        if(x<y)
            std::cout << x <<" is the smaller number.\n" << y <<" is the larger number.\n";
        else if(y<x)
            std::cout << y <<" is the smaller number.\n" << x <<" is the larger number.\n";
        else if(x==y)
            std::cout <<"The numbers are equal.\n";
        std::cin >> x >> y;
       
    }
    return 0;

}


Mechanikx 10-25-2018 10:08 PM

You've declared 'x' and 'y' to be of type double. '|' is a char.

If I change your while statement to:

while(x != 0 && y != 0)

for instance, it terminates appropriately.

TheEzekielProject 10-25-2018 10:15 PM

Thank you for pointing that out!
The exercise requires that I use '|' so I suppose I will have to find another way.

NevemTeve 10-25-2018 10:30 PM

You could use fgets to read a line, remove the terminating \n character, then compare the content with "|".
Then try sscanf (fmt "%lf %lf") to read two double values from the linlineffer - if it doesn't return 2, then warn the users.

TheEzekielProject 10-25-2018 10:34 PM

Quote:

Originally Posted by NevemTeve (Post 5919256)
You could use fgets to read a line, remove the terminating \n character, then compare the content with "|".
Then try sscanf (fmt "%lf %lf") to read two double values from the linlineffer - if it doesn't return 2, then warn the users.




I am only on the 4th Chapter of the book and have not learned about those. I am assuming I am supposed to find a way to accomplish the task only with what has been taught so far.


But thank you for the suggestion!

Mechanikx 10-25-2018 10:46 PM

Quote:

Originally Posted by TheEzekielProject (Post 5919257)
I am only on the 4th Chapter of the book and have not learned about those. I am assuming I am supposed to find a way to accomplish the task only with what has been taught so far.


But thank you for the suggestion!

In that case you can declare 'x' and 'y' to be of type 'char' that way you can store a '|' in either of them during runtime. The only difference is you'll now be comparing the characters '23' and '32', for example.

EDIT: This is incorrect. It will only properly compare single character digits. Sorry, it's been a long day.

NevemTeve 10-25-2018 10:48 PM

Well, these functions/ways are considered to be 'old fashioned' by some C++ programmers, so you might not read about them in Stroupstrup's book.
A note: at this level it might be completely enough to exit when the reading of a number fails (see cin.fail())

TheEzekielProject 10-25-2018 10:54 PM

Quote:

Originally Posted by Mechanikx (Post 5919259)
In that case you can declare 'x' and 'y' to be of type 'char' that way you can store a '|' in either of them during runtime. The only difference is you'll now be comparing the characters '23' and '32', for example.




The directions for this part requires that I use 'double'


Quote:

1. Write a program that consists of a while-loop that (each time around the loop) reads in two ints and then prints them. Exit the program when a terminating '|' is entered.
2. Change the program to write out the smaller value is: followed by the smaller of the numbers and the larger value is: followed by the larger value.
3. Augment the program so that it writes the line the numbers are equal (only) if they are equal.
4. Change the program so that it uses doubles instead of ints.

Mechanikx 10-26-2018 01:05 AM

I remember doing a project similar to this one when I was learning C. You had to write a program that functioned like an accumulator. So, you would enter a number then an arithmetic symbol to operate on the total amount stored. The input was 'int' 'char'. Where 'char' was the arithmetic symbol or 'E' to exit.

Beryllos 10-26-2018 01:05 PM

I am not an expert in C++, but I gather that you could define a class which can contain either double or char, and define corresponding methods for input and comparison. I have never done that, but it is possible, right?

TheEzekielProject 10-26-2018 03:00 PM

Just in case anyone is interested I think I'm making progress
Code:

#include <iostream>
#include <cmath>

int main ()
{
        int x, y;
        std::cout <<"Enter 2 integers, terminate with '|'\n";
        while(std::cin >> x >> y)
        {

                if(x<y)
                        std::cout << x <<" is the smaller number.\n" << y <<" is the larger number.\n";
                else if(y<x)
                        std::cout << y <<" is the smaller number.\n" << x <<" is the larger number.\n";
                else if(x==y)
                        std::cout <<"The numbers are equal.\n";
        }
        return 0;

}

Right now it terminates on any non int character. But I think it's a start in the right direction

astrogeek 10-26-2018 03:29 PM

Quote:

Originally Posted by TheEzekielProject (Post 5919520)
Just in case anyone is interested I think I'm making progress
Code:

#include <iostream>
#include <cmath>

int main ()
{
        int x, y;
        std::cout <<"Enter 2 integers, terminate with '|'\n";
        while(std::cin >> x >> y)
        {

                if(x<y)
                        std::cout << x <<" is the smaller number.\n" << y <<" is the larger number.\n";
                else if(y<x)
                        std::cout << y <<" is the smaller number.\n" << x <<" is the larger number.\n";
                else if(x==y)
                        std::cout <<"The numbers are equal.\n";
        }
        return 0;

}

Right now it terminates on any non int character. But I think it's a start in the right direction

Of course that is not in line with the previous instructions...

Quote:

Originally Posted by TheEzekielProject (Post 5919263)
The directions for this part requires that I use 'double'

But the whole point of such exercises is to get you to explore the territory, the best way to learn, so all variations can be informative!

Considering the problem of doing it with doubles, using "|" as the only termination character is an interesting exercise, no doubt why it was included!

Think about it this way: Your first task was to use integer types which presumably resulted in your code structure. The termination test was a natural fit in that case - you didn't have to think about it too much. Then they asked you to use doubles for the numeric types, which produces the apparent "conflict" with the termination character comparison - but only because you already wrote everything usiing integers! Now you have to think about how to accept and compare numeric input or character input, without knowing which it will be in advance. Stringstream comes to mind.

Good luck!

BW-userx 10-26-2018 05:03 PM

Quote:

Originally Posted by TheEzekielProject (Post 5919263)
The directions for this part requires that I use 'double'

Quote:

1. Write a program that consists of a while-loop that (each time around the loop) reads in two ints and then prints them. Exit the program when a terminating '|' is entered.
2. Change the program to write out the smaller value is: followed by the smaller of the numbers and the larger value is: followed by the larger value.
3. Augment the program so that it writes the line the numbers are equal (only) if they are equal.
4. Change the program so that it uses doubles instead of ints.

that is line 4 that you are to use doubles, this is having you going one step at a time, your use of double code should already have the '|' figured out in how to do that while using int for your numbers. whereas I do not see this in your code.

try this, its in need of cleaning up, but... it works for me..
Code:

#include <iostream>
#include <cstdlib>
#include <cstring>

int main ()
{
  char x1[2];
  char y1[2];
 
std::cout <<"Enter 2 integers 0 - 9 , terminate with '|'\n";
   
    for (;;)
    {
            std::cout<<"enter 1st number\n";
            std::cin>> x1 ;
      // feed back to see what I am working with
        std::cout<<x1[0]<<std::endl;
        std::cout<<" compare "<<strcmp("|", x1)<<std::endl;
           
            if ( strcmp("|", x1) == 0)
                  return 0;

        std::cout<<"enter second number : ";
        std::cin >>y1;

        //is int because that is what is returned
        // so it meets the requirement of the assignment
        auto x = atoi(x1);
        auto y = atoi(y1);
       
        if ( x == y )
            std::cout<<x<<" is equal to "<<y<<std::endl;
        else if ( x > y )
            std::cout<<x<<" is larger than " <<y<<std::endl;
        else
            std::cout<<x<<" is lesser than "<<y<<std::endl;
      }
      return 0;
}

stop and think it through first so you can build on your programming logic.

you where taking in both, one after then other, and only need to check for the first one, first to see if that meets the requirements to stop the program, if no, then take in second data type, then proceed with what ever you need to do.

your 'if statements too' it is process of elimination logic
Code:


    if(x<y)
        std::cout << x <<" is the smaller number.\n" << y <<" is the larger number.\n";
    else if(y<x)
        std::cout << y <<" is the smaller number.\n" << x <<" is the larger number.\n";
    else if(x==y)
        std::cout <<"The numbers are equal.\n";

that is not applying that logic. it is,
Code:

if
else if
else


mina86 10-28-2018 05:33 AM

Quote:

Originally Posted by TheEzekielProject (Post 5919263)
The directions for this part requires that I use 'double'

Not quite. It requires that you read two numbers but it doesn’t say you need to read them directly to a variable of wanted type. In fact, if pipe character is the only thing that terminates the program, you must read the data into a string first. To do that, declare a std::string buf and then do std::cin >> buf. You can then inspect the value to detect whether it’s a pipe character. If it is – terminate, if it’s not – try to convert the value to a number with strtol or strtod which will let you detect when an invalid value is entered. Here’s one approach which loops when incorrect value is entered and reads the next one (alternative would be to terminate on any error):

Code:

#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>

static int read_long(long *value) {
        for (std::string buf; std::cin >> buf; ) {
                if (buf == "|") {
                        return 0;
                }
                errno = 0;
                char *end;
                long ret = strtold(buf.c_str(), &end);
                if (*end || (errno && errno != ERANGE)) {
                        std::cerr << "Expected integer or '|', got "
                                  << buf << '\n';
                } else if (errno == ERANGE) {
                        std::cerr << "Value too large\n";
                } else {
                        *value = ret;
                        return 1;
                }
        }
        return -1;  /* EOF */
}

int main() {
        for (;;) {
                long x, y;
                int ret = read_long(&x);
                if (ret < 1) {
                        return -ret;
                }
                ret = read_long(&y);
                if (ret < 1) {
                        return -ret;
                }
                if (x == y) {
                        std::cout << "The numbers are equal.\n";
                } else {
                        std::cout << (x < y ? x : y)
                                  << " is the smaller number; "
                                  << (x < y ? y : x)
                                  << " is the larger number.\n";
                }
        }
}

Perhaps a more interesting problem would be to support numbers of arbitrary length. For integers it’s relatively simple problems. For real numbers it gets a little bit trickier though not too bad if one chooses not to support exponent format.


All times are GMT -5. The time now is 01:28 AM.