0

I have an NSArray<NSString*>* object, and I need to invoke a C API which takes in an array of strings as char**.

What's the best way to do this? The important note is the c-strings must not have a const modifier, so something like the following isn't good enough since UTF8String returns const char*:

NSArray<NSString*>* names = ...;
int len = args.count;
char* cNames[len];
for( int i = 0; i < len; i++ ) {
    cNames[i] = names[i].UTF8String;
};
5
  • Will the C API change the content of the strings? Commented Sep 23, 2016 at 1:35
  • I do not believe so, but in theory it could. Commented Sep 23, 2016 at 1:45
  • 1
    If it does, nothing will make that modify the original NSArray. The above is basically the right approach. You just want to add the tedious malloc and strncpy to create a full copy. The answer is: the above, plus C. Commented Sep 23, 2016 at 2:09
  • 1
    Don't know where your strings are coming from, but be aware of multi-byte "characters" in these emoji-filled times. If your C API is not Unicode-aware and your strings are not ASCII-except-in-name you'll get strange results. Commented Sep 23, 2016 at 2:37
  • Good point, I may need to use the platform specific encoding. Commented Sep 23, 2016 at 3:19

1 Answer 1

1

You will want to do some dynamic memory as you cannot rely on the backing memory for UTF8String being released.

NSArray *strings = @[ @"String 1", @"Other string", @"Random String"];
char **cStrings = NULL;
NSInteger numCStrings = strings.count;

if (numCStrings) {
    cStrings = (char **)calloc(numCStrings, sizeof(char*))  ;

    if (cStrings) {
        // Safer to allocate memory for each string

        for (NSInteger i=0;i<numCStrings;i++) {
            NSString *nsString = strings[i];
            char *cString = (char *)malloc([nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding] + 1); // + 1 for \0

            if (cString) {
                strcpy(cString, nsString.UTF8String);
                cStrings[i] = cString;
            } else {
                // You should handle your error
            }
        }
    } else {
        // You should handle your error
    }
}

for (NSInteger i=0;i<numCStrings;i++) {
    NSLog(@"C-String (%ld): %s", i, cStrings[i]);
}

// Note you need to free your memory later!
// Do any additional setup after loading the view, typically from a nib.
for (NSInteger i=0;i<numCStrings;i++) {
    if (cStrings[i]) {
        // Free each string
        free(cStrings[i]);
    }
}

// Free the array
free(cStrings);

cStrings = NULL;
numCStrings = 0;
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Ugly but I guess it will have to do!
One minor correction - nsString.length returns the length in the UTF-16 encoding. Need to use [nsString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]

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.