Variable Passing issue

Discussion in 'iOS Programming' started by xelhark, Jul 16, 2010.

  1. macrumors newbie

    Joined:
    Jul 16, 2010
    #1
    Hi there!

    I was working on a Sudoku Generator. While trying different approaches i tried to create a Tree in which every node contains a partial generation, and if it can't go on that node is bounded. Eventually it should find a solution.

    The algorithm is not the problem, just take a look at this!


    Code:
    -(void) solve{
    	ConstraintGraph *g = [[ConstraintGraph alloc] initAsSudoku];
    	
    	SolutionTree *tree = [[SolutionTree alloc] init];
    
    	tree.root->info = (Node*)(g.nodeList->Head->info);
    	
    	tree.root->info->n = 3;
    	NSLog(@"the value is %d", tree.root->info->n);
     * * * *//this prints 'the value is 3'
    	[self visitNode:tree.root];
    	
    }
    
    -(void) visitNode:(solutionTreeNode*)N{
     * * * *//this prints 'the value is 1296' (or another number)
    	NSLog(@"he value is %d", N->info->n);
    }
    

    The first NSLog prints
    Code:
    the value is 3
    the second one (in visitNode) prints:

    Code:
    the value is 1456
    or other random numbers..

    I think the problem happens when i pass the variable, but i couldn't figure it out. Could you please help me? :confused:

    Thanks in advance :p
     
  2. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    Are there any warnings when you compile this? Are all the declarations in scope?

    Otherwise it's difficult to guess without seeing the declarations for all the relevant bits. I'll also say it's a bit weird to see the -> operator mixed with Objective-C classes, but legit if you know what you're doing.
     
  3. thread starter macrumors newbie

    Joined:
    Jul 16, 2010
    #3
    Nope, no warning, nothing at all..

    Actually i'm using Objective-C++ which lets me use structs and lists rather than NSMutableArrays (i'm trying to make it as fast as i can), and that's why i'm using -> operator

    anyway, i tried to take a better look at it, and it might be some casting problem..

    I isolated it here..
    Code:
    	ConstraintGraph *g = [[ConstraintGraph alloc] initAsSudoku];
    	NSLog(@"The value is %d", ((Node*)(g.nodeList->Head->info))->n);
    
    The ConstraintGraph is a graph in which a node is connected to another node if they must have different values. (for example, a node is connected with all of the other nodes in his row, column and 3x3 subgrid)


    anyway, the NSLog here prints
    'The value is [random number]'

    This is the code from the 'initAsSudoku' method.

    Code:
    -(id) initAsSudoku{
    	if ((self = [super init])) {
    		Node Nodi[SUDOKUSIZE][SUDOKUSIZE];
    		for (int i=0; i<SUDOKUSIZE; i++) {
    			for (int j=0; j<SUDOKUSIZE; j++) {
    				Nodi[i][j].Adjs = new myList();
    				//-----------------HERE I AM INITIALIZING THE n AS 0
    				Nodi[i][j].n = 0;
    			}
    		}	
    		
    		/*
    		 You can skip this part, it just creates the connections
    		 */
    		for (int i=0; i<SUDOKUSIZE; i++) {
    			for (int j=0; j<SUDOKUSIZE; j++) {
    				//Adding Constraints...
    				//The first SUDOKUSIZE-1 (except itself) are the ones from its subgrid
    				for (int k=0; k<SUDOKUSIZE; k++) {
    					int x = (((i/sizeX)*sizeX)+(k%3));
    					int y = (((j/sizeY)*sizeY)+(k/3));
    					if (x!=i || y != j) {
    						Nodi[i][j].Adjs->addNodeContaining(&Nodi[x][y]);
    					}
    				}
    				//The others are from its row/column (except the ones in the subgrid)
    				for (int k=0; k<SUDOKUSIZE; k++) {
    					if (k/sizeX != i/sizeX) {
    						Nodi[i][j].Adjs->addNodeContaining(&Nodi[k][j]);
    					}
    					if (k/sizeY != j/sizeY) {
    						Nodi[i][j].Adjs->addNodeContaining(&Nodi[i][k]);
    					}
    				}
    			}
    		}
    		/*
    		 Here all connections are created, i store the nodes in a list then return
    		 */
    		nodeList = new myList();
    		//Adding nodes in the list..
    		for (int i=0; i<SUDOKUSIZE; i++) {
    			for (int j=0; j<SUDOKUSIZE; j++) {
    				nodeList->addNodeContaining(&Nodi[i][j]);
    			}
    		}
    		NSLog(@"The value is %d", ((Node*)(self.nodeList->Head->info))->n);
    	}
    	return self;
    }
    
    The list holds a (void*) as info, that's why i need the cast.

    The weird thing is, the NSLog here prints '0' (the right value). Once the code returns to the first method, the VERY SAME instruction prints another value (random)
    :eek:
    i don't know what to do please help :(
     
  4. macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #4
    Remember that NSLog is a varargs method and it doesn't really know the types of the values passed to it. You can put a typecast in the NSLog to help it with the type, like:

    Code:
    NSLog(@"The value is %d", (int)((Node*)(g.nodeList->Head->info))->n);
    
    Otherwise what happens with something like

    Code:
    NSInteger d = (g.nodeList->Head->info)->n;
    NSLog(@"The value is %d", d);
     
  5. macrumors 603

    Joined:
    Aug 9, 2009
    #5
    First, you need to post the datatypes: struct definitions, class headers, properties, etc. We can't tell what anything is except by guessing from context. There isn't enough context to determine what's really happening.

    Second, assuming that nodeList is both an ivar and a property, you are accessing the property in two different ways (red hilited code). This may be a problem if your property is defined as retain, but you don't consistently use the property accessors.

    So my guess is that you somehow have a variable being deleted or dealloc'ed, yet you still have a reference to it, but without seeing more of the data types and properties, it's just a guess.


    In general, the debugging strategy to use is Bracketing. You set a breakpoint before or at the initFunction. You inspect the variables. You set another breakpoint at the end of the function. Inspect variables again. Set a third breakpoint right before the printing that doesn't work. Inspect variables yet again, and then single-step only if they're correct.

    If all the variables (and the memory they point to) is always correct, and the print works, then expand the range bracketed by the breakpoints. If the 2nd or 3rd breakpoint shows incorrect variables (or memory), then move the breakpoint earlier or later, so there are always 2 breakpoints bracketing a suspected section of code. You will eventually find the statement that's wrong as you move the breakpoint past it.

    You can move the 1st breakpoint later, as you find that a bracketed section of code is correct. The 1st breakpoint establishes your "known good" state. The other 2 move as you search for the point at which it goes bad.
     
  6. macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #6
    Are you kidding? Do you know how powerful the iPhone is when compared to the small differences in speed between C++ and Obj-C messaging?

    Smells like premature optimization to me.
     
  7. thread starter macrumors newbie

    Joined:
    Jul 16, 2010
    #7
    Uhm... You're right, i didn't think of it, i'll check it out and let you know.. Thanks a lot ;)



    Actually, i once tried using a NSMutableArray for things like that, and it came up being really really slow compared to this kind of lists, but maybe there were other things slowing it down.. I'm not sure, and i'm pretty new to Objective-C and iPhone programming, so if you think it's faster to use NSMutableArrays instead of lists i'd be glad to accept your advice :)
     
  8. thread starter macrumors newbie

    Joined:
    Jul 16, 2010
    #8
    GREEEEEEEEAT!! :D

    thanks a lot chown33, you spotted the precise problem!

    The problem was, i was allocating the nodes in the stack and not in the heap, so even if i saved them in the "nodeList" they were being deleted as soon as the function returned.

    This was the problem:
    Code:
    		Node Nodi[SUDOKUSIZE][SUDOKUSIZE]; //<--- STACK ALLOCATION!
    		for (int i=0; i<SUDOKUSIZE; i++) {
    			for (int j=0; j<SUDOKUSIZE; j++) {
    				Nodi[i][j].Adjs = new myList();
    				Nodi[i][j].n = 0;
    			}
    		}	
    		
    
    And this is how i solved it:

    Code:
    		Node **Nodi = (Node**)malloc(SUDOKUSIZE * sizeof(Node*)); //<-- HEAP ALLOCATION
    		for (int i=0; i<SUDOKUSIZE; i++) {
    			Nodi[i] = (Node*)malloc(SUDOKUSIZE * sizeof(Node)); //Other Heap allocation
    			for (int j=0; j<SUDOKUSIZE; j++) {
    				Nodi[i][j].Adjs = new myList();
    				Nodi[i][j].n = 0;
    			}
    		}
    
    Thanks to you all guys, you're amazing :D:D:D:D
     
  9. macrumors 603

    Joined:
    Aug 9, 2009
    #9
    You haven't shown any data types. No one can tell whether NSMutableArray is good, when they haven't seen the structure of the data.

    And you should realize that Objective-C is a true superset of C. Anything you can do in C, you can also do in Objective-C. This means you can use C arrays, including ones allocated by malloc() or calloc(). You can also use macros.
     

Share This Page