4

Sorry, I'm not even sure how to ask, since I'm a complete newbie at C, pointers and stuff like that. There's a function that accepts an argument: char **arg. If I write that argument like so:

char *cargs[] = {"blah", NULL};

and pass it to the function:

function(cargs);

it works. but ... I have an NSArray of NSStrings and I need to make this array out of values from NSArray. I figured it should be a matter of creating a C array of the same element count as NSArray and copy the strings, converting them with cStringUsingEncoding. But I honestly have no idea how to do this, since I get confused with all those pointers and such. Any help would be appreciated.

2 Answers 2

6

Well, the rough steps can be:

  1. use count method of NSArray to know how many NSStrings are there in the NSArray.

  2. use malloc to allocate memory for cargs, something like this

    char **cargs = (char **) malloc(sizeof(char *) * count);
    

    by your example, you may need to one more room for NULL which will be at the end of cargs.

  3. use a loop and objectAtIndex: of NSArray to get out the NSStrings, like NSString *nsstring = [array objectAtIndex:index];

  4. use method cStringUsingEncoding: to get the c-string out, better make a copy

  5. put these c-string pointers in cargs

  6. pass cargs to your function, clean and free things needed to.

It's a lot of work. 'Cause the mix of c and obj-c stuff. And a lot of manual malloc and free , messy stuff. Can't you avoid it?

--add sample code--

I'm not quite sure what your real intent is. Hope this will help.

void func(char **arg)
{
    int i;
    for(i = 0; arg[i] != NULL; i++) {
        printf("%d=%s\n", i, arg[i]);
}
}
int main(int argc, const char *argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    NSString *s1 = [NSString stringWithString:@"first"];
    NSString *s2 = [NSString stringWithString:@"second"];
    NSString *s3 = [NSString stringWithString:@"third"];

    NSArray *array = [NSArray arrayWithObjects: s1, s2, s3, nil];
    //by now, we have an NSArray of three NSStrings

    int count = [array count];
    char **cargs = (char **) malloc(sizeof(char *) * (count + 1));
    //cargs is a pointer to 4 pointers to char

    int i;
    for(i = 0; i < count; i++) {
        NSString *s = [array objectAtIndex:i];//get a NSString
        const char *cstr = [s cStringUsingEncoding:NSUTF8StringEncoding];//get cstring
        int len = strlen(cstr);//get its length
        char *cstr_copy = (char *) malloc(sizeof(char) * (len + 1));//allocate memory, + 1 for ending '\0'
        strcpy(cstr_copy, cstr);//make a copy
        cargs[i] = cstr_copy;//put the point in cargs
    }
    cargs[i] = NULL;

    func(cargs);//call the function to do something

    for(i = 0; i < count; i++) {
        free(cargs[i]);
    }
    free(cargs);

    [pool drain];
    return 0;
}
Sign up to request clarification or add additional context in comments.

11 Comments

Why send lengthOfBytesUsingEncoding:? cStringUsingEncoding: will automatically create a string of the right length; indeed, you can't tell it to use a different length.
Well, i'd be glad to avoid it, but i'm using AuthorizationExecuteWithPrivileges to run a shell script with elevated privileges and i don't know any other way to do it.
char* arg; arg = (char *)malloc([a count] + 1); for (int i = 0; i < [a count]; i++) { arg[i] = [[a get:i] cStringUsingEncoding:NSUTF8StringEncoding][0]; } arg[[a count]] = 0; This is what i've come up with with the help of my friend, but it breaks the AuthorizationExecuteWithPrivileges ... How do i format the code in the comment? :(
Well, the problem actually is ... how do i assign a cString to that array's element? I've tried: arg[1] = "test" - works. *arg[1] = [@"test" cStringUsingEncoding:NSUTF8StringEncoding][0]; - doesn't work
Marius: cStringUsingEncoding: returns a C string. A C string is an array of characters (char), ending with a zero byte ('\0'); cStringUsingEncoding: returns the address of that array of characters. Saying […cStringUsingEncoding:…][0] takes the first char in the array—the first character of the C string. Don't try to access a specific character of the string; set arg[i] to the pointer to the whole string, as returned by cStringUsingEncoding:.
|
1

@yehnan your answer is GREAT - especially because I thought that const ** cStyle[arrays] were NOT able to be created dynamically... (I really wish there was somewhere with just basic information about C pointers and variables and crap... I find the most basic "C primitives" to be far more bewildering than anything else...) Here's your nice little example "bundled up" into a function... "for the children..."

char ** cArrayFromNSArray ( NSArray* array ){
   int i, count = array.count;
   char **cargs = (char**) malloc(sizeof(char*) * (count + 1));
   for(i = 0; i < count; i++) {        //cargs is a pointer to 4 pointers to char
      NSString *s      = array[i];     //get a NSString
      const char *cstr = s.UTF8String; //get cstring
      int          len = strlen(cstr); //get its length
      char  *cstr_copy = (char*) malloc(sizeof(char) * (len + 1));//allocate memory, + 1 for ending '\0'
      strcpy(cstr_copy, cstr);         //make a copy
      cargs[i] = cstr_copy;            //put the point in cargs
  }
  cargs[i] = NULL;
  return cargs;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.