0

My function is part of a Roman Numeral to Arabic conversion function. It evaluates fine where there is a pair CM, a pair CD, where there is a single character C, and for all the combinations of CM, CD, M, D and C.

However, where the final character in a string is C (e.g. MCDCCC), the function crashes on the final 'C'. Ive put a stack of NSLog in there to trace the problem but I can't work out why its crashing on the final 'C'.

Any help welcome as Ive been trying to figure this out for a week. PS, Ive rewritten it as a switch function but Im getting the same kind of problem.

-(NSString *) decimalToRomanNumeral : (NSString*) romanNumeral
{
    NSLog(@"Roman Numeral       is %@", romanNumeral);

    int sumOfDecimals = 0;
    int stringLength = [romanNumeral length];
    NSLog(@"RomanNumeral Length is %i characters", stringLength);
    int arrayOfPrimitiveIntegers[stringLength];
    NSLog(@"Array Size          is %i spaces", stringLength);

    for (int c=0; c<[romanNumeral length]; c++)
    {
        NSLog(@"Character at       counter %i is %C", c, [romanNumeral characterAtIndex:c] );

        if ([romanNumeral characterAtIndex:c] == 'M')
        {
            NSLog(@"**********************************");
            NSLog(@"Within                 Evaluator M");
            NSLog(@"Counter                      is %i", c);
            arrayOfPrimitiveIntegers[c] = 1000;
            NSLog(@"Value in Array at position %i is %i", c, arrayOfPrimitiveIntegers[c] );
            sumOfDecimals = sumOfDecimals + arrayOfPrimitiveIntegers[c];
            NSLog(@"Sum of Decimals              is %i", sumOfDecimals);
            NSLog(@"**********************************");
        }
        else if (  ([romanNumeral length]>1 ) && (([romanNumeral characterAtIndex:c] == 'C') && ([romanNumeral characterAtIndex:c+1] == 'D'))  )
        {
            NSLog(@"**********************************");
            NSLog(@"Within                Evaluator CD");
            NSLog(@"Counter                      is %i", c);
            arrayOfPrimitiveIntegers[c] = -100;
            NSLog(@"Value in Array at position %i is %i", c, arrayOfPrimitiveIntegers[c] );
            sumOfDecimals = sumOfDecimals + arrayOfPrimitiveIntegers[c];
            NSLog(@"Sum of Decimals              is %i", sumOfDecimals);
            NSLog(@"**********************************");
        }
        else if (  ([romanNumeral length]>1 ) && (([romanNumeral characterAtIndex:c] == 'C') && ([romanNumeral characterAtIndex:c+1] == 'M'))  )
        {
            NSLog(@"**********************************");
            NSLog(@"Within                Evaluator CM");
            NSLog(@"Counter                      is %i", c);
            arrayOfPrimitiveIntegers[c] = -100;
            NSLog(@"Value in Array at position %i is %i", c, arrayOfPrimitiveIntegers[c] );
            sumOfDecimals = sumOfDecimals + arrayOfPrimitiveIntegers[c];
            NSLog(@"Sum of Decimals              is %i", sumOfDecimals);
            NSLog(@"**********************************");
        }
        else if ([romanNumeral characterAtIndex:c] == 'D')
        {
            NSLog(@"**********************************");
            NSLog(@"Within                 Evaluator D");
            NSLog(@"Counter                      is %i", c);
            arrayOfPrimitiveIntegers[c] = 500;
            NSLog(@"Value in Array at position %i is %i", c, arrayOfPrimitiveIntegers[c] );
            sumOfDecimals = sumOfDecimals + arrayOfPrimitiveIntegers[c];
            NSLog(@"Sum of Decimals              is %i", sumOfDecimals);
            NSLog(@"**********************************");
        }
        else if  (([romanNumeral length]==1 ) &&   ([romanNumeral characterAtIndex:c] == 'C'))
        {
            NSLog(@"**********************************");
            NSLog(@"Within                 Evaluator C");
            NSLog(@"Counter                      is %i", c);
            arrayOfPrimitiveIntegers[c] = 100;
            NSLog(@"Value in Array at position %i is %i", c, arrayOfPrimitiveIntegers[c] );
            sumOfDecimals = sumOfDecimals + arrayOfPrimitiveIntegers[c];
            NSLog(@"Sum of Decimals              is %i", sumOfDecimals);
            NSLog(@"**********************************");
        }        
        else if ([romanNumeral characterAtIndex:c] == 'C')
        {
            NSLog(@"**********************************");
            NSLog(@"Within               Evaluator C>1");
            NSLog(@"Counter                      is %i", c);
            arrayOfPrimitiveIntegers[c] = 100;
            NSLog(@"Value in Array at position %i is %i", c, arrayOfPrimitiveIntegers[c] );
            sumOfDecimals = sumOfDecimals + arrayOfPrimitiveIntegers[c];
            NSLog(@"Sum of Decimals              is %i", sumOfDecimals);
            NSLog(@"**********************************");
        }
    }
    NSString * numberString = [[NSString alloc]init];
    //numberString = [NSString stringWithFormat:@"%d", decimalNumber];
    return numberString;
}
@end
Filburt
  • 17,626
  • 12
  • 64
  • 115
MiltsInit
  • 153
  • 7
  • 1
    What's the error message? – Larme Apr 24 '14 at 21:01
  • Yes - NSRangeException:Full text is *** Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFString characterAtIndex:]: Range or index out of bounds' – MiltsInit Apr 24 '14 at 21:30
  • Ive understood that the evaluation conditions will evaluate the first condition e.g.([romanNumeral length]>1 ) and if that true, proceed to the next, otherwise exit if the condition is false. – MiltsInit Apr 24 '14 at 21:35

1 Answers1

1

romanNumeral characterAtIndex:c+1 -- this would seem to to be out of bounds on the final loop iteration.

You getting an NSRangeException?

stevesliva
  • 5,351
  • 1
  • 16
  • 39
  • Yes NSRangeExcpetion. However, it evaluates fine for CD and CM (i.e. where I use [romanNumeral characterAtIndex:c+1] – MiltsInit Apr 24 '14 at 21:32
  • Short-circuit evaluation means that the c+1 indices are going to be queried only when the character at index c is 'C' so your failure case of checking index c+1 requires that index c contain a 'C'. CD and CM don't meet those criteria – stevesliva Apr 24 '14 at 21:37
  • To put it another way, you're OOB when at index length-1 there is a 'C' and you check index length for an 'M' or a 'D' ... CD and CM do not have a 'C' at index length-1, so the `characterAtIndex:c+1` isn't checked. – stevesliva Apr 24 '14 at 21:56
  • thanks Steve. When I enter CCCC or CCC or CCCCCC etc, it crashes on the final 'C', but for the earlier 'C' characters it iterates through the loop fine. this suggests to me that it's bypassing case CM (as it should) and CD (as it should) and C (as a single character, as it should), so it's seems to be getting into the right evaluation loop but crashing at the last 'C', whatever the string length. – MiltsInit Apr 24 '14 at 22:00
  • Right. Because if the final char is a 'C' it's asking for `characterAtIndex:length` because c+1==length and that generates your NSRangeException – stevesliva Apr 24 '14 at 22:36
  • Hi Steve. Im really grateful for your help on this. Its helped me understand that the basic idiom was faulty and that Id never get it to work, so Ive gone back to using a switch statement with a final if else checking if the value of the current character is larger than the previous, then subtracting twice the value of the previous character from the total. Thanks again. – MiltsInit Apr 25 '14 at 21:58
  • That probably expands to the larger full set of IVXLCDM. I was also wondering whether parsing the roman string backwards from the final char would make sense. – stevesliva Apr 26 '14 at 00:20
  • yes you're right. I just put up part of the code to highlight the issue. following your feedback it made me realise that the design idiom wouldn't work so I ditched it and went to a switch statement which works fine – MiltsInit Apr 28 '14 at 18:51