How to multiply numbers in serial monitor?

Hellloooo
I have a question! I want (when I write number on the serial monitor) the program to multiply the numbers. This is my code but I dont know what went wrong. Could someone help me please? :slight_smile:

String number;
String message;
int total= 0;

void setup() {
int i;
Serial.begin (9600);
number = random (1, 500);

for (i=0; i <0; ++i)
total *=number [i];
}

void loop() {
if (Serial.available () >0)
{
char received = Serial.read ();

if (received == '\n')
{
Serial.println (total);
}
}}

oops for (i=0; i <0; ++i) total *=number[i];

not sure I really understood what you want to do. Your code does not do much in the loop...

J-M-L:
oops

for (i=0; i <0; ++i) total *=number[i];

not sure I really understood what you want to do. Your code does not do much in the loop...

I want for example when I send 3 * 3 the monitor to answer the math

I dont think I need to write in the loop, do I?

Well you need to parse what’s coming on that line. That means you need to decide if you support only * or if I can use +,-,/ if I can use () etc

The first thing to do is to correctly read in the request

I would suggest to study Serial Input Basics to handle this

Then you need parsing. There is a strong grammar defining operator precedence for example it is customary to agree that 4+58 is 44 and not 160, meaning it’s interpreted as 4+( 58 ). So you can’t read numbers and operations as they come, you need to look ahead. A tree structure can be useful

The program flow is completely wrong. You read in a value in loop() then you do nothing with it. Your attempt at calculation is all in setup() which only runs once BEFORE you have read any thing from Serial in loop().

And what does the random(1,500) have to do with what you say the program should do?

Steve

@Jml thank you for the tips!

@Steve: I wanted the program to know the numbers 1-500, so thats why (1, 500). I didnt write it in loop, because I dont want it to repeat itself (I thought that what loop is for)

I didnt write it in loop, because I dont want it to repeat itself

well you want to repeat the maths every time you have something to calculate - so the loop would be the right place to do this.

you need to start by clarifying what you expect from the Serial monitor input, for example your use case could be:

  • user types number1 and validates
  • user types number2 and validates
    => you print the result of number1 * number2

or it could be

  • user types number1 operation number2 validates
    => you detect the numbers, detect the operation and print the result

or it could be any arbitrary operation on the line, something like
2 + (7*3) - 5 * (12 + (27/12 - 6)3248 / (3 + 1)) / 22
and then it's a bit more complicated

Try something like this

// https://forum.arduino.cc/?topic=733469#msg4935218
// modified from
// readStringUntil_nonBlocking.ino
// Reads chars into a String until newline '\n'
// https://www.forward.com.au/pfod/ArduinoProgramming/SoftwareSolutions/index.html
// Pros: Simple. Non-Blocking
// Cons: Does not return until the until_c char is found. i.e. no timeout or length limit

String input;
bool haveFirstNum = false;
int num1;
int num2;

void setup() {
  Serial.begin(9600);
  for (int i = 10; i > 0; i--) {
    Serial.print(' '); Serial.print(i);
    delay(500);
  }
  Serial.println();
  Serial.println(F("modified from readStringUntil_nonBlocking.ino"));
  Serial.println(F(" Enter 2 nums, one per line (terminated by newline)"));
  input.reserve(20); // expected line size
}

// read Serial until until_c char found, returns true when found else false
// non-blocking, until_c is returned as last char in String, updates input String with chars read
bool readStringUntil(String& input, char until_c) {
  while (Serial.available()) {
    char c = Serial.read();
    input += c;
    if (c == until_c) {
      return true;
    }
  }
  return false;
}


void loop() {
  if (readStringUntil(input, '\n')) { // read until find newline
    Serial.print(F(" got a line of input '")); Serial.print(input); Serial.println("'");
    // parse to int
    input.trim();
    int inputNum = input.toInt(); // a very poor conversion method
    if (input == String(inputNum)) { // so check the result
      // have valid int
      Serial.println(inputNum);
      if (!haveFirstNum) {
        num1 = inputNum;
        haveFirstNum = true;
      } else {
        num2 = inputNum;
        Serial.print(F("Ans:")); Serial.println(num1*num2);
        haveFirstNum = false;
      }
    } else {
        Serial.print(F("Number :")); Serial.print(input); Serial.println(F(" is not a valid int"));
    }
    input = ""; // clear after processing for next line
  }
}

My SafeString library has a more powerful SafeStringReader for reading/parsing inputs and much more robust text to number conversion methods.

int number;
int total = 0;


void setup()
{
  Serial.begin (9600);
  number = random (1, 500);
}


void loop()
{
  if (Serial.available () > 0)
  {
    total = number * Serial.parseInt();
    Serial.println(total);
  }
}

Try these inputs with the two posted sample codes and see what you get as answers
5.6
5a
abc

123456789012345

@drmpf

C and C++ standard cString and String functions have long accepted that 00042 is a valid decimal input for an integer and its value should be 42 or trying to parse an integer from "0042abc" should also return 42 (and if the function is smart tells you there are trailing characters).

Why are you redefining what has been common practice (for almost half a century in the case of cString)?

String S = "0042abc";
char cS[] = "0042abc";

void setup() {
  Serial.begin(115200);
  Serial.println(S.toInt());
  Serial.println(atoi(cS));
}

void loop() {}

The rationale for stoping the parsing at the first "non compatible" character is to support inline parsing of simple expressions without having to tokenise for example.

I'm not saying it's robust, I'm just saying this is the commonly agreed behavior and thus if you want to make this robust, don't do it by removing the expected outcome (applies to your sample code and your library if I remember correctly)

Not sure what you are objecting to here.
I am just applying stricter validation to the user's input.
My expected outcome for an input of "44abc" is an Error Message to the user.

If you want your program to accept "44abc" as a valid integer from your user you can use atoi() or a bare Arduino Strings toInt()

I don't want my programs to accept "44abc" or "123456789012345" as valid integers
It has never been common practice for a user input of "42abc" to be accepted as a valid integer by any program.

Neither S.toInt() nor atoi(cS) indicate to the program that there are any "non compatible" chars following.
So pretty useless on their own for handling user input or parsing integer fields.

C recognises this deficency and provides a 'better' function strtol()

if the function is smart tells you there are trailing characters

Yes SafeString toInt() is a smart function that function wraps up strtol() and handles the pointers and checks for "non compatible" chars following and alerts the user by returning false.

As for 00042, yes that should be valid and it is a valid integer under safeString's toInt().
However the simple Arduino String fix I implemented in the code in #7 fails for this case :frowning:
If the OP wants a really robust validation of the input the he should use SafeString toInt()

Using atoi() or a bare Arduino String toInt() statement to convert an integer input is just sloppy in my book since simple more robust alternatives are available
i.e. If input is an Arduino String

    input.trim();
    int inputNum = input.toInt(); // a very poor conversion method
    if (input == String(inputNum)) { // so check the result
      // have valid int
    } else {
      // input not a valid  int
    }

OR if input is a SafeString

    // trim() not need as SafeString toInt() allows for trailing white space
    int inputNum
    if (input.toInt(inputNum) {
      // have valid int
    } else {
      // input not a valid  int
    }

Yes SafeString toInt() is a smart function that function wraps up strtol() and handles the pointers and checks for "non compatible" chars following and alerts the user by returning false.

that's my point.

I'm just saying I do not find smart at all to not handle toInt() in your class in the same way integer parsing has been done for ever elsewhere, whether its String.toInt(), atoi() or the better strtol(). This is breaking well known conventions and expectations. May be you could return false but still provide what you decoded...

With strtol() you still get 42 with this input "0042abc"

char cS[] = "0042abc";
void setup() {
  Serial.begin(115200);
  Serial.println(strtol(cS, NULL, 10));
}
void loop() {}

(and extra information if you wanted to keep parsing or do some more robust stuff)

May be you could return false but still provide what you decoded...

Yes that is a possibility.

Do you have any example sketches where calling String("5abc").toInt() or String("5 3").toInt()
and returning 5 makes sense to the overall program and is a useful thing to do, other then just hiding a data error.

Any parsing that would not require tokenizing the input string because you know it’s well formed - like reading a number based CSV spreadsheet file or the output of a serial device

The goal is to involve as little substring or remove or whatever string operations as possible and handle the buffer in place like you would do with cString in the first place.

That would be true if you are using strtol() to parse a number from a char* and then saving the endPtr to continue other parsing.
Then returning 5 make sense, but that use case is not possible with atoi(), String toInt() or SafeString toInt()

I don't want my programs to accept "44abc" or "123456789012345" as valid integers
It has never been common practice for a user input of "42abc" to be accepted as a valid integer by any program.

Well, strtol() has been converting hex numbers such as 42abc since probably before 1970. Concerning validation, hierarchical validation is best, working on a string with well defined endpoints. The proper approach is programmatic, since validation needs vary, but since substrings may be context dependent, the validation could also require parsing. In this case, you wish to at least differentiate the 42 and the "abc" and, in your definition, flag the latter as an error. That is all fine, and there is no reason why it can't be implemented using the standard functions that were designed for that purpose, but a scheme is required to guide the parsing. Perhaps the discussion is about how to do that. But it's not a new topic.

hex numbers such as 42abc

Common practice is that base 10 is expected unless otherwise noted, hence my programs don't expect hex input when just asking for an integer.
If I was asking for a memory address that would be a special case and I would advise the user of the valid/expected input format. SafeString has a hexToLong() method to handle numbers in hex format.

validation could also require parsing

I agree entirely. SafeString toInt() / toLong() / hexToLong() / octToLong() / binToLong() / toFloat() / toDouble() are expected to be used at the bottom level after the higher level parsing has extracted a field that is expected to be a number and has identified the expected format for that field.

Would require to be able yo extract at a given index

That’s one more proof of the efficiency of cStrings

one more proof of the efficiency of cStrings

No argument about the efficiency of c-strings. But you have to be very careful when you program them and the resulting program is fragile. Not recommended. The Arduino Language Reference documents Strings for text manipulation for ease of use and reliability of the the resulting program.