Shafaruddin Sahdion
Shafaruddin Sahdion

Reputation: 15

Returning back parameter values

I am trying to update c01 parameter value to a new one by calling following method. However it still returns 0.

[self testingmethod:c01];

The method body is:

- (void)testingmethod:(int)y {
  int x;
  x = arc4random() % 399 + 1;
  while (x == y || x == 0){
    x = arc4random() % 399 + 1;
  }
  y = x;
  return y; // is this right?
}

Can someone help me to solve this?

Upvotes: 0

Views: 70

Answers (2)

zrzka
zrzka

Reputation: 21249

Your method signature is ...

- (void)testingmethod:(int)y

... which says this:

  • there's no return value (void),
  • name is testingmethod,
  • it accepts one argument named y of type int.

If you would like to return an value, you have to change your method signature to ..

- (int)testingmethod:(int)y

... and method body to ...

- (int)testingmethod:(int)y {
  int x;
  x = arc4random()%400 + 1;
  while(x == y || x == 0){
    x = arc4random()%400 + 1;
  }
  return x;
}

Also do not use arc4random() with %. There's arc4random_uniform:

u_int32_t arc4random_uniform(u_int32_t upper_bound);

arc4random_uniform() will return a uniformly distributed random number less than upper_bound. arc4random_uniform() is recommended over constructions like ``arc4random() % upper_bound'' as it avoids "modulo bias" when the upper bound is not a power of two.

It leads to this code ...

- (int)testingmethod:(int)y {
  int x;
  x = arc4random_uniform(400) + 1;
  while(x == y || x == 0){
    x = arc4random_uniform(400) + 1;
  }
  return x;
}

... which can be used in this way:

c01 = [self testingmethod:c01];

This can be further optimized to ...

- (int)testingmethod:(int)y {
  int x;
  do {
    x = arc4random_uniform(400) + 1;
  } while(x == y);
  return x;
}

... because:

  • u_int32_t is unsigned, arc4random... returns positive numbers (>= 0),
  • you're adding 1 to this number, it can never be 0, useless to check for 0,
  • do while is better, because there's just one line where you generate numbers and generally, do while is used over while in cases where you need to execute some statements before you compare value.

Why c01 value is not modified when you do modify y in original example? Objective-C is superset of C and everything what does C, does Objective-C as well.

Function parameters are always passed by value. Pass-by-reference is simulated in C by explicitly passing pointer values.

Do you want to simulate references, so, you can change value of c01? Use pointers ...

- (void)testingmethod:(int *)y {
  if ( y == nil ) { return; }
  int x;
  do {
    x = arc4random_uniform(400) + 1;
  } while(x == *y);
  *y = x;
}

Usage:

[self testingmethod:&c01];

Example of required number generator based on comments. Not optimized at all, for readability and proper understanding sake.

@interface RandomNumberGenerator: NSObject

- (NSArray *)generatorRandomNumbersWithLowerBound:(NSUInteger)lowerBound
                                       upperBound:(NSUInteger)upperBound
                                            count:(NSUInteger)count;

@end

@implementation RandomNumberGenerator

- (NSArray *)generatorRandomNumbersWithLowerBound:(NSUInteger)lowerBound
                                       upperBound:(NSUInteger)upperBound
                                            count:(NSUInteger)count {

  if ( lowerBound > upperBound ) {
    // lowerBound can't be greater than upperBound, error
    return nil;
  }

  if ( count == 0 ) {
    // number of required numbers is not > 0? error
    return nil;
  }

  if ( lowerBound == upperBound ) {
    // bounds equals
    if ( count == 1 ) {
      // equal bounds, just return one number
      return @[ @(lowerBound) ];
    } else {
      // equal bounds, but required more than one number, error
      return nil;
    }
  }

  if ( count > upperBound - lowerBound + 1 ) {
    // number of required numbers is greater than available numbers in given bounds, error
    return nil;
  }

  // arc4random_uniform generates numbers from 0, just calculate right upper bound
  NSUInteger arc4randomUpperBound = upperBound - lowerBound + 1;
  NSUInteger arc4randomAddition = lowerBound;

  // generated numbers so far
  NSMutableArray *numbers = [@[] mutableCopy];

  // loop until all required numbers are generated
  while ( numbers.count < count ) {
    NSInteger x;
    do {
      x = arc4random_uniform((u_int32_t)arc4randomUpperBound) + arc4randomAddition;
      // loop till generated number is not in already generated numbers
    } while ( [numbers indexOfObject:@(x)] != NSNotFound );
    [numbers addObject:@(x)];
  }

  return numbers;
}

@end

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    RandomNumberGenerator *generator = [[RandomNumberGenerator alloc] init];

    NSLog( @"1-400, 10 numbers: %@",
      [generator generatorRandomNumbersWithLowerBound:1 upperBound:400 count:10]);
    NSLog( @"0-9, 10 numbers: %@",
      [generator generatorRandomNumbersWithLowerBound:0 upperBound:9 count:10]);
  }
  return 0;
}

Upvotes: 0

holex
holex

Reputation: 24041

there would be two possible ways here for you to do what you want to achieve:

1st idea

- (int)testingMethod:(int)y {
    int x;
    x = arc4random() % 399 + 1;
    while (x == y || x == 0){
        x = arc4random() % 399 + 1;
    }
    y = x;
    return y;
}

then

c01 = [self testingMethod:c01];

2nd idea

- (void)testingMethod:(int *)y {
    if (y) {
        int x;
        x = arc4random() % 399 + 1;
        while (x == *y || x == 0){
            x = arc4random() % 399 + 1;
        }
        *y = x;
    }
}

then

[self testingMethod:&c01];

Upvotes: 1

Related Questions