array of char * in objective c - objective-c

I have a c string and need it to break it up into lines (I wont make a NSString of them at this moment).
Is there something like an NSMutableArray where I can put this char * in?
Or how can I achieve it to make something from the strings what I can access later by index?
Currently I make
char *cline = strtok(data, "\n");
while(cline)
{
...
}
Or is it easier todo this when I read the file from disk?

Use an NSValue to store your char* in an NSMutableArray
Overview
An NSValue object is a simple container for a single C or Objective-C data item. It can hold any of the scalar types such as int, float, and char, as well as pointers, structures, and object ids. The purpose of this class is to allow items of such data types to be added to collections such as instances of NSArray and NSSet, which require their elements to be objects. NSValue objects are always immutable.

You cannot insert a C/C++ pointer into an NSMutableArray, unless it is wrapped in a container like an NSValue or other Objective-C class.
It would be a lot easier, if you want an NSMutableArray, to just convert it to an NSString.
NSArray* strings = [[NSString initWithCString:data encoding:NSUTF8StringEncoding] componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]];
Your other options, if you strictly want to stay in the C/C++ realm would be to have a vector of strings or an array of char*.

As others have already pointed out, to store primitive C types such as a in an Obj-C object such as an instance of NSMutableArray, you would need to wrap them in NSValue objects first.
As an alternative to doing this - if you are wanting to work with pure C strings in Obj-C, don't forget that you can freely mix C with Objective-C source code, so using a normal C array is a perfectly legitimate solution too.
By wrapping the values into an obj-c array you gain the bounds checking and mutability, but if you keep unwrapping the values to work on them as a C string, you might be better sticking with a plain old C string to begin with, to save the overhead.
If you then want to make an NSString, you can simply use the NSString convenience method stringWithFormat:, like so:
char str[50];
// read characters into the buffer from a file...
// When done, convert to an NSString:
NSString *string = [NSString stringWithFormat:#"%s", str];

Related

How to access a character in NSMutableString Objective-C

I have an instance of NSMutableString called MyMutableStr and I want access its character at index 7.
For example:
unsigned char cMy = [(NSString*) MyMutableStr characterAtIndex:7];
I think this is an ugly way; it's too much code.
My question is: Are there more simple ways in Objective-C to access the character in NSMutableString?
Like, in C language we can access a character of a string using [ ] operator:
unsigned char cMy = MyMutableStr[7];
The way of doing it is to use characterAtIndex:, but you don't need to cast it to a NSString pointer, since NSMutableString is a subclass of NSString. So it isn't that long, but if you still don't find it comfortable, I suggest to use UTF8String to obtain a C string over which you can iterate using the brackets operator:
const char* cString= [MyMutableStr UTF8String];
char first= cString[0];
But remember this (taken from NSString class reference):
The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.
As others said characterAtIndex: but a few things you might want to consider carefully.
First you're dealing with an mutable string. You want to be careful to avoid it changing out from under you. One way is to an immutable copy and use that for the op.
Second, you're dealing with Unicode so you may want to consider normalizing your string to get a precomposed form as some visual representations may be more than one actual unichar. That's often a stumbling block for folks.

Errors in trying to cast to NSInteger * and NSMutableArray *

I'm a newbie in obj c. So I have a simple question.
I have a matrix of NSInteger values. It is called "curBoard". I want to update value at (x,y) coordinates with value "curStep". I have an arror "operand of type void where arithmetic..."
What am I doing wrong ?
[curBoard replaceObjectAtIndex:x withObject:(NSMutableArray *)[[curBoard objectAtIndex:x] replaceObjectAtIndex:y withObject:(NSInteger *)[NSNumber numberWithInt:curStep]]];
Update:
NSMutableArray *board;
board = [NSMutableArray new];
for(NSInteger i = 0; i<boardSize; i++) {
NSMutableArray *row = [NSMutableArray new];
for(NSInteger j = 0; j < boardSize; j++)
[row addObject:(NSInteger *)[NSNumber numberWithInt:0]];
[board addObject:row];
}
This withObject:(NSInteger *)[NSNumber numberWithInt:curStep]] part is what causing an issue. If you are storing as NSNumber objects, you should just use:
... withObject:[NSNumber numberWithInt:curStep]]
Edit:
From the code posted above, you should add it as:
[row addObject:[NSNumber numberWithInt:0]];
NSInteger is not of pointer type and you should use NSNumber itself to add to array.
Objective-C is basically just a bunch of object syntax strapped to C. The overall effect is something like strapping a jetpack to a horse: sometimes the two parts don't really work together very well. In this case, you're trying to go faster by telling the horse to giddy up, when you should really be opening up the throttle.
NSMutableArray is part of the jetpack—it's an Objective-C object and is only equipped to handle arrays of Objective-C objects. But NSInteger is part of the horse—it's a primitive C integer type, not a real object.*
I know NSInteger is capitalized like a class and has an NS prefix like a class, but it's really a creature of C. You can confirm this yourself—type Cmd-O in Xcode and type "NSInteger" into the Open Quickly dialog that pops up, and you'll be able to jump to its definition. In my current Mac project, that's typedef long NSInteger;; long is one of the primitive C types.
NSNumber exists to bridge the two. It's an object specifically designed to hold the C numeric types inside it. Since NSNumber is an object, NSMutableArray and other Objective-C things can deal with it.
But you can't just cast between NSNumber and NSInteger. NSNumber holds an NSInteger inside it, but that doesn't mean it's actually an NSInteger itself. If you put a sandwich in a plastic bag, you can't eat the bag.
Instead, you have to use NSNumber's +numberWithInteger: method to construct an NSNumber, and -integerValue to get the integer back out of it. (+numberWithInt: and -intValue will usually work, but they may behave differently with very large values, depending on whether your app is running on a 32-bit or 64-bit processor.) Actually, nowadays you can say [NSNumber numberWithInteger:foo] as #(foo) instead, which is a lot shorter.**
So when you add a number, you should be saying:
[row addObject:#(0)];
And when you later want that number back, you'll want to say something like:
n = [[row objectAtIndex:y] integerValue];
The -replaceObjectAtIndex:withObject: error is a different story. -replaceObjectAtIndex:withObject: doesn't return anything at all, so you can't use it as an argument. Luckily, you don't need to in this case. -replaceObjectAtIndex:withObject: doesn't create a new array; it alters the array that's already inside [curBoard objectAtIndex:x], so you don't need to do anything to curBoard. Instead, you can just write:
[[curBoard objectAtIndex:x] replaceObjectAtIndex:y withObject:#(curStep)];
* You actually used NSInteger *, which is slightly different. The * means "pointer to", so NSInteger * is a pointer to a primitive integer. This is sort of like NSNumber *, a pointer to an NSNumber object, so the compiler allows you to cast it.
Note that casting a pointer doesn't convert the data at the other end of the pointer; it just makes the compiler interpret the same data in a different way. If you actually tried to use the NSInteger * pointer to get data, you would either get garbage data or (for reasons too large to fit within this margin) crash.
In this case, though, once you've Jedi mind-tricked the compiler into thinking that value is a pointer to an NSInteger, you try to pass it to to -addObject:. -addObject: expects a pointer to an object, so the compiler balks at passing a pointer to an NSInteger instead.
** This syntax will work as long as you're using the iOS 6 SDK Xcode 4.4 or later, even if you actually run the app on an older iOS. It will also automatically use the right +numberWithWhatever: method for you, so you don't have to worry about picking the best one. When you're using a numeric literal like 0, the parentheses are optional, but they're required when you use a variable or constant. Of course, you can still do it the wordy way if you want, but there's little point nowadays.

Storing NSMutableDictionary a C struct with a pointer to a link list

I have this C struct (allocated with malloc, thus in heap) I want to store in NSMutableDictionary, because I want to avoid re-creating the C struct which is a complicated process.
Usually with C struct I know I can use a NSData object to store the bits then put it in Objective-C containers such as NSArray and NSDictionary. However, the struct I want to save contains a pointer to a C link list, which is why I want to avoid re-creating. I'd rather just saving the pointer in a container like NSDictionary and fetch it when I need it.
The question is, what's the best way to be able to reuse the struct without re-creating it?
I'm thinking of storing the pointer to the struct themselves. Since pointer is really just a number, can I store it in NSNumber? If I can, what do I use? Unsigned long long?
Example: [NSNumber numberWithUnsignedLongLong:aPointer];
PS: This is for iPhone BTW.
A pointer is not a number (at least not in the sense of NSNumber). But it is a value. And in fact you can use [NSValue valueWithPointer:myPtr].

Using malloc to allocate an array of NSStrings?

Since NSSstring is not defined in length like integer or double, do I run the risk of problems allocating an array of NSStrings for it using malloc?
thanks
ie:
NSString ***nssName;
nssName = (NSString***) malloc(iN * sizeof(NSString*));
the end result with for_loops for the rows is a 2D array, so it is a little easier to work then NSArray(less code).
No problems should arise, allocating an array of NSStrings is like making an array of the pointers to string objects. Pointers are a constant length. I would recommend just using NSArray but it is still fine to use a C array of NSStrings. Note that this may have changed with ARC.
Here is completely acceptable code demonstarting this:
NSString** array = malloc(sizeof(NSString*) * 10); // Array of 10 strings
array[0] = #"Hello World"; // Put on at index 0
NSLog(#"%#", array[0]); // Log string at index 0
Since NSString is an object (and to be more precise: an object cluster) you cannot know its final size in memory, only Objective-C does. So you need to use the Objective-C allocation methods (like [[NSString alloc] init]), you cannot use malloc.
The problem is further that NSString is an object cluster which means you do not get an instance of NSString but a subclass (that you might not even know and should not care about). For example, very often the real class is NSCFString but once you call some of the methods that treat the string like a path you get an instance of NSPathStore2 or whatever). Think of the NSString init methods as being factories (as in Factory Pattern).
After question edit:
What you really want is:
NSString **nssName;
nssName = (NSString**) malloc(iN * sizeof(NSString*));
And then something like:
nssName[0] = #"My string";
nssName[1] = [[NSString alloc] init];
...
This is perfectly fine since you have an array of pointers and the size of pointer is of course known.
But beware of memory management: first, you should make sure the array is filled with NULLs, e.g. with bzero or using calloc:
bzero(nssName, iN * sizeof(NSString*));
Then, before you free the array you need to release each string in the array (and make sure you do not store autoreleased strings; you will need to retain them first).
All in all, you have a lot more pitfalls here. You can go this route but using an NSArray will be easier to handle.
NSStrings can only be dealt with through pointers, so you'd just be making an array of pointers to NSString. Pointers have a defined length, so it's quite possible. However, an NSArray is usually the better option.
You should alloc/init... the NSString*s or use the class's factory methods. If you need an array of them, try NSArray*.
You should not use malloc to allocate data for Objective-C types. Doing this will allocate memory space but not much else. Most importantly the object will not be initialized, and almost as importantly the retain count for the object will not be set. This is just asking for problems. Is there any reason you do not want to use alloc and init?

Char * vs NSString *

I am trying to get rid of some confusion when working with C.
Is using char *name in some sense the same as working with NSString *name in the sense that the pointer still points to the first memory allocation for it?
Ofcourse NSString has a bunch of extras but that isnt what I mean, will working with char *name allow me to work as if it was a NSString *name, so that I could in the future just work with the pointer "name" ?
The answer is no.
char* is meant to point to a simple array of (or single) char data values.
char* myCharPtr = "This is a string.";
//In memory: myCharPtr contains an address, e.g. |0x27648164|
//at address 0x27648164: |T|h|i|s| |i|s| |a| |s|t|r|i|n|g|.|\0|
On the other hand, NSString *name will be a pointer to an object which could have lots of extras, and you can't rely on where the actual character data is stored, or how. It is not encoded as ASCII (Sherm Pendley down below said it's UTF-16), and it could have extra data like the string's length, etc.
NSString* myStringPtr = #"This is an NSString.";
//In memory: myStringPtr contains e.g. |0x27648164|
//at address 0x27648164: |Object data|length|You don't know what else|UTF-16 data|etc.|
You alter and access unknown objects through their exposed methods because you don't know how they are formatted in memory, and thus can't access their data directly. (Or because they encapsulate themselves to hide it from you.)
You can still use the NSString pointer in future if you declare it as NSString *name though. This is what I mean:
NSString *name = #"This is a string.";
NSString *sameName = name; //This is pointing to the same object as name
NSLog(#"%#", sameName); //This prints "This is a string.", and if NSStrings were mutable, changing it would change name as well.
//They point to the same object.
char* and NSString* are two completely different implementations of strings.
NSString can only be used in Objective C (not in plain C), represents immutable strings, is based on Unicode characters and - being an object-oriented class - provides many methods. Furthermore, they are reference counted and always allocated on the heap.
char* is just any array of bytes, whose encoding is not well defined, it's mutable and it isn't object-oriented. char arrays can be allocated on the heap (with malloc) or on the stack. The former requires a call to free, while the latter must never be freed.
Is using char *name in some sense the
same as working with NSString *name in
the sense that the pointer still
points to the first memory allocation
for it?
I think you should regard the NSString* name as a handle to the object rather than a pointer to the object and as such not assume it points to the first memory allocation. I think that would be a better metaphor.
No,
char * is a pointer to an array of characters. NSString is a pointer to an NSString object. I cannot find any documentation of it, but I believe that NSString boxes a char *. Doing name[1] against NSString *name would refer to the 2nd element of an array of NSString objects.
In a sense - a somewhat non-useful sense, to be sure - they are the same, in that both are pointer types that refer to a memory address. That similarity turns out to be not very useful in practice though. To make use of either one, you have to take into account the type of "thing" they point to, and how one uses an array of char and an NSString instance is entirely different. Even for something as simple as assignment, one needs to handle the NSString instance in accordance to Cocoa's memory-management rules, using either -copy or -retain instead of a simple "foo = bar" assignment.