Home > Software design >  Array index out of bounds error even though the indices are within the array length
Array index out of bounds error even though the indices are within the array length

Time:06-30

I was trying to write a java program where every digit of an input integer is printed in words for example: 123 is "one two three". I wrote the following program that takes an integer value then converts it into a string. I then iterated over the characters of the string and converted them to integer values which I later used as indices for the array. But it is showing array index out of bounds error.

Index 49 out of bounds for length 10

    import java.util.*;

public class DigitsAsWords {
    static void Print_Digits(int N){
        String arr[] = {"zero","one", "two", "three", "four","five", "six", "seven", "eight", "nine"};
        String st = Integer.toString(N);
        System.out.println(st);
        char s;
        int a;
        for (int i=0; i<st.length(); i  ){
            s = st.charAt(i);
            a = Integer.valueOf(s);
            System.out.print(arr[a] " ");
        }
    }
    public static void main (String args[]){
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        Print_Digits(a);
    }
}

CodePudding user response:

This is the place your code is failing at:

a = Integer.valueOf(s);

Instead of converting '1' to 1 as you were expecting, it converts '1' into the ascii equivalent, 49.

To avoid this:

a = Character.getNumericValue(s);

This will convert '1' to 1, and so on.

CodePudding user response:

Here's the problem:

There are two Integer.valueOf() methods:

  1. Integer.valueOf(int)

  2. Integer.valueOf(String)

When you call valueOf on a character such as '5', the Integer.valueOf(int) is called. The '5' is casted to int which is 53 which is the ascii code for the character '5'.

Your code:

for (int i=0; i<st.length(); i  ){
  s = st.charAt(i);
  a = Integer.valueOf(s);  <=== a is the ascii code
  System.out.print(arr[a] " ");  <==will cause index out of bound.
}

Possible fixes:

  1. compute the digit of the character (preferred). For example: '5' - '0' = 5.
  2. convert the character to a string.
for (int i=0; i<st.length(); i  ){
  s = st.charAt(i);
  a = Integer.valueOf(s-'0'); 
  System.out.print(arr[a] " ");  
}

CodePudding user response:

Change:

a = Integer.valueOf(s);

To:

a = s - '0';

Subtracting '0' returns the int value of a digit character.

CodePudding user response:

you are getting an error here

 a = Integer.valueOf(s);

it converts char to their respective Unicode value. Instead of this code, you can use the below function.

Character.getNumericValue();

Refer this link -> Char to Int

You can also do

String c=String.valueOf(s);  
int foo = Integer.parseInt(c);

Refer -> How do I convert a String to an int in Java?

CodePudding user response:

Firstly, lean about the primitive data types in Java.

If your background is JavaScript, which has no char type, you might have been thinking that char is a "kind of" string, but it's not.

char - is a 16-bit numeric primitive data type, which has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535) which was meant to represent Unicode-characters. But in the earlier days of Java the Unicode standard has been changed, and char type appeared to be broken, to fix this code points were introduced in the language.

In this statement a = Integer.valueOf(s); character s is being promoted into int type and method valueOf() creates an unnecessary instance of Integer which is being immediately thrown away, and you end up with a having a value in the range from 48 (0) to 57 (9), which is greater than array's length. Therefore, you're getting a justifiable ArrayIndexOutOfBoundsException.

Also, there are few more issues.

Compiler will not complain that you're creating a new array for each method call but this approach is wrong, the string array should be static, i.e. it should reside on a class level:

public static final String[] DIGITS = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

Another important issue which might seem unimportant is that the names you're using both uninformative (like arr) and they violate the Java naming convention (like Print_Digits).

Also, C-style of array declarationString arr[] is not considered to be a good practice in Java because it mixes the data type and the variable name.

And here is a couple of solutions for this problem.

The first one is somewhat close to code provided by OP:

public static void printDigits1(int num) {
    String numericString = String.valueOf(num);
    
    for (int i = 0; i < numericString.length(); i  ) {
        String digit = DIGITS[Character.getNumericValue(numericString.charAt(i))];
        System.out.print(digit   " ");
    }
}

We can also address this problem without using strings at all:

public static void printDigits2(int num) {
    if (num == 0) {
        System.out.println(DIGITS[0]);
        return;
    }
    
    int len = (int) Math.ceil(Math.log10(num));
    String[] result = new String[len];

    for (int cur = num, i = len - 1; cur > 0; cur /= 10, i--) {
        result[i] = DIGITS[cur % 10];
    }

    System.out.println(String.join(" ", result));
}

And here's a concise solution using Stream API:

public static void printDigits3(int num) {
    
    String result = String.valueOf(num).chars()
        .map(Character::getNumericValue)
        .mapToObj(i -> DIGITS[i])
        .collect(Collectors.joining(" "));

    System.out.println(result);
}

main()

public static void main(String[] args) {
    printDigits1(59);
    System.out.println();
    printDigits2(128);
    printDigits3(789);
}

Output:

five nine 
one two eight
seven eight nine

A link to Online Demo

  • Related