0
\$\begingroup\$

You probably know the following problem: You have written a small program that runs in your console and want the user to enter something. of course, it is very inconvenient when the user types the wrong things, so we have to prepare for any small child hacking like a madman on the keyboard.

Most functions wait for a valid input, which results in the problem that nasty line breaks occur when the user ONLY presses the enter key.

the problem is also normally easy to solve under Linux: read a character with getchar, determined the position of the cursor with the ANSI escape sequences and provided the whole thing with a do while loop.

BUT: I was not able to find a simple function to read in numbers in the same elegant way. The function must be able to read in numbers, but also be able to prevent line breaks. to achieve this, I used getchar and store the characters in a char array, whose indices I then convert to the corresponding numbers, which I then add to the actual number.

But maybe there is an easier way? or you have ideas how to optimize the function?

#include <iostream>
#include "TheGameHeaders.h"

#define CLEAR_LINE printf("\033[K")
#define POSITION(Ze, Sp) printf("\033[%d;%dH", Ze, Sp)
#define CLEAR printf("\033[2J")


int getint(int pos_ze, int pos_sp, int qntty_of_incs)
{   
    int i = 0;
    char fake_nbr;
    char fake_nbrs[qntty_of_incs];

    int real_nbr = 0;
    int real_nbrs[qntty_of_incs];


    do
    {
        POSITION(pos_ze, pos_sp);
        while((fake_nbr = getchar()) != '\n')
        {
            if(fake_nbr == '0' || fake_nbr == '1' || fake_nbr == '2' || fake_nbr == '3' || fake_nbr == '4' || fake_nbr == '5' || fake_nbr == '6' || fake_nbr == '7' || fake_nbr == '8' || fake_nbr == '9')
            {
                if(i <= (qntty_of_incs-=1))
                {
                    fake_nbrs[i] = fake_nbr;
                    i++;
                    qntty_of_incs++;
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                return 0;
            }
        }
    }
    while(i < 1);

    for(int a = 0; a < i; a++)
    {
        fake_nbrs[a] -= '0';
        real_nbrs[a] = fake_nbrs[a];
    }

    int i_fix = i;
    int i_fix_2 = i-=1;

    for(int a = 0; a < i_fix; a++)
    {
        i = i_fix_2;
        real_nbrs[a] *= pow(10, i-=a);
    }

    for(int a = 0; a < i_fix; a++)
    {
        real_nbr += real_nbrs[a];
    }

    return real_nbr;
}

oh and pow is a simple function:

int pow(int base, int exponent)
{

    if(exponent == 0)
    {
        return 1;
    }

    exponent -= 1;
    int fixBase = base;

    for(int i = 0; i < exponent; i++)
    {
        fixBase *= base;
    }

    return fixBase;
}
\$\endgroup\$
5
  • 1
    \$\begingroup\$ This is not C++. This is C. \$\endgroup\$
    – indi
    Feb 23 at 1:44
  • 1
    \$\begingroup\$ maybe it looks like c because i learned some c before i started with c++ but this is definitely c++ \$\endgroup\$
    – Lui
    Feb 23 at 7:46
  • 1
    \$\begingroup\$ No, it’s definitely C. It’s not just “bad-C++-that-looks-like-C”, it’s C; it won’t even compile in a C++ compiler without C extensions. It’s just C code with #include <iostream> at the top (for no good reason anyway, because it’s never used). You might as well put import sys at the top and call it Python. \$\endgroup\$
    – indi
    Feb 23 at 11:14
  • 1
    \$\begingroup\$ Have to agree this is C code. It may happen to compile with a lenient C++ compiler but that does not change it from C code that happens to use some C++ features accidently. \$\endgroup\$ Feb 23 at 18:09
  • 1
    \$\begingroup\$ @Lui stop treating c++ like c. If you’re going to learn c++ you must learn modern c++ (otherwise there’s no point you are just using the c part of c++). Modern c++ and c having nothing in common (except like curly braces). To get you started on modern c++ learn about oop, smart pointers and the stl. Trust me, c++ and c are completely different (look at template meta programming if you don’t believe me). \$\endgroup\$ Feb 24 at 21:06
2
\$\begingroup\$

Overview

Looks like you are reading data from the standard input and converting to a number. There is already code for that:

int val;
std::cin >> val;

You use C functionality throughout this code (printf/arrays/getchar) where there are better C++ alternatives (std::cout/vector/std::cin). A lot of this work can be delegated to standard functions.

Code Review

#include <iostream>

What are these headers and what do they define?

#include "TheGameHeaders.h"

This is very terminal specific.

#define CLEAR_LINE printf("\033[K")
#define POSITION(Ze, Sp) printf("\033[%d;%dH", Ze, Sp)
#define CLEAR printf("\033[2J")

A lot of terms might support this but it is not universal. Have a look at ncurses library; that will provide a terminal-neutral way to achieve all this. ncurses, and curses before it, look up these control characters from their terminal databases and retrieve the terminal-specific escape codes.


This is not standard C++:

    char fake_nbrs[qntty_of_incs];

If you want dynamic (run time sized) arrays, then you should be using std::vector<>


We have standard functions for checking for numbers:

        while((fake_nbr = getchar()) != '\n')
        {
            if(fake_nbr == '0' || fake_nbr == '1' || fake_nbr == '2' || fake_nbr == '3' || fake_nbr == '4' || fake_nbr == '5' || fake_nbr == '6' || fake_nbr == '7' || fake_nbr == '8' || fake_nbr == '9')

Have a look at:

   std::isdigit()

Returning valid integer numbers to indicate failure conditions is probably not a good idea.

                else
                {
                    return 1;
                }
            }
            else
            {
                return 0;
            }

How can the user of your code tell if this is real user input or an error?


You use several loops to convert the each number to its correct value. Why not do this in a single loop?

    for(int a = 0; a < i; a++)
    {
        fake_nbrs[a] -= '0';
        real_nbrs[a] = fake_nbrs[a];
    }

    int i_fix = i;
    int i_fix_2 = i-=1;

    for(int a = 0; a < i_fix; a++)
    {
        i = i_fix_2;
        real_nbrs[a] *= pow(10, i-=a);
    }

    for(int a = 0; a < i_fix; a++)
    {
        real_nbr += real_nbrs[a];
    }

Seems simpler like this:

   int result = 0
   for(int a = j; a > 0; a--) {
       result = (result * 10) + (fake_nbrs[a - 1] - '0');
   }

There already exists a standard power function in the maths library.

int pow(int base, int exponent)

Nice touch. Most people forget this part.

    if(exponent == 0)
    {
        return 1;
    }
\$\endgroup\$
2
\$\begingroup\$

OP's pow() inefficient

Rather than iterate n times, form the power by squaring and iterate log2(n) times.

// Shown without overflow protection for brevity.
int pow_i(int base, int expo) {
  assert(expo >= 0);  // Leave expo < 0 as TBD code

  int ipow = 1;
  while (expo > 0) {
    if (expo % 2) {
      ipow *= base;
    }
    base *= base;
    expo /= 2;
  }
  return ipow;
}

OP's pow() not needed

Alternate algorithm

sum = 0
while (isdigit((c = get_next_character)
  sum = sum * 10 + (c - '0')

Ten test cases not needed

'0' .. '9' are always consecutive integer values.

 // if(fake_nbr == '0' || fake_nbr == '1' || fake_nbr == '2' || fake_nbr == '3' || fake_nbr == '4' || fake_nbr == '5' || fake_nbr == '6' || fake_nbr == '7' || fake_nbr == '8' || fake_nbr == '9')
 if(fake_nbr => '0' && fake_nbr <= '9')

Or use isdgit() - be sure to avoid negative char values.

 if (isdigit( (unsigned char)fake_nbr )) 

No protection against overflow

int getint() should detect potential int overflow and return a well defined result.

A little documentation goes a long way

int getint(int pos_ze, int pos_sp, int qntty_of_incs) lacks description of functionality and parameters uses.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.