Register FAQ / Rules Forum Spy Search Today's Posts Mark Forums Read
Go Back   MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Apr 25, 2013, 03:10 PM   #1
dancks
macrumors member
 
Join Date: Nov 2009
Objective-C noob: EXC_BAD_ACCESS with simple print method?

I'm going through an exercise in a cocoa programming book, where there is a GUI and from a textfield I enter and to a list of strings displayed on a table. There are plenty of things that aren't working, the most confusing of which is I keep leaking data. First with NSMutableArray, so I decide to try a c style linked list for whatever reason. I got a prototype to work in C, apply it to my project, it leaks and seg faults whenever I try to to simply print out the string:

struct declaration in header:
Code:
    struct que {
    NSString *sentence;
    struct que *next; };
    typedef struct que que;
    @interface linkedlist : NSObject
    {
    que *top;
    int count;
    }
method in question:

Code:
    -(void)print_list
    {
    if(top==nil) {printf("In print_list, top lost its node!\n");exit(3);}
    for(que *a=top;a!=0;a=a->next) NSLog(@"\n%@\n",a->next);
    }
I even published/archived the app to be standalone and ran it with valgrind and it didn't detect any data loss until I pressed "Check List" button which calls print_list.

entire linkedlist.m (in case there's something I missed:

Code:
#import <stdlib.h>
#import <stdio.h>
#import "linkedlist.h"

@implementation linkedlist
-(id)init
{
    [super init];
    count = 0;
    top = 0;
    return self;
}
-(void)dealloc
{
    [self destroy];
}
+(que *)get_new:(NSString *)str
{
	que *nnew = 0;
	if(!(nnew = malloc(sizeof(que)))) {printf("In get_new, malloc failed\n"); exit(1);}
	nnew->sentence=str;
	nnew->next=0;
    if (nnew!=nil) printf("Good here\n");
	return nnew;
}
+(void)pop:(que**)p
{
	if(p!=0)
	{
		if((*p)!=0)
		{
			if((*p)->next==0)
			{
				printf("In pop, popping single node\n");
			}
			que *a = *p;
			(*p)=(*p)->next;
			a->next=0;
			free(a);
		}
		else
		{
			NSLog(@"In pop: Pop passed a null pointer. going to crash\n");
			que *a;
			a->next=0; //crash
		}
	}
}
+(void)pop_in_middle:(que**)n
{
	if(n!=0)
	{
		if((*n)!=0)
		{
			if(!(*n)->next)
			{
				printf("In pop_in_middle, que->next not set, not popping\n");
			}
			else
			{
				if(!(*n)->next->next)
				{
					printf("In pop_in_middle, que->next->next not set\n");
				}
				que *h1 = (*n)->next;
				que *h2 = (*n)->next->next;
				(*n)->next=h2;
				h1->next=0;
				free(h1);
			}
		}
	}
}
+(void)pop_last:(que**)a
{
	que *h = (*a)->next;
	(*a)->next=0;
	if(h->next)
	{
		NSLog(@"in pop_last, h->next is either dangling or points to valid memory. About to leak\n");
		h->next=0;
	}
	free(h);
}
+(void)pushed:(que**)a pusher:(que*)b
{
	b->next=(*a);
	(*a)=b;
}
+(void)add_to_middle:(que**)a str:(NSString *)s
{
	que *nnew = [linkedlist get_new:s];
	que *holder = (*a)->next;
	nnew->next=holder;
	(*a)->next=nnew;
}


-(void)dropAt:(int) i
{
	count = [self check_count];
	if(top!=0)
	{
		if((!i)||(count==1))
		{
			NSLog(@"Popping top node\n");
			[linkedlist pop:&top];
		}
		else if(i>=count)
		{
			NSLog(@"popping last node\n");
			que *a;
			for(a=top;a->next!=0;a=a->next);
			[linkedlist pop_last:&a];
		}
		else if(count>=2)
		{
			NSLog(@"popping somewhere in the middle\n");
			que *a = top;
			for(int x=0;x<(i-1);x++) a=a->next;
			[linkedlist pop_in_middle:&a];
		}
		else
		{
			NSLog(@"in dropAt, something is wrong with the logic\n");
		}
		count--;
	}
	else
	{
		NSLog(@"In dropAt: Top is 0\n");
	}
}
-(void)place:(NSString*)str At:(int)i
{
	count = [self check_count];
	if(top==0)
	{
		NSLog(@"Top is initially null\n");
		top = [linkedlist get_new:str];
        if(top!=nil) printf("Good here apparently. Dereference:\n");
        NSLog(@"\n%@\n",top->sentence);
	}
	else
	{
		que *nnew = 0;
		que *a;
		if(i<=0)
		{
			NSLog(@"Inserting que at top\n");
			nnew = [linkedlist get_new:str];
			[linkedlist pushed:&top pusher:nnew];
		}
		else if(i>=count)
		{
			NSLog(@"Inserting que at bottom\n");
			nnew = [linkedlist get_new:str];
			for(a=top;a->next!=0;a=a->next);
			a->next=nnew;
		}
		else
		{
			NSLog(@"Inserting que in middle somewhere\n");
			a=top;
			for(int x=0;x<(i-1);x++) a=a->next;
			[linkedlist add_to_middle:&a str:str];
		}
	}
	count++;
}


-(void)print_list
{
    if(top==nil) {printf("In print_list, top lost its node!\n");exit(3);}
	for(que *a=top;a->next!=0;a=a->next) NSLog(@"\n%@\n",a->next);
}
-(int)check_count
{
	int i=0;
	for(que *a=top;a!=0;a=a->next) i++;
	return i; 
}
-(int)count
{
	return count;
}
-(void)destroy
{
	NSLog(@"Linked list about to be destroyed\n");
	while(top!=0)
	{
		[linkedlist pop:&top];
	}
}
-(NSString *)stringAt:(int)i
{
    NSString *b = @"";
    if(i<count)
    {
        que *a=top;
        for(int z=0;((z<i)&&(a->next!=0));z++) a=a->next;
        b=a->sentence;
    }
    return b;
}
@end
dancks is offline   0 Reply With Quote
Old Apr 25, 2013, 03:30 PM   #2
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
You used %@ which is the format specifier for NSObject*, but a->next is not an NSObject*. If you turn on warnings about format specifiers, the compiler will tell you.
gnasher729 is offline   0 Reply With Quote
Old Apr 25, 2013, 03:50 PM   #3
dancks
Thread Starter
macrumors member
 
Join Date: Nov 2009
Quote:
Originally Posted by gnasher729 View Post
You used %@ which is the format specifier for NSObject*, but a->next is not an NSObject*. If you turn on warnings about format specifiers, the compiler will tell you.
Ok. Would that explain the error message? Valgrind tells me it's try to access data of size 8. I assume that means an unallocated byte. Unless NSLog itself is causing the crash by using the wrong formatting, causing a default? What would I use in its place? Xcode warns me against %s, saying its the wrong data type
dancks is offline   0 Reply With Quote
Old Apr 25, 2013, 04:04 PM   #4
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by dancks View Post
Ok. Would that explain the error message? Valgrind tells me it's try to access data of size 8. I assume that means an unallocated byte. Unless NSLog itself is causing the crash by using the wrong formatting, causing a default? What would I use in its place? Xcode warns me against %s, saying its the wrong data type
%@ for NSObject*.
%s for char*
%p to print a pointer.

a->next is neither an NSObject*, nor a char*, but a struct que*. So %p is the only one that would work.

Surely Xcode warned against %@ as well, didn't it?

%@ works by assuming the parameter is an NSObject*, sending it the "description" method which should return an NSString*, and printing the characters in the NSString*. Since you passed a struct que*, sending it a "description" method isn't going to work.
gnasher729 is offline   0 Reply With Quote
Old Apr 25, 2013, 04:23 PM   #5
dancks
Thread Starter
macrumors member
 
Join Date: Nov 2009
Quote:
Originally Posted by gnasher729 View Post
%@ for NSObject*.
%s for char*
%p to print a pointer.

a->next is neither an NSObject*, nor a char*, but a struct que*. So %p is the only one that would work.

Surely Xcode warned against %@ as well, didn't it?

%@ works by assuming the parameter is an NSObject*, sending it the "description" method which should return an NSString*, and printing the characters in the NSString*. Since you passed a struct que*, sending it a "description" method isn't going to work.


there we go! I didn't want to print out a struct, I wanted to print out the string! lolz. wow. Thanks.

EDIT: hold the phone:
Code:
for(que *a=top;a->next!=0;a=a->next) NSLog(@"\n%s\n",[a->sentence UTF8String]);
crashes. No warnings. Nothing. I'm getting really frustrated.

Last edited by dancks; Apr 25, 2013 at 04:58 PM.
dancks is offline   0 Reply With Quote
Old Apr 25, 2013, 08:03 PM   #6
lee1210
macrumors 68040
 
lee1210's Avatar
 
Join Date: Jan 2005
Location: Dallas, TX
Start much simpler. You're going to a lot of trouble, mixing a lot of C data structures and Objective-C, throwing things at the wall and hoping dearly for a miracle.

Given an NString literal, can you log it?
Now can you do it using %@ as the format specifier?
Now create an NSArray of NSString.
Use fast enumeration to log each element.
Create an NSMutableArray.
Add NSStrings one at a time.
Loop over this with fast enumeration, logging each element.
Try logging one of your NSArrays directly with %@.

Look at the documents for NSString, NSArray, and NSMutableArray. Test the methods. Print lengths. Remove elements. Play with an NSMutableString.

You're expecting things to happen without practice. Read the docs. When something doesn't work right away, spend time figuring it out. Don't fall back to what you already know, it will only confuse you and keep you from the real task: learning. Ask questions here. Post full, compilable code. Do your exercises in main, don't worry about building your own objects yet.

Good luck.
-Lee
lee1210 is offline   0 Reply With Quote
Old Apr 25, 2013, 08:49 PM   #7
subsonix
macrumors 68030
 
Join Date: Feb 2008
Quote:
Originally Posted by dancks View Post
EDIT: hold the phone:
Code:
for(que *a=top;a->next!=0;a=a->next) NSLog(@"\n%s\n",[a->sentence UTF8String]);
crashes. No warnings. Nothing. I'm getting really frustrated.
You haven't told us under what circumstances it crashes, for example, trying to print an empty list would segfault since *top would be a NULL pointer and a->next is attempting to dereference it.

Some other thoughts, your list methods doesn't need to take a reference to the list itself as arguments, you already have an internal reference with your instance variable *top. This way you can also avoid one level of indirection and hide your internal list representation from your interface.
subsonix is offline   0 Reply With Quote
Old Apr 25, 2013, 11:57 PM   #8
ArtOfWarfare
macrumors 601
 
ArtOfWarfare's Avatar
 
Join Date: Nov 2007
Send a message via Skype™ to ArtOfWarfare
Quote:
Originally Posted by dancks View Post
EDIT: hold the phone:
Code:
for(que *a=top;a->next!=0;a=a->next) NSLog(@"\n%s\n",[a->sentence UTF8String]);
crashes. No warnings. Nothing. I'm getting really frustrated.
Don't write out so much on a single line - it becomes difficult to read. Your code has no comments in it anywhere which also makes it difficult to read.

What do you think your code does? Write down a list in plain english of the steps that occur in order. I wrote them down in white below - highlight it to read it.

1: (In the Initialization of the for loop) Define a as a pointer to a que structure that is equivalent to top.
2: (In the Condition of the for loop) Check that member next (why are you already looking at member next?) of the que structure pointed at by a is not 0 (is that really what you want? What is 0?). If it is, exit the for loop.
3: (In the Body of the for loop) Invoke UTF8String on member sentence of the que structure pointed at by a, and put the results in a formatted string. (This is an odd way of printing out an NSString. There's a format specifier that you can use to print out any NSObject, which NSString inherits from. Why not use that specifier and pass it the NSString* directly?)
4: (In the Increment of the for loop) Set a as the pointer to whatever member next of a points at.


I've bolded questions in the steps above for you that should hopefully help you fix your mistakes. I wrote it in white because I figured it'd be a good exercise for you to come up with the steps yourself before you look at what I came up with. I listed the steps myself as an exercise for myself, because practice is good for everyone.
__________________
Battery Status - On the Mac App Store
The only app that'll estimate when your wireless devices will need their batteries changed.
Including the ones paired with other Macs on your network.
ArtOfWarfare is offline   0 Reply With Quote
Old Apr 26, 2013, 11:39 AM   #9
dancks
Thread Starter
macrumors member
 
Join Date: Nov 2009
lol. In my defense I did actually get it to work somewhat by replacing NSLog with fprintf. I didn't fully test the linkedlist outside of the project but I'm confident there are no leaks.

Now I get EXC_BAD_ACCESS on return NSApplicationMain(argc, (const char **)argv); after a couple of seconds of testing it out (adding, deleting rows). I wonder if I have to take ownership of and manually release rows in a tableview when I want to remove them.

My understanding of what happened is that when you pass a pointer or object to NSLog, it takes it by reference and destroys it at the end of execution, leaving a dangling pointer. This wouldn't explain why I get a bad pointer with [MyString UTF8String] as that returns a const char*, which can't be destroyed (but can be lost). It doesn't make sense but thats the only thing I can figure.

I just tested:
Code:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[])
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

	NSString *test = [[NSString alloc] initWithUTF8String:"This is the test string"];
	int i;

	NSLog(@"First test:\n");
	for(i=0;i<4;i++)
	{
		NSString *ret = [NSString stringWithString:test];
		NSLog("\n%@\n",ret);
		[ret release];
	}

	NSLog(@"Second test:\n");
	for(i=0;i<4;i++)
	{
		NSLog("\n%@\n",test);
	}

	[test release];
	[pool drain];
	return 0;
}
but I get:

Code:
NSStringtest.m:13: warning: passing argument 1 of ‘NSLog’ from incompatible pointer type
NSStringtest.m:20: warning: passing argument 1 of ‘NSLog’ from incompatible pointer type
mac:objective-c jdd$ ./test
2013-04-26 04:35:30.725 test[584:903] First test:
Segmentation fault
dancks is offline   0 Reply With Quote
Old Apr 26, 2013, 12:41 PM   #10
whooleytoo
macrumors 603
 
whooleytoo's Avatar
 
Join Date: Aug 2002
Location: Cork, Ireland.
Send a message via AIM to whooleytoo
NSLog requires a NSString, not a char*. So, it should be NSLog(@"....") rather than NSLog("...");
__________________
Mac <- Macintosh <- McIntosh apples <- John McIntosh <- McIntosh surname <- "Mac an toshach" <- "Son of the Chief"
whooleytoo is offline   0 Reply With Quote
Old Apr 26, 2013, 12:43 PM   #11
chown33
macrumors 603
 
Join Date: Aug 2009
Quote:
Originally Posted by dancks View Post
lol. In my defense I did actually get it to work somewhat by replacing NSLog with fprintf. I didn't fully test the linkedlist outside of the project but I'm confident there are no leaks.

Now I get EXC_BAD_ACCESS on return NSApplicationMain(argc, (const char **)argv); after a couple of seconds of testing it out (adding, deleting rows). I wonder if I have to take ownership of and manually release rows in a tableview when I want to remove them.

My understanding of what happened is that when you pass a pointer or object to NSLog, it takes it by reference and destroys it at the end of execution, leaving a dangling pointer. This wouldn't explain why I get a bad pointer with [MyString UTF8String] as that returns a const char*, which can't be destroyed (but can be lost). It doesn't make sense but thats the only thing I can figure.
Explain how you achieved this understanding. Please give a rationale (explanation of your though process).

I think you're guessing, or misunderstanding something you may have read somewhere long ago.

NSLog takes no ownership of anything passed to it. Why would it? It needs no objects or pointers to have a lifetime beyond the single function call. There's no logical reason for it to alter any retain-counts, either by retaining or releasing anything.




In these statements, point out "argument 1 of 'NSLog'":
Code:
		NSLog("\n%@\n",ret);
		NSLog("\n%@\n",test);
Do this before reading further.



Answers in light gray text:
  • The answer is that "\n%@\n" is argument 1.
  • What type is it? It's a C string literal (formal type: const char[]).
  • What type does NSLog need? An NSString object (formal type: NSString *).
  • How does one write an NSString literal? Like so: @"\n%@\n"


Note that this convoluted code:
Code:
	NSString *test = [[NSString alloc] initWithUTF8String:"This is the test string"];
is more succinctly expressed as:
Code:
	NSString *test = @"This is the test string";
You should review the very basic parts of Objective-C, and learn them without thinking of them as related to C. The complex code looks like something a C programmer would write if they only knew about NSString methods, and were unaware of how to write Objective-C NSString literals. Literals are fundamental.


It would also help us understand your learning context if you provided the following:
1. The exact title, author, and edition of the book.
2. What other programming languages you know, and programming experience you have. A complete work history isn't needed. I'm just trying to figure out why your approach seems to have C in it.
chown33 is offline   0 Reply With Quote
Old Apr 27, 2013, 12:09 AM   #12
dancks
Thread Starter
macrumors member
 
Join Date: Nov 2009
Quote:
Originally Posted by chown33 View Post
Explain how you achieved this understanding. Please give a rationale (explanation of your though process).

I think you're guessing, or misunderstanding something you may have read somewhere long ago.

NSLog takes no ownership of anything passed to it. Why would it? It needs no objects or pointers to have a lifetime beyond the single function call. There's no logical reason for it to alter any retain-counts, either by retaining or releasing anything.

You should review the very basic parts of Objective-C, and learn them without thinking of them as related to C. The complex code looks like something a C programmer would write if they only knew about NSString methods, and were unaware of how to write Objective-C NSString literals. Literals are fundamental.


It would also help us understand your learning context if you provided the following:
1. The exact title, author, and edition of the book.
2. What other programming languages you know, and programming experience you have. A complete work history isn't needed. I'm just trying to figure out why your approach seems to have C in it.
the first language I tried to learn seriously was C++, so I just feel comfortable with it. It did allow me to eliminate any possible problems with using NSMutableArray. I have an annoying habit of glossing over the small yet still important parts of programming. I seriously toyed with the idea of writing a program that would run through and fix minor typo's and symbols I forgot. Like '@'. I'll get around to it.

Thanks everyone for your patience.
dancks is offline   0 Reply With Quote
Old Apr 27, 2013, 01:38 PM   #13
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by dancks View Post
the first language I tried to learn seriously was C++, so I just feel comfortable with it. It did allow me to eliminate any possible problems with using NSMutableArray. I have an annoying habit of glossing over the small yet still important parts of programming. I seriously toyed with the idea of writing a program that would run through and fix minor typo's and symbols I forgot. Like '@'. I'll get around to it.

Thanks everyone for your patience.
Have you tried Xcode? Turn all the warnings on, and turn the static analyzer on as well. Make sure that warnings = errors. Xcode will find an awful lot of bugs, and Xcode will very often suggest the correct fix.
gnasher729 is offline   0 Reply With Quote
Old Apr 27, 2013, 02:04 PM   #14
Madd the Sane
macrumors 6502
 
Join Date: Nov 2010
Location: Utah
You can skip the Xcode step by using Clang. It will show the warnings in a helpful manner in the Terminal.
Madd the Sane is offline   0 Reply With Quote
Old Apr 27, 2013, 04:47 PM   #15
gnasher729
macrumors G5
 
gnasher729's Avatar
 
Join Date: Nov 2005
Quote:
Originally Posted by Madd the Sane View Post
You can skip the Xcode step by using Clang. It will show the warnings in a helpful manner in the Terminal.
What would be the benefit of that?
gnasher729 is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > Mac Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -5. The time now is 09:04 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Copyright 2002-2013, MacRumors.com, LLC