Convert a Swift Array of String to a to a C string array pointer

前端 未结 2 984
走了就别回头了
走了就别回头了 2020-12-04 01:42

I\'m on Swift 3, and I need to interact with an C API, which accepts a NULL-terminated list of strings, for example

con         


        
2条回答
  •  醉梦人生
    2020-12-04 02:48

    This class provides a pointer that works with char** and automatically deallocates the memory, even though it's a struct (using a little trick with a mapped data with deallocator).

    public struct CStringArray {
        public let pointer: UnsafeMutablePointer?>
        public let count: Int
        private var data: Data
    
        public init(_ array: [String]) {
            let count = array.count
    
            // Allocate memory to hold the CStrings and a terminating nil
            let pointer = UnsafeMutablePointer?>.allocate(capacity: count + 1)
            pointer.initialize(repeating: nil, count: count + 1)  // Implicit terminating nil at the end of the array
    
            // Populate the allocated memory with pointers to CStrings
            var e = 0
            array.forEach {
                pointer[e] = strdup($0)
                e += 1
            }
    
            // This uses the deallocator available on the data structure as a solution to the fact that structs do not have `deinit`
            self.data = Data(bytesNoCopy: pointer, count: MemoryLayout>.size * count, deallocator: .custom({_,_ in
                for i in 0...count - 1 {
                    free(pointer[i])
                }
                pointer.deallocate()
            }))
    
            self.pointer = pointer
            self.count = array.count
        }
    
        public subscript(index: Data.Index) -> UnsafeMutablePointer? {
            get {
                precondition(index >= 0 && index < count, "Index out of range")
                return pointer[index]
            }
        }
    
        public subscript(index: Data.Index) -> String? {
            get {
                precondition(index >= 0 && index < count, "Index out of range")
                if let pointee = pointer[index] {
                    return String(cString: pointee)
                }
    
                return nil
            }
        }
    }
    

提交回复
热议问题