-1

Okay, so I'm going to start with showing the working version of my while and if-check loop:

  int letterIndex = 0;
  int rows = sizeof letterArr / sizeof letterArr[0];

  while(letterIndex < rows) {
    if(letter == letterArr[letterIndex][0]) {
      break;
    } else {
      letterIndex++;
    }
  }

...and then I obviously do some stuff when the loop's condition is no longer true. Cool.

But at first I was trying to break the loop with this condition:

  int letterIndex = 0;
  int rows = sizeof letterArr / sizeof letterArr[0];

  while( (letter != letterArr[letterIndex][0]) && (letterIndex < rows) ) {
    letterIndex++;
  }

...and I'd just end up in a never ending loop. The second condition letterIndex < rows never changed its evaluation to false.

And then when I tried this next configuraiton:

  int letterIndex = 0;
  int rows = sizeof letterArr / sizeof letterArr[0];

  while(letter != letterArr[letterIndex][0]) {
    if(letterIndex < rows) {
      break;
    } else {
      letterIndex++;
    }
  }

...I was super confused with what was going on. For some reason I switched the condition statements so letterIndex < rows broke the while loop but that just makes this more confusing for me. In this context shouldn't letterIndex < rows and letter == letterToArr[letterIndex][0] be interchangeable?

I printed out a ton of debugging messaging around the variable's values and from the outputted statements the other two versions on this code should be working like I'd assume: when the letterIndex is more than the rows value then the statement evaluates to false.

I'm not sure if this is super helpful but I'm working on an Arduino Uno board and I'm more of a web developer. I've dabbled in C++ but I've never done anything professional with it so no doubt this is due to my lack of understanding/knowledge for either the Arduino architecture or C++. Possibly both.

  • 3
    [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) – 463035818_is_not_an_ai Apr 17 '23 at 07:53
  • 2
    Are you asking whether you can first access an array element and then check whether this element exists? – Daniel Langr Apr 17 '23 at 07:53
  • 1
    One question -- what's the reason for not simply using the first snippet, which obviously works? If the reason for why you attempted to write the other two code snippets is for optimization purposes, the compiler is smart enough to optimize the code already. – PaulMcKenzie Apr 17 '23 at 07:55
  • 1
    don't use `sizeof` to determine the size of an array. There is `std::size` which is less error prone, and imho the biggest benefit, it was made to be used for that – 463035818_is_not_an_ai Apr 17 '23 at 07:56
  • 1
    btw even without the out of bounds issue explained in the answer, the first two variants are not the same. Only if `letter == letterArr[letterIndex][0]` would be `true` for all iterations of the loop, the two are equivalent, but if thats the case you dont need that condition in the first place – 463035818_is_not_an_ai Apr 17 '23 at 07:58
  • 2
    This is a case of trying to over-engineer somthing that worked. The first code snippet is quite clear and concise to someone reading the code -- the outer loop will execute if the `letterIndex` is in-bounds. The other two snippets are obfuscations, IMO, which wound up doing things that were not expected. – PaulMcKenzie Apr 17 '23 at 08:02
  • @463035818_is_not_a_number Thanks for the link on debugging! But since I'm new to embedded systems and the like I'm unfamiliar with any robust step-through style debugging I'd normally use and thought print statements to the serial monitor would get me 80% of what I needed. **To address almost all the other comments:** yeah, I got it to work but I'm really looking to understand why. The answers I got were good and I learned some language specific stuff. Mission accomplished, everyone. Thank you. – romanchukenator Apr 17 '23 at 09:55

2 Answers2

2

This code

while( (letter != letterArr[letterIndex][0]) && (letterIndex < rows) ) {

has undefined behaviour because you check if letterIndex is less than rows after you use letterIndex to access the letterArr array. Because the check is afterwards you will end up making an out of bound access on your array and that leads to undefined behaviour. That said I'm a bit surprised it led to an infinite loop.

The correct code is

while( (letterIndex < rows) && (letter != letterArr[letterIndex][0]) ) {

Operator && is always evaluated left to right. And if the left hand side evaluates to false, the right hand side is not evaluated at all. This avoids the out of bounds array access that your version had. Similar rules apply to operator ||. This is known as short circuit evaluation.

john
  • 85,011
  • 4
  • 57
  • 81
  • Ah-hah. Okay. Thank you for that. Bad assumption on my part that I'd have a `nil` or `undefined` type or something along those lines returned. Learned that C arrays don't check bounds. Another SO answer went into a little more [detail](https://stackoverflow.com/a/1239977/3709029). – romanchukenator Apr 17 '23 at 09:46
  • @romanchukenator for c-arrays `arr[i]` is exactly equivalent to `*(arr+i)`, thats all – 463035818_is_not_an_ai Apr 17 '23 at 09:59
1

You are not allowed to access letterArr[letterIndex] when letterIndex is out of range. In the working version you don't because you first check the condition letterIndex < rows. In both versions that don't work you access letterArr[letterIndex] without checking first if letterIndex is a valid index resulting in Undefined Behavior.

bolov
  • 72,283
  • 15
  • 145
  • 224