Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
I get a warning which I cannot understand.

Given Fraction is a class, defined in "Fraction.h",

Code:
//
//  Fraction.h
//  Chap 7 Prgm 7.1

//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import <Foundation/Foundation.h>


@interface Fraction : NSObject {
	int numerator;
	int denominator;
}

@property int numerator, denominator;



/** class initialization **/

- initWith: (int)  n over: (int) d;

-(void) reduce;

/* modified accessor*/
-(void) setTo: (int) n over: (int) d;


/*utilities*/

-(double) convertToNum;


-(void) print;



@end

Code:
//
//  Fraction.m
//  Chap 7 Prgm 7.1

//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "Fraction.h"
#import "Comparison.h"


@implementation Fraction;

@synthesize denominator, numerator;



- initWith: (int)  n over: (int) d
{
	if ( ! ( self = [super init]))
		return nil;
	
	if (self)
		[self setTo: n over: d];
		
		return self;
	
}

-(double) convertToNum
{
	if (denominator != 0)
		return (double) numerator / denominator;
	else
		return 1.0;
}



/*********SPECIFIC TO EXERCISE 7-5 ***************

-(void) print 
{
	float f = 0.00;
	
	if ( (f = (float) numerator / denominator) > 1)
		
		NSLog(@"%i %i/%i", numerator/denominator, numerator % denominator, denominator);
	
	else
		
		NSLog(@"%i/%i ", numerator, denominator);
}



-(void) setTo: (int) n over: (int) d
{
	numerator = n;
	denominator = d;
}



/*
-(Fraction *) add: (Fraction *) f
{
	int resultNum, resultDenom;
	Fraction* result = [[Fraction alloc] init];
	
	resultNum = numerator * f.denominator + denominator * f.numerator;
	resultDenom = denominator * f.denominator;
	
	[result setTo: resultNum over: resultDenom];
	[result reduce];
	return result;
}
 
 */

-(void) reduce
{
	int u, v, temp;
	BOOL isNegativeNumerator = NO;
	BOOL isNegativeDenominator = NO;
	
	if ( numerator < 0)
	{
		isNegativeNumerator = YES;
		numerator = -numerator;
	}
	
	
	if ( denominator < 0)
	{
		isNegativeDenominator = YES;
		denominator = -denominator;
	}
	
	u = numerator;
	v = denominator;
	
	
	while (v != 0) {
		temp = u % v;
		u = v;
		v = temp;
	}
	
	
	
	numerator /= u;
	denominator /= u;
	
	
	
	if ( isNegativeNumerator == YES || isNegativeDenominator == YES)
		numerator = -numerator;
	
}

@end

Code:
#import "Fraction.h"
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	Fraction *fractArr[10], *fractPtr;
	fractPtr = fractArr;  /*warning: assignment from incompatible pointer type */

	Fraction *aFrac = [ [ Fraction alloc] initWith: 3 over: 4];
	Fraction *bFrac = [ [ Fraction alloc] initWith: 7 over: 8];
	
	fractArr[0] = aFrac;
	fractArr[1] = bFrac;
	
	[fractPtr print];
	fractPtr++;
	[fractPtr print];

	[aFrac release];
	[bFrac release];
    [pool drain];
    return 0;
}




Help would be appreciated.
Thanks
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
Have you tried making sure that your initWith: returns a Fraction?

-(Fraction *) initWith: (int) n over: (int) d;


I don't think that is the problem..but thanks. The issue has to do with assignment of a ptr to an array...I think.
 

kpua

macrumors 6502
Jul 25, 2006
294
0
fractArr is a Fraction ** since it is a pointer to an array.

fractPtr, is obviously only a Fraction *, hence the warning about incompatible types.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
fractArr is a Fraction ** since it is a pointer to an array.

fractPtr, is obviously only a Fraction *, hence the warning about incompatible types.

Bah... by the time i got this compiling in a Obj-C 1.0 environment i was beat to the punch. Fraction ** is the right type for fractPtr... you'll have to derference fracPtr before passing a message to the Fraction * it's pointing to.

-Lee
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
fractArr is a Fraction ** since it is a pointer to an array.

fractPtr, is obviously only a Fraction *, hence the warning about incompatible types.

Yes...I thought it was something like that.
So, this is what I am ****trying*** to do.
Declare an array that will hold Fraction objects. ??? Fraction *arr[IntConst];

Declare a ptr of type Fraction ??? *myFractPtr;

So, how do I then assign a ptr to point at the array that holds these objects. But, having said that, further in Kochan's text, he gives the example that once one has declared and assigned appropriately, then one could use the pointer to do something like this ( given print is a message understood by Fraction class) [myFractPtr print]...which is also a little confusing, as it implies that myFractPtr is de-referenced by the [ ] operator....hence all the confusion. :)
 

kpua

macrumors 6502
Jul 25, 2006
294
0
Why don't use just use NSArray?

Anywho...

This snippit should help you out:

Code:
Fraction *fracArr[10];
Fraction **fracPtr = fracArr;

// Fill array
*fracPtr = [[Fraction alloc] init...];

[(*fracPtr) someMethod];
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
Bah... by the time i got this compiling in a Obj-C 1.0 environment i was beat to the punch. Fraction ** is the right type for fractPtr... you'll have to derference fracPtr before passing a message to the Fraction * it's pointing to.

-Lee

Lee, you are correct...as always!!! :)

I just got it to work, but not quite sure why?

Code:
Fraction *fractArr[10], **fractPtr;
	fractPtr = fractArr;
	Fraction *aFrac = [ [ Fraction alloc] initWith: 3 over: 4];
	Fraction *bFrac = [ [ Fraction alloc] initWith: 7 over: 8];
	
	fractArr[0] = aFrac;
	fractArr[1] = bFrac;
	
	[*fractPtr print];
	fractPtr++;
	[*fractPtr print];


This does not match Kochan's example, so not sure if I am correct or not?
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Steve might need to chime in, then. i don't know how else to have this work without multiple assignments from the array, or indexing the array when passing the message, etc. And those certainly will not work using ++.

-Lee
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
Why don't use just use NSArray?

Just following along in Kochan's book...I don't think I would ever actually do this, but nice to understand how it works.

Anywho...

This snippit should help you out:

Code:
Fraction *fracArr[10];
Fraction **fracPtr = fracArr;

// Fill array
*fracPtr = [[Fraction alloc] init...];

[(*fracPtr) someMethod];


So, you declare a pointer to pointer to Fraction as the array is really an array of pointers to Fraction??
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
So, you declare a pointer to pointer to Fraction as the array is really an array of pointers to Fraction??

Yes. C-Style arrays are always just pointers to the base element of the array. The array in this case contains Fraction *s, so the array is just a Fraction ** pointing to the 0th element.

-Lee
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
Steve might need to chime in, then. i don't know how else to have this work without multiple assignments from the array, or indexing the array when passing the message, etc. And those certainly will not work using ++.

-Lee


Yes...that's the confusing part to me. I tried to get a simple [myPt print] to work but could not. The **only** way to get it to even compile was to dereference myPtr.
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
Yes. C-Style arrays are always just pointers to the base element of the array. The array in this case contains Fraction *s, so the array is just a Fraction ** pointing to the 0th element.

-Lee


Of course..I had forgotten. In this case, element 0 of the array is a pointer to a pointer to a Fraction object!!

Thank you all...I hope Steve can give his opinion.
 

skochan

macrumors regular
Apr 1, 2006
150
0
California
So, you declare a pointer to pointer to Fraction as the array is really an array of pointers to Fraction??

Yes. Recall from the end of the chapter that an "object" in Objective-C is really a pointer to a structure that contains the object's declared instance variables, as well as its inherited ones. So the fraction array you are setting up is an array of pointers. If you want to make a pointer to point to an element in the array, it would be declared as a pointer to a pointer, or as Fraction **

So to add two consecutive Fraction objects stored in an array pointed to by fractsPtr you would write

Code:
result = [*fractsPtr add: *(fractsPtr + 1)];

The declaration of fractsPtr and the print method call should also be corrected, as you have discovered.

This error has been there since the first edition (written about 5 years ago), and you are the first to discover this. It's a credit to your detailed study of the subject.

Cheers,

Steve Kochan
 

kalimba

macrumors regular
Jun 10, 2008
102
0
I haven't actually tried to compile this and I'm just wondering aloud here, but would this be a suitable fix to the problem:

Code:
#import "Fraction.h"
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	Fraction *fractArr[10], *fractPtr;
	fractPtr = fractArr[COLOR="Red"][0][/COLOR]; [COLOR="Red"]// make fractPtr point to the first Fraction * in the array[/COLOR]

	Fraction *aFrac = [ [ Fraction alloc] initWith: 3 over: 4];
	Fraction *bFrac = [ [ Fraction alloc] initWith: 7 over: 8];
	
	fractArr[0] = aFrac;
	fractArr[1] = bFrac;
	
	[fractPtr print];
	fractPtr++;
	[fractPtr print];

	[aFrac release];
	[bFrac release];
    [pool drain];
    return 0;
}
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,566
I haven't actually tried to compile this and I'm just wondering aloud here, but would this be a suitable fix to the problem:

It will go very badly wrong.

Maybe this helps you to clean up the confusion: If you compare Cocoa and Carbon, there are NSString* in Cocoa and CFStringRef in Carbon, and they are roughly the same thing. NSString* is officially a pointer, but you don't use it as a pointer, you just use it as a thing that somehow in unidentifiable ways refers to a string, just like a CFStringRef is a thing that somehow in unidentifiable ways refers to a string.

Add a line:

typedef Fraction* FractionRef;

and use FractionRef instead of Fraction*. Then things should suddenly become a lot, lot clearer. Once it is clear that way, change FractionRef back to Fraction* and do the translation in your head only.

And you never, ever perform pointer arithmetic on an NSObject*. It is always wrong. (CFStringRef is defined in a way that makes pointer arithmetic illegal).
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
I haven't actually tried to compile this

it crashes when you try and print.

Now I am no expert on pointers...and there are others that might want to chime in, but here is what I perceive as problems with the code you suggested.




Code:
#import "Fraction.h"
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	Fraction *fractArr[10], *fractPtr;

OK...So fractPtr is a ptr to a Fraction Object. Now, I am not sure, as I have not reached the end of the chapter, but I suspect the pointer value here is the address of the first element of the object...which is not really what you want.

Code:
fractPtr = fractArr[COLOR="Red"][0][/COLOR]; [COLOR="Red"]// make fractPtr point to the first Fraction * in the array[/COLOR]

As you say, point to the fraction object stored in the first element of the array

.....snip....

Code:
	[fractPtr print];
	fractPtr++;

Well, the first easy one is fractPtr++. I think the **intention** is to advance the pointer to the next element in the array, but I think what you are doing is advancing it in the object, which is not what you want.

As to why [fractPtr print] crashes with a sig error is more of a mystery to me. But...it certainly does crash. I am not sure what the diff is between dereferencing a ptr declared as Fraction **fptr and your method..perhaps others can chime in.
 

eddietr

macrumors 6502a
Oct 29, 2006
807
0
Virginia
As to why [fractPtr print] crashes with a sig error is more of a mystery to me. But...it certainly does crash. I am not sure what the diff is between dereferencing a ptr declared as Fraction **fptr and your method..perhaps others can chime in.

The reason it crashes is this:

Code:
fractPtr = fractArr[0];

So fractPtr is a copy of the contents of the first element of the array. The compiler allows this because the array is defined as an array of Fraction*, and fractPtr is declared as a Fraction*. So far so good.

But, the copy (of the "pointer") is made before fractArr[0] has anything meaningful in it. It isn't until later that fractArr[0] contains an actual pointer to a Fraction object.
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
The reason it crashes is this:


But, the copy (of the "pointer") is made before fractArr[0] has anything meaningful in it. It isn't until later that fractArr[0] contains an actual pointer to a Fraction object.

Of course!! Good point. If I do the initialization prior to the assignment, it **does** print the first fraction. But, the essence of the pointer is to parse the **array** so advancing the pointer as declared cannot be done???? Besides, this is the intention of the code, so, if he pointer is declared as it is, one cannot achieve the purpose set out.
Thanks for catching the cause of the crash...makes it more interesting to understand the overall effect.
 

kalimba

macrumors regular
Jun 10, 2008
102
0
It will go very badly wrong.
Eeep. Sorry for adding noise to the discussion. I was looking at the problem from the standpoint of eliminating the compiler warning, without looking at what effect it have on proper program execution. With the latter now in mind, would this work as expected?:

Code:
#import "Fraction.h"
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	Fraction *fractArr[10], *fractPtr;
	fractPtr = fractArr[COLOR="Red"][0][/COLOR]; // make fractPtr point to the first Fraction * in the array

	Fraction *aFrac = [ [ Fraction alloc] initWith: 3 over: 4];
	Fraction *bFrac = [ [ Fraction alloc] initWith: 7 over: 8];
	
	fractArr[0] = aFrac;
	fractArr[1] = bFrac;
	
	[[COLOR="Red"]*fractPtr[/COLOR] print];
	fractPtr++;
	[[COLOR="Red"]*fractPtr[/COLOR] print];

	[aFrac release];
	[bFrac release];
    [pool drain];
    return 0;
}
 

eddietr

macrumors 6502a
Oct 29, 2006
807
0
Virginia
But, the essence of the pointer is to parse the **array** so advancing the pointer as declared cannot be done???? Besides, this is the intention of the code, so, if he pointer is declared as it is, one cannot achieve the purpose set out.

Yes, you're right about that. It won't achieve the objective. As least as far as I understand what the objective was without having looked at the book yet. (I don't have the book)
 

eddietr

macrumors 6502a
Oct 29, 2006
807
0
Virginia
Eeep. Sorry for adding noise to the discussion. I was looking at the problem from the standpoint of eliminating the compiler warning, without looking at what effect it have on proper program execution. With the latter now in mind, would this work as expected?:

Code:
#import "Fraction.h"
int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	Fraction *fractArr[10], *fractPtr;
	fractPtr = fractArr[COLOR="Red"][0][/COLOR]; // make fractPtr point to the first Fraction * in the array

	Fraction *aFrac = [ [ Fraction alloc] initWith: 3 over: 4];
	Fraction *bFrac = [ [ Fraction alloc] initWith: 7 over: 8];
	
	fractArr[0] = aFrac;
	fractArr[1] = bFrac;
	
	[[COLOR="Red"]*fractPtr[/COLOR] print];
	fractPtr++;
	[[COLOR="Red"]*fractPtr[/COLOR] print];

	[aFrac release];
	[bFrac release];
    [pool drain];
    return 0;
}

Still a couple of issues, though.

fractPtr needs to be a pointer to the pointer, not just a copy of the Fraction* as you have it now. So you still want:

Code:
Fraction **fractPtr;

fractPtr = fractArr;

or alternatively:

Code:
fractPtr = &fractArr[0];

The point being you're not looking for the contents of fractArr[0], you're looking for the address of fractArr[0].
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,566
Eeep. Sorry for adding noise to the discussion. I was looking at the problem from the standpoint of eliminating the compiler warning, without looking at what effect it have on proper program execution. With the latter now in mind, would this work as expected?:

I took the liberty to add a typedef to make things clearer. A Fraction* refers to a single object that is allocated at some unknown location in memory.

Code:
#import "Fraction.h"
typedef Fraction* FractionRef;

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	FractionRef fractArr[10], FractionRef;
	fractPtr = fractArr[COLOR="Red"][0][/COLOR]; 
// doesn't make fractPtr point to the first FractionRef in the array. 
// fractPtr is supposed to _be_ a FractionRef.

	FractionRef  aFrac = [ [ Fraction alloc] initWith: 3 over: 4];
	FractionRef bFrac = [ [ Fraction alloc] initWith: 7 over: 8];
	
	fractArr[0] = aFrac;
	fractArr[1] = bFrac;
	
        // This is nonsense; you shouldn't dereference a FractionRef.
	[[COLOR="Red"]*fractPtr[/COLOR] print];
        // This is nonsense, you can't increment a FractionRef in a meaningful way
	fractPtr++;
        // This is nonsense; you shouldn't dereference a FractionRef.
	[[COLOR="Red"]*fractPtr[/COLOR] print];

	[aFrac release];
	[bFrac release];
    [pool drain];
    return 0;
}
 

eddietr

macrumors 6502a
Oct 29, 2006
807
0
Virginia
snip

Code:
snip..
        // This is nonsense; you shouldn't dereference a FractionRef.
	[[COLOR="Red"]*fractPtr[/COLOR] print];
        // This is nonsense, you can't increment a FractionRef in a meaningful way
	fractPtr++;
        // This is nonsense; you shouldn't dereference a FractionRef.
	[[COLOR="Red"]*fractPtr[/COLOR] print];

It might be useful if mdeh posted some background on what the assignment was. But I'm guessing the point of the assignment was to illustrate how you can move through the array using pointer arithmetic.

So if that was the point (mdeh correct me if I'm wrong), then fractPtr should be a Fraction**. And then you can use fractPtr++ to iterate through the array of Fraction*. And of course then [*fractPtr whatever] would be correct.
 

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
It might be useful if mdeh posted some background on what the assignment was. But I'm guessing the point of the assignment was to illustrate how you can move through the array using pointer arithmetic.

So if that was the point (mdeh correct me if I'm wrong), then fractPtr should be a Fraction**. And then you can use fractPtr++ to iterate through the array of Fraction*. And of course then [*fractPtr whatever] would be correct.


Well..it's not really an assignment (yet!!) but the purpose was to show how pointers can be used to iterate through an array ( as Steve's note indicates). From the text it was clear that the idea of fractPtr was to point to an **array** of fraction objects and **not** to the objects themselves. Besides, the real crux if one does not point to the array is how does one then iterate the array. Hope that helps.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.