Reputation: 15
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
Reputation: 21249
Your method signature is ...
- (void)testingmethod:(int)y
... which says this:
void
),testingmethod
,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
),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
Reputation: 24041
there would be two possible ways here for you to do what you want to achieve:
- (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];
- (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