3

I have created an array like this

var outputReal = UnsafeMutablePointer<Double>.allocate(capacity: numeroDados)

Now I need to convert that to an array of Double.

I can convert that using something like this:

var newArray : [Double] = []

for i in 0..<n {
  newArray[i] = outputReal
}

But I remember seeing on a page another method of doing this.

Any ideas?

Jonathan Lam
  • 16,831
  • 17
  • 68
  • 94
Duck
  • 34,902
  • 47
  • 248
  • 470

3 Answers3

7

First create an UnsafeBufferPointer<Double> referencing the same memory area. That is a Collection so that you can create and initialize an array from that memory:

let bufPtr = UnsafeBufferPointer(start: outputReal, count: numeroDados)
let newArray = Array(bufPtr)

Alternatively, allocate an UnsafeMutableBufferPointer (which holds both the address and the size of the allocated memory) in the first place:

let numeroDados = 10

let outputReal = UnsafeMutableBufferPointer<Double>.allocate(capacity: numeroDados)
outputReal.initialize(repeating: 0.0)

let newArray = Array(outputReal)

In both cases the values are copied to the array's element storage, so you'll have to release the allocated memory eventually.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Brilliant! That's it! Do you know where I can read about this pointer/buffer safe/unsafe/mutable stuff that explains it well? Anyway thanks!!!!! – Duck Mar 31 '19 at 14:27
  • Thank you, you helped me realise that I never needed an `Array`, but rather a collection / `UnsafeMutableBufferPointer` over an `UnsafeMutablePointer`. This gets rid of an `Array` init followed by an unsightly redundant `withUnsafeMutableBytes`! – Rhythmic Fistman Aug 28 '19 at 20:50
6

Details

  • Xcode 11.2.1 (11B500), Swift 5.1

Solution 1

extension UnsafeMutablePointer {
    func toArray(capacity: Int) -> [Pointee] {
        return Array(UnsafeBufferPointer(start: self, count: capacity))
    }
}

Usage of the solution 1

var array = [3.9, 7.7, 11.1, 1.11, 1.02, 3.3, 3.9, 0]
let pointer = UnsafeMutablePointer<Double>.allocate(capacity: array.count)
pointer.initialize(from: &array, count: array.count)
print(pointer.toArray(capacity: array.count))

Solution 2

extension Array {
    init(pointer: UnsafeMutablePointer<Element>, count: Int) {
        let bufferPointer = UnsafeBufferPointer<Element>(start: pointer, count: count)
        self = Array(bufferPointer)
    }
}

Usage of the solution 2

var array2 = [3.9, 7.7, 11.1, 1.11, 1.02, 3.3, 3.9, 0]
let pointer2 = UnsafeMutablePointer<Double>.allocate(capacity: array.count)
pointer2.initialize(from: &array, count: array.count)
print(Array(pointer: pointer2, count: array.count))
Vasily Bodnarchuk
  • 24,482
  • 9
  • 132
  • 127
1

Do you mean to convert the Pointer to double to an Array of double??

You shouldn't cast a pointer to double to array of double in swift since array in swift is not necessarily the same as a C array. Instead, you copy the contents into the new array. A "low-level" way to do it is

var pointerToDoubles = UnsafeMutablePointer<Double>.allocate(capacity: 10)
var newArray = Array<Double>(repeating: 0, count: 10)
_ = newArray.withContiguousMutableStorageIfAvailable {
  UnsafeMutableRawPointer($0.baseAddress!).copyMemory(from: x, byteCount: MemoryLayout<double>.size * 10)
}

Please keep in mind this is not safe and will crash if you made some mistakes, for example your new array is too small or if your pointer don't not have as many elements you expecting.

Yuji
  • 74
  • 3