Using simple arrays within objects

Discussion in 'Mac Programming' started by jctj, Feb 24, 2010.

  1. jctj macrumors newbie

    Joined:
    Feb 24, 2010
    #1
    I am trying to make objects that have simple C arrays in them. One is a straightforward array of integers, and another is an array of a structure. The values are 'correct' when the objects (simpleObj) are made, but once the objects are returned the values in the arrays are all messed up.

    I use a NSMutableArray object to hold the simpleObjs. In this case, I simple make three such simpleObj. Each simpleObj has two arrays: one a ten number array of integers (all "5") and the other an array of a structure. The structure only holds two NSPoints (which are also structures).

    For the life of me, I cannot figure out why the values are correct when made, but fall apart when passed out to the calling object. Help please!

    I use simpleObj for the object definition (header and methods all in one file) and I use "main" to call the object.

    Any help is greatly appreciated....

    James

    (Note: I'm not sure the two files (simpleObj.h and main.m made it as attached files - I'll keep trying if it does work via the "Attach Files" option)

    Attaching didn't work - I'll have to figure that out later. I will paste the two files in here now.

    Main:
    Code:
    //
    //  main.m
    //  Arrays2Objects
    //
    //  Created by JCTJ on 2/24/10.
    //  Copyright __MyCompanyName__ 2010. All rights reserved.
    //
    
    #import <Cocoa/Cocoa.h>
    #import "SimpleObj.h"
    
    int main(int argc, char *argv[])
    {
    	int				numOfObjects = 3,
    					howManyElements = 10,
    					i;
    	SimpleObj *		starterObject;
    	NSMutableArray * myArrayOfObjects;
    
    // Create the array of objects
    	myArrayOfObjects = [[NSMutableArray arrayWithCapacity:numOfObjects] retain];
    	
    // Add the simple Objects to the array of objects
    	for (i = 0; i < numOfObjects; i++)
    		{
    			starterObject = [[SimpleObj alloc] initWithNumber:howManyElements];		// Each must be unique due to later manipulations
    			[myArrayOfObjects addObject:starterObject];
    			[starterObject release];
    		}
    	
    //	Print the results
    	printf("The Final Results are.... \n");
    	for (i = 0; i < numOfObjects; i++) [[myArrayOfObjects objectAtIndex:i] spillMyGuts:i];
    	
    	[myArrayOfObjects release];
    	
    	return 0;
    }
    
    Here is the simpleObj file, with header and methods combined:
    Code:
    //
    //  SimpleObj.h
    //  Arrays2Objects
    //
    //  Created by JCTJ on 2/24/10.
    //  Copyright 2010 __MyCompanyName__. All rights reserved.
    //
    
    #import <Cocoa/Cocoa.h>
    #import <stdio.h>
    
    struct theStruct
    {
    	NSPoint entry;
    	NSPoint exit;			
    };
    
    @interface SimpleObj : NSObject 
    {
    	int						numOfElements;
    	int	*					simpleArray;		
    	struct theStruct *		structArray;			
    }
    
    //	Actions
    -(void)spillMyGuts:(int)theObjectNumber;
    
    //	Setters
    
    
    //	Accessors
    
    //	Overrides
    -(id)initWithNumber:(int)theNumber;
    -(void)dealloc;
    
    @end
    
    @implementation SimpleObj
    
    //	Actions
    -(void)spillMyGuts:(int)theObjectNumber
    {
    	int i;
    	
    	printf("SimpleObj %i: Array = {", theObjectNumber);
    	for (i = 0; i < numOfElements; i++) printf("%i, ", simpleArray[i]);
    	printf("}\n  Structure Array = \n");
    	for (i = 0; i < numOfElements; i++) 
    		{
    			printf("%i: (%f, %f)    (%f, %f) \n", i, structArray[i].entry.x, structArray[i].entry.y, structArray[i].exit.x, structArray[i].exit.y);
    		}
    	printf("\n \n");
    	
    	return;
    }
    //	Setters
    
    //	Accessors
    
    //	Overrides
    -(id)initWithNumber:(int)theNumber
    {
    	self=[super init];
    	if (self != nil)
    		{
    			int					i;
    			int					tempArray[theNumber];
    			struct theStruct	tempStructArray[theNumber];	
    			
    			numOfElements = theNumber;
    			
    			//	Create the temporary arrays
    			for (i = 0; i < theNumber; i++)
    				{
    					tempArray[i] = 5;
    					tempStructArray[i].entry.x = 2;
    					tempStructArray[i].entry.y = 4;
    					tempStructArray[i].exit.x = 7;
    					tempStructArray[i].exit.y = 14;
    				}	// i = 0 to theNumber
    			
    			//	Assign the temporary arrays to the pointers
    			simpleArray = tempArray;
    			structArray = tempStructArray;
    			
    			
    			// Print using the spillMyGuts method (number "0" means it is not being referenced from the NSMutableArray)
    			[self spillMyGuts:0];
    		}
    	return self;
    }
    
    -(void)dealloc
    {
    	[super dealloc];
    }
    
    @end;
    
     
  2. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #2
    Wouldn't you have to allocate (malloc) the space taken by each of your structs in those objects? Can I ask why you are using a C array and structs in the first place instead of objects? Unless you have hundreds of thousands of these, I doubt the overhead is going to kill you, and it'd make it a lot easier to use Cocoa classes for everything.
     
  3. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #3
    This is no good. You assign stack-local pointers to ivars in a heap-resident object. As soon as the init stack frame is popped, the pointers you have stored are garbage. They point to someplace in the stack that will be reused when subsequent stack frames are pushed.

    As HiRez said, you need to malloc heap space, or just use an NS(Mutable)Array or other structure.

    -Lee
     
  4. jctj thread starter macrumors newbie

    Joined:
    Feb 24, 2010
    #4
    This is used in an optimization program, so there can certainly be hundreds of thousands of integers being stored and manipulated. I wasn't sure what the speed overhead (as well as the memory overhead, but I would guess that would be relatively small) was for using NSNumber's for objects, so I was focusing on the 'smallest footprint' solution. Looks like - for the time being, at least - going all-object will be the best way to go.
     
  5. jctj thread starter macrumors newbie

    Joined:
    Feb 24, 2010
    #5
    I tried using new and delete, but oddly enough I couldn't find a way to make sure I was deleting ALL of the memory. "delete [] simpleArray" was not recognized by Cocoa, and I feared just deleting the pointer would end up with a massive memory leak. I got errors with every configuration I could think of, so finally I begged for help (here).

    This is a classic case of a little information being dangerous... I am surprised that the "int *simpleArray = new int [theNumber];" and "delete [] simpleArray;" don't work, since they are established C/C++ commands, but I'm sure there is a reason for it.

    I will just go w/ NSArray's of NSNumbers and NSPoints. If the speed or memory overhead becomes burdensome, I may be back here for help....

    Thanks for the help, guys. It really is appreciated.
     
  6. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #6
    new and delete are not C. If you want to mix C++ and Objective-C you need a .mm file extension so the Objective-C++ compiler is used.

    You seem to believe this should be Objective-C, and it seems to have a purpose beyond learning experience. If this is a production tool you need soon, write it in an environment you know. If you just want a learning experience and the tool doesn't need to be done soon, be fast, be correct, etc. go full-on cocoa/foundation, don't play with hybrid constructs.

    -Lee
     
  7. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #7
    If its "optimization" you want, use c++ or straight C.
     
  8. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #8
    new and delete are not C/C++ commands, they are C++ operators.

    The C functions to allocate and deallocate memory are malloc and free.

    Code:
    int* tempArray = malloc (number * sizeof (int));
    struct theStruct *tempStructArray = malloc (number * sizeof (struct theStruct));
    and call free () to free them in your dealloc method.

    BTW. It seems really cool that you can access members of an object just by their name - but at some point you will find out that it is not a good idea because you never know what a name in your source code means just by looking at it. Makes it continuously hard to read your code and easy to make mistakes.

    Many people (for example the programmers at Apple) make the names of all class members always end in an underscore like "int numOfElements_" so when you assign "numOfElements_ = 0;" you know immediately that this is modifying the self object when reading the source code.
     
  9. jctj thread starter macrumors newbie

    Joined:
    Feb 24, 2010
    #9
    Gnasher - thanks for the info! I tried to send this to you in a PM, but either you don't accept them or I can't find where to do it... With apologies to others, are you referring to using setter/accessor methods for objects or naming conventions? The naming issue makes sense - and I will do that henceforth - but using setter/accessors for integers in an array seemed to be overkill. if

    Code:
    simpleArray_[i] = 5;
    is confusing, is it any clearer to use

    Code:
    [simpleArray_ setInteger:i  theNumber:5];
    ?

    I understand why setters are better when dealing with memory issues, but even for integers?

    (@SilentPanda - thanks for adding code tags to my original post. Now I know how!)
     
  10. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #10
    Are you sure about that? I thought the trailing underscore was a C++ and Google Code convention, not Objective-C/Cocoa. I can't remember seeing that in any Apple code. I'm sure it does exist somewhere, but I'd bet those are C++ greybeards hesitant to give up their habits. I do specifically remember someone at Apple saying, in a WWDC presentation, that you should not use either prefix or suffix underscores, that they were not necessary. The presenter made that point at the time because a lot of people were using prefixed underscores for private variables and as those are reserved by Apple there may be a conflict, but he did also mention that any suffix was unnecessary.

    Not saying you can't use it, I'm just not so sure it's actually an Apple/Objective-C convention.
     
  11. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #11
    Apple has said that it is ok to use _prefix for ivars, but not for _private method names.
    http://developer.apple.com/mac/libr.../CodingGuidelines/Articles/NamingMethods.html
     
  12. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #12
    It is not about setters and getters. It's no problem setting members by hand, especially in the implementation of your method. The problem is: If you see a statement in a method in source code

    Code:
    theNumber = 5;
    what is it setting? Just by looking at the line of code, you have no idea. It could be a local variable named theNumber in your method. It could be a member of the object named theNumber. It could be a global variable defined somewhere completely else. It only takes you ten seconds to find out, but what if you are looking for a bug somewhere in ten thousand lines of code? These ten seconds add up.

    So if you use a good coding standard you will write one of these:

    Code:
    theNumber = 5; // Local variable
    theNumber_ = 5; // self->theNumber_
    gTheNumber = 5; // That would be a global variable
    
    One look at the line of code and you know exactly what it is doing.
     

Share This Page