Array Out Of Bounds Error - but why?

Former Member
Former Member

Hi,

I'm currently struggling with this error message and I don't know what is the problem and how to get rid of it.
The code causing the error is simple number formatting function, number is input parameter, gAccum5[] is 5-element global byte array, and function returns number of valid digit values stored in the gAccum5[].
The gAccum5[] is global variable defined just after "using" keywords (among others global vars) in the module which also contains formatting function:
var gAccum5 = [0, 0, 0, 0, 0]b;

The formatting function formatNumber():

    // -----------------------------------------------------------------------
    // Write number to byte array
    // Number is limited to +/-9999
    // Return value is number of written digit values (0, 1,...)
    // -----------------------------------------------------------------------
    function formatNumber(n) {
        // if n is float, round it first
        var nr = Math.round(n).toNumber();
        // gAccum5 index
        var idx = 0;
        // Sign for negative number
        if (nr < 0) {
            gAccum5[0] = 45; // '-'
            nr = -nr;
            idx = 1;
        }
        if (nr >= 10000) {
            return 0;
        }
        var flag = 0;
        var div = 1000;
        do {
            if ((nr >= div) or (div == 1) or (flag)) {
                System.println("Digit: " + nr + "  " + idx + "  " + div + "  " + flag + "   " + nr / div);
                gAccum5[idx] = nr / div;
                idx += 1;                      // <------------ This is line 1200
                flag = 1;
                nr %= div;
            }
            div /= 10;
        } while (div);
        return idx;
    }

And this is the end of simulator output (Connect IQ SDK 3.1.5):

...
AV:weather: {pr=>1028, sp=>1, ic=>7, tm=>13.980000, st=>200, hm=>58, dg=>null}
Code: 7

Digit: 14  0  10  0   1
Digit: 4  1  1  1   4
Digit: 1  0  1  0   1
Digit: 1028  0  1000  0   1
Digit: 28  1  100  1   0
Digit: 28  2  10  1   2
Digit: 8  3  1  1   8

Error: Array Out Of Bounds Error
Details: Failed invoking <symbol>
Stack:
  - formatNumber() at C:\Users\mates\Documents\SDK_Manager\connectiq-sdk-win-3.0.8-2019-1-23-8f00e4f\samples\Analog\source\AnalogView.mc:1200 0x10003575
  - updateWeatherFields() at C:\Users\mates\Documents\SDK_Manager\connectiq-sdk-win-3.0.8-2019-1-23-8f00e4f\samples\Analog\source\AnalogView.mc:906 0x10002756
  - onUpdate() at C:\Users\mates\Documents\SDK_Manager\connectiq-sdk-win-3.0.8-2019-1-23-8f00e4f\samples\Analog\source\AnalogView.mc:653 0x10001b5b

Notes:

1. The error occurrence is random, sometimes it goes through function, sometimes not - it probably depends on the number passed as function parameter.

2. The AV:weather: line in error listing is debug println of dictionary get from the background process printed just before I call sequence of formatNumber().

3. The Code: 7 is also debug println before sequence of formatNumber() is called.

4. First call of formatNumber() is with 14 as an input parameter (source AV:weather:tm rounded to 14) -> the function prints first two lines with Digit: label.

5. The second call of formatNumber() is with 1 as an input parameter (source AV:weather:sp = 1) -> the function printlns third line with Digit: label.

6. The third call of formatNumber() is with 1028 as an input parameter (source AV:weather:pr = 1028) -> the function printlns the fourth to seventh  line with Digit: label.

I really do not have any idea what is wrong, the idx is always in the gAccum5[] limits.

What does the "Details: Failed invoking <symbol>" mean?

Thanks for any help.

  • If I take your formatNumber and use this to run it, the problem I see is that the null causes a problem (it can't be rounded or converted to a number.)

     

            
            var d=[1028, 1, 7, 13.980000, 200, 58, null];       
        	for(var i=0;i<d.size();i++) {
    			System.println("try "+d[i]);
    			System.println("ret="+formatNumber(d[i])); 
    			System.println("ba="+gAccum5);   	
        	}

    I suspect your problem is how/when you are calling formatNumber() or what you do with gAccm5 outside of the code you posted

    You can catch the null with this as the first line in formatNumber()

    if(n==null) {return 0;}

    Try adding this to the beginning of formatNumber() It may help you see what's going on

    System.println("ba="+gAccum5);

  • Former Member
    0 Former Member over 5 years ago in reply to jim_m_58

    Solved - thanks jim_m_58 for help.
    Error reason: I know about null problem but I filter out null value outside the function just before calling (because I need different action if the parameter is null). But the idea "what you do with gAccum5 outside the code" was the hint. In upper level code, for some specific parameter value, I set gAccum5 = ['-','-','-',']; instead of formatNumber() calling which of course shortened the array. Agrrr ... stupid mistake, some mist covered my eyes yesterday. Thanks again.

  • To protect in the future, you could have the byte array local to formatNumber and return it.

    So in formatNumber,

     var ba=[0,0,0,0,0]b;

    then

    return [ba,idx];

    and in the calling code, 

    var fmt=formatNumber(n);

    gAccum5=fmt[0];

    size=fmt[1];

    or something like this

  • I'm kind of wondering what you are using this for, as if you just want to format a number for output, there's an easier way

    Say you have

    var num=123;

    with num.format("%d") you get a string, and if you want a fixed size, num.format("%08d")

    based on the string you pass to format(),you can do a number of things.  Like with a float, display a single decimal place

    var flt=1.2345;

    flt.format("%0.1f")

    and you get "1.2" 

  • Former Member
    0 Former Member over 5 years ago in reply to jim_m_58

    I have reopened the code after several months and now I'm wondering too.
    If I look at the code in detail, I wanted to convert numbers (always integer between -9999 to 9999) to some array of digits code (I used byte array, I do not know why), then add/insert some specific characters code (degree character to signalize temperature, arrow character to signalize wind speed/direction etc), and than I call function which takes element-by-element from array and draw corresponding bitmap to screen (I do not use font due to aliasing required which is not possible in used dc).

    So, if it is possible to read/write string elements by index (str[3]), I can move from byte arrays to strings.

  • Ok, with a custom font, they can be ani-aliased:

    <font id="large" antialias="true"  filename="lai65.fnt"/>

    With fonts, you can use setColor() and not need bitmaps for different colors

    Say you have

    var string= "12345";

    you can make it a character array with

    var ca=string.toCharArray()

    and access a character at a time

    The way I do things like a degree symbol is:

    var degree="°"; //utf-8, b0 hex, 176 dec

    and then just display

    temperature+degree (using dc.drawText())

  • Former Member
    0 Former Member over 5 years ago in reply to jim_m_58

    1. It sounds good that the toCharArray() can enable access character-by-character so I can use .format instead of my formatting function. The question is the memory requirement for .format code - I'm several kB under memory limit. But I can try it and I will see.

    2. The problem with drawText is that I use buffering (BufferedBitmap) due to the second hand (it is a watch-face what I'm writing). In this case the anti-aliasing is not supported (or do I miss something?)

    Thanks.