Objective C: Why am I getting "EXC_BAD_ACCESS"? - objective-c

I'm really new to Objective C and am trying to write a program to go through the collatz conjecture. When I run the program, it stops after the first scanf and comes up with "EXC_BAD_ACCESS". Here's my code:
int original,i;
NSString *PrintFull;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(#"Collatz Conjecture:");
NSLog(#"Print full results?");
scanf("%s",PrintFull);
NSLog(#"What number should we go up to?");
scanf("%d", &original);
while (original <= 100) {
NSLog(#"\n\n%d", original);
i = original;
while (i != 1) {
if (i % 2) {
i = (i*3)+1;
} else {
i = (i/2);
}
if ([PrintFull isEqualToString:#"yes"]) {
NSLog(#"%d",i);
}
}
original++;
}
}
What am I doing wrong here?

scanf does not work with with object types such as NSString. Please see SO post - Using scanf with NSStrings.

scanf's arguments after the format string should point to already allocated objects. In this case you've just declared a pointer and passed it in without setting it. scanf will try to write to this location, but since the pointer contains a garbage value, the application crashes.
scanf is from the C library 'stdio.h', meaning it doesn't know about NSStrings, which are from the Objective-C 'Foundation' framework.
The following should solve these problems
int original,i;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSLog(#"Collatz Conjecture:");
NSLog(#"Print full results?");
char inputBuffer[80];
scanf("%s", inputBuffer);
NSString *printFull = [NSString stringWithCString:inputBuffer encoding:NSUTF8Encoding];

First, you have to initialize and alloc the NSString. Second, scanf can't handle NSString.
Also notice, that class names begin with a capital letter and class instances with a small one.

Related

Objective c — Update parameter in block

I was doing some tinkering with tree traversals (which I have solved in a much more straightforward way) but I have come across an issue in the following piece of Objective C logic:
- (NSString *)someWrapperFunction
{
NSString *result = #"";
NSString *(^appendBlock)(int, NSString **) = ^NSString *(int a, NSString **adder){
if (a == 0)
{
// base case
return #"";
}
NSLog(#"%d", a);
*adder = [*adder stringByAppendingFormat:#"-%d-", a];
NSLog(#"adder: %#", *adder);
return [*adder stringByAppendingString:appendBlock(a-1, adder)];
};
appendBlock(5, &result);
return result;
}
Basically, I want to create a block of code that concatenates numbers into the given string (adder). The result should be: "-5--4--3--2--1-".
I get a segmentation fault with the above code but with some other code that I wrote for the tree traversal, the adder string was essentially not getting updated. Any pointers to what I am doing wrong here? (Is it possible that the variable that is being updated by the inner block (inside recursion) is disallowed as it is already being occupied by the outer block OR is it just that NSString is non-mutable data type?)
In any case, I want to keep the design of the function the same; how would I solve this problem (using c/objective)?
After some searching and experimenting I found a way to fix this.
There is no reason to be using a double-pointer for your adder parameter in the block. Just use a regular pointer and update your code accordingly.
The error is coming from the fact that inside of the block, appendBlock is NULL and you end up dereferencing the NULL pointer trying to call it.
Here's an updated version that works:
- (NSString *)someWrapperFunction
{
NSString *result = #"";
NSString *(^appendBlock)(int, NSString *);
__block __weak NSString *(^weakBlock)(int, NSString *);
weakBlock = appendBlock = ^NSString *(int a, NSString *adder){
NSString *(^innerBlock)(int, NSString *) = weakBlock;
if (a == 0)
{
// base case
return #"";
}
NSLog(#"%d", a);
adder = [adder stringByAppendingFormat:#"-%d-", a];
NSLog(#"adder: %#", adder);
// Split this update to make it easier to debug.
NSString *update = innerBlock(a-1, adder);
return [adder stringByAppendingString:update];
};
appendBlock(5, result);
return result;
}
Output: "-5--4--3--2--1-"
This update is rewritten for point #1 (which really has nothing to do with your original issue.
To solve point #2 this update creates the original appendBlock variable as well as a new __block __weak weakBlock reference to the same block. And then inside the block, a new (strong) block pointer is created to reference the weak block pointer. Without the use of the weak pointer, the code works but causes a warning.

Function calls with pointers in Objective C

I'm a newbie in Objective C, used to write C. Anyway, I have a class called DataProcessing:
DataProcessing.m
...
- (BOOL)MyStringTweaker:(NSString *)strIn : (NSString *)strOut {
if(some_thing) {
strOut = [NSString stringWithFormat:#"I_am_tweaked_%#", strIn];
return true;
}
else
return false;
}
...
From the AppDelegate (OSX Application)
AppDelegate.m
...
NSString *tweaked;
DataProcessing *data_proc = [[DataProcessing alloc] init];
if([data_proc MyStringTweaker:#"tweak_me":tweaked])
NSLog([NSString stringWithFormat:#"Tweaked: %#", tweaked]);
else
NSLog(#"Tweaking failed...");
...
This doesn't work, *tweaked is NIL after the call to MyStringTweaker...
What am I missing?
Objective-C, like C, is pass-by-value only. You need to change your method signature to be:
- (BOOL)MyStringTweaker:(NSString *)strIn : (NSString **)strOut
and use:
*strOut = [NSString stringWithFormat:#"I_am_tweaked_%#", strIn];
to do the assignment.
Then, where you call it, you need to pass the address of the pointer you want to fill in:
[data_proc MyStringTweaker:#"tweak_me" :&tweaked]
A good explanation is in the comp.lang.c FAQ.
Editorial aside: Why not label the second argument? It looks weird to have it naked like that.

Objective-C, Simple String input from Console?

I honestly did a) search using key words and b) read the 'questions with similar titles' before asking this.
Also I tried to make this question more concise, but I had a hard time doing that in this case. If you feel the question is too wordy, I get it. Just don't try to answer.
I'm trying to write very simple objective-C programs that mirror the basic assignments in my introductory java class. I worked through an objective-c book over the summer and now I want to do lots of practice problems in objective-c, at the same time as I do java practice problems. I'm avoiding the objective-c GUI environment and just want to focus on working with the language for awhile. I still have a lot to learn about how to figure things out.
The program I'm duplicating from my java homework, is a standard type. I ask the user for number input and string input via the console. I was able to get numeric input from the console using an example I found here using scan f. (I will put the couple code lines below). But I'm unsure on how to get console input and store it in a string (NSString). I'm trying to learn to use the apple documentation and found a reference to a scan type command, but I cannot figure out how to USE the command. The one that seems likely is
scanCharactersFromSet:(NSCharacterSet )scanSet intoString:(NSString *)name;
Here's what I understand and works
int age = 0;
NSLog (#"How old are y'all?");
scanf("%d", &age);
NSLog (#"\n Wow, you are %d !", age);
But I don't understand how to pickup an NSString called 'name'. I THINK I'm supposed to make my 'name'a pointer, because the class is NSString.
(BTW I did try using scanf to pickup the string, but the compiler doesn't like me trying to use scanf in conjunction with name. It says that I shouldn't be using 'scanf' because it's expecting a different kind of data. I'm not sure where I found the data type 'i'. I was looking through my text for different ideas. I'm guessing that scanf is related to 'scanfloat' which clearly deals with numeric data, so this is not a big surprise)
I realize that 'scanf' isn't the right command (and I don't really get why I can't even find scanf in the apple documentation - maybe it's C?)
I'm guessing that scanCharactersFromSet might be the right thing to use, but I just don't understand how you figure out what goes where in the command. I guess I tend to learn by example, and I haven't found an example. I'd like to figure out how to learn properly by reading the documentation. But I'm not there yet.
NSString* name ;
scanf("%i", &name);
//scanCharactersFromSet:(NSCharacterSet *)scanSet intoString:(NSString **)name;
...
My book is oriented towards moving me into a gui environment, so it doesn't deal with input.
Thank you for any pointers you can give me.
Laurel
I would recommend ramping up on C. Objective-c is a thin layer over C and that knowledge will pay for itself over and over.
There's multiple ways in C to read:
http://www.ehow.com/how_2086237_read-string-c.html
For example:
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
[pool drain];
return 0;
NOTE: the simple scanf is succeptible to buffer overruns. There's multiple approaches around this. see:
How to prevent scanf causing a buffer overflow in C?
Here is what Objective C looks like:
NSString *FNgetInput() {
#autoreleasepool {
return [[[NSString alloc] initWithData:[[NSFileHandle fileHandleWithStandardInput] availableData] encoding:NSUTF8StringEncoding] stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]];
}
}
The way to get data from the standard input (or any other file handle) in cocoa is to use the NSFileHandle class. Check the docs for +fileHandleWithStandardInput
Here's how to get user input using Objective-C in 2020:
main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
NSLog(#"Hello, World!");
char str[50] = {0}; // init all to 0
printf("Enter you Last name: ");
scanf("%s", str); // read and format into the str buffer
printf("Your name is %s\n", str); // print buffer
// you can create an NS foundation NSString object from the str buffer
NSString *lastName = [NSString stringWithUTF8String:str];
// %# calls description o object - in NSString case, prints the string
NSLog(#"lastName=%#", lastName);
return 0;
}
return 0;
}
Compile and run:
$ clang -framework Foundation main.m -o app

How to change this so that it returns arrays

The following code works perfectly and shows the correct output:
- (void)viewDidLoad {
[super viewDidLoad];
[self expand_combinations:#"abcd" arg2:#"" arg3:3];
}
-(void) expand_combinations: (NSString *) remaining_string arg2:(NSString *)s arg3:(int) remain_depth
{
if(remain_depth==0)
{
printf("%s\n",[s UTF8String]);
return;
}
NSString *str = [[NSString alloc] initWithString:s];
for(int k=0; k < [remaining_string length]; ++k)
{
str = [s stringByAppendingString:[[remaining_string substringFromIndex:k] substringToIndex:1]];
[self expand_combinations:[remaining_string substringFromIndex:k+1] arg2:str arg3:remain_depth - 1];
}
return;
}
However, instead of outputting the results, I want to return them to an NSArray. How can this code be changed to do that? I need to use the information that this function generates in other parts of my program.
There are several things that you need to change in your code.
First - consider changing the name of your method to something more legible and meaningful than -expand_combinations:arg2:arg3.
Second - you have a memory leak. You don't need to set allocate memory and initialize str with the string s, because you change its value right away in the loop without releasing the old value.
Third - take a look at NSMutableArray. At the beginning of the method, create an array with [NSMutableArray array], and at every line that you have printf, instead, add the string to the array. Then return it.
basicaly you have:
create mutable array in viewDidLoad before [self expand_combinations ...
add aditional parameter (mutable array) to expand_combinations
populate array in expand_combinations

How to check a character array is null in objective C

How to check a character array is null in objective C?
char hName[255];
- (void)setHost {
phent = gethostbyaddr((const char*)&haddr, sizeof(int), AF_INET);
if(phent){
strncpy(hName,phent->h_name,255);
}
-(void) getHost {
NSString *str = [[NSString alloc] initWithBytes:tTemp.hName
length:sizeof(tTemp.hName) encoding:NSASCIIStringEncoding];
}
I have a character array named hName[255]. I will assign values to this array at some point of my project. Now i need to check if the hName[255] contains null value. i tried some methods. I get a string str from that array and check if it is equal to #""; It failed. Then i check the length of the string str. Even if the array contains no values it will return 255. How can i check the array contains null value. Any help? Thanks in advance!!
You might need to elaborate a bit on your question. For example, to just check if a pointer is null is pretty simple :
char *my_chars;
...
if (! my_chars)
NSLog(#"Woo, my_chars is null");
else
NSLog(#"my_chars is at 0x%08x", my_chars);
because null is just 0 :)
However, it doesn't look like that's your problem. you've created an array of characters like so
char my_chars[255];
so my_chars is not going to be null.
However, as outis says in his answer, you've just allocated it and not zeroed the contents so you have no idea what's in those 255 bytes! Out of the three options he suggests I'd personally go with this one :
char my_chars[255];
memset(my_chars, 0, sizeof(my_chars));
now, you have an array of 255 zeroes :) This is pretty easy to check to see if it's null :
if (0 == strlen(my_chars))
NSLog(#"It's not null but it is an empty string!");
else
NSLog(#"my_chars contains a valid string which is %i chars long", strlen(my_chars));
Hope that helps.
Sam
First thing, note that the word "null" is overloaded. You can have null pointers and null (empty) strings, and there's the null character ('\0', equal to 0 when converted to an int:((int)'\0') == 0). There are also uninitialized variables, which may or may not be null. I'm guessing you're talking about an uninitialized character array, used as a c-string.
Most likely, hName is being allocated on the stack (I can't tell without seeing more of the source code), which means it's not zero-initialized. Practically speaking, hName will hold whatever data was last stored in the region of memory that hName occupies. You'll need to initialize it yourself.
char hName[255] = {0};
// or
memset(hName, 0, sizeof(hName));
// or, if you have bzero
bzero(hName, sizeof(hName));
Also note that since hName is declared as an array rather than a pointer, sizeof(hName) is the number of characters it stores.
void test() {
char *name1 = "";
char name2[255];
// All the following lines will be true
strlen(name1) == 0;
sizeof(name2) == 255
0 <= strlen(name2) && strlen(name2) < 255;
// pointers are 4 or 8 bytes on most machines these days
sizeof(name1) == 4 || sizeof(name1) == 8;
}
Edit (addressing code sample):
The length of str in getHost is 255 because you tell it to have that length when you copy from tTemp.hName. NSStrings can contain nulls, though you may have difficulty printing them and any characters following.
It's not clear from the code sample if hName is a global (globals are bad) or a property. Similarly, the scope of the other variables, such as haddr and tTemp, is unclear. Some of those should be parameters to the methods.
The name "setHost" should be reserved for a setter–one of a pair of methods ("accessors", in Objective-C parlance) that get and set a property. They return and take (respectively) a type that's notionally the type of the property. In this case, NSString* makes the most sense; best to use an NSString in your code and switch to (via NSString's cStringUsingEncoding: or UTF8String). The partner to -(void)setHost:(NSString*) would be -(NSString*)host.
Once you make the switch to NSString (and use stringFromCString:withEncoding:), you can simply examine its length or compare it to #"" to check for an empty string.
#interface MyHost : NSObject {
NSString *name_;
...
}
/* post ObjC 2.0 */
#property(retain) NSString* name;
/* pre ObjC 2.0 */
-(NSString*)name;
-(void)setName:(NSString*);
/* any ObjC version */
-(int)setHostFromAddress:(MyAddress*)addr;
...
#end
#implementation MyHost
/* post ObjC 2.0 */
#synthesize name = name_;
-(int)setHostFromAddress:(MyAddress*)addr {
struct hostent *phost;
phost = gethostbyaddr(addr.address, addr.length, addr.type);
if (phost) {
self.name = [NSString stringWithCString:phost->h_hname encoding:NSASCIIStringEncoding];
}
return h_errno;
}
/* pre ObjC 2.0 */
-(NSString*)name {
return name_;
}
-(NSString*)setName:(NSString*)nom {
[name_ release];
name_ = [nom retain];
}
-(int)setHostFromAddress:(MyAddress*)addr {
struct hostent *phost;
phost = gethostbyaddr([addr address], [addr length], [addr type]);
if (phost) {
[self setName:[NSString stringWithCString:phost->h_hname encoding:NSASCIIStringEncoding]];
}
return h_errno;
}
...
#end