2013-08-18 53 views
0

我初始化像這樣存儲的UIImage像素數據轉換成C數組,無法確定數組的元素計數

CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, bounds); 
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
NSUInteger width = CGImageGetWidth(imageRef); 
NSUInteger height = CGImageGetHeight(imageRef); 
unsigned char *rawData = malloc(height * width * 4); 
NSUInteger bytesPerPixel = 4; 
NSUInteger bytesPerRow = bytesPerPixel * width; 
NSUInteger bitsPerComponent = 8; 
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 

然而,當我試圖檢查通過的NSLog計數陣列,總是得到4(4/1 ,具體而言)。

int count = sizeof(rawData)/sizeof(rawData[0]); 
NSLog(@"%d", count); 

但是,當我NSLog單個元素的值,它返回非零值。

ex。
CGFloat f1 = rawData[15];

CGFloat f2 = rawData[n],其中nimage width*height*4;

//我沒想到這個工作,因爲最後一個元素應該是N-1

最後,我想

int n = lipBorder.size.width *lipBorder.size.height*4*2; //lipBorder holds the image's dimensions, I tried multiplying by 2 because there are 2 pixels for every CGPoint in retina 
CGFloat f = rawData[n]; 

這將每次返回不同的值相同的圖像, (例如0.000,115.000,38.000)。

如何確定計數/數值如何存儲到數組中?

回答

1

rawData是一個指向無符號字符的指針,因此它的大小是32位(4字節)[1]rawData[0]是一個無符號字符,因爲它的大小是8位(1字節)。因此,4/1

你可能已經看到了這一點與數組之前完成,如果它確實工作,你所期望的:

unsigned char temp[10] = {0}; 
NSLog(@"%d", sizeof(temp)/sizeof(temp[0])); // Prints 10 

但是請注意,你是在處理一個指針爲unsigned char,而不是數組 unsigned char - 語義不同,因此爲什麼這在你的情況下不起作用。

如果你想要緩衝區的大小,只需使用height * width * 4就好多了,因爲這就是你傳給malloc的東西。如果你真的必須這樣做,你可以用sizeof(char)sizeof(rawData[0])除以得到元素的數量,但因爲它們是字符,所以無論如何你都會得到相同的數字。

現在,rawData只是一塊內存的某個地方。在它之前和之後還有其他記憶。因此,如果您嘗試執行類似rawData[height * width * 4]的操作,您實際上正在嘗試訪問內存的下一個字節,分配給rawData的塊。這是未定義的行爲,並可能導致隨機垃圾值被返回[2](如您所見),某些「未分配的內存」標記值正在返回或發生分段錯誤。


[1]:iOS的是一個32位的平臺
[2]:可能的任何值放入它被合法地使用最後一次存儲位置。

+0

好的,但爲什麼我得到寬*高* 4的值? – Mahir

+0

@馬希爾:我不確定我是否遵守。用'n'的參數調用'malloc'就意味着「給我分配內存的n個字節」。如果你從'malloc'得到一個有效的指針,你可以放心,它指向一塊(至少)'n'字節的內存。在你的情況下,你可以使用'height * width * 4'的'n'來調用'malloc'並獲得一個有效的指針,所以你知道'rawData'的長度必須是'height * width * 4'字節。無需任何其他間接手段來確定其大小。 – Mac

+0

對不起,我認爲參數是元素的數量,而不是內存大小。但是,如果每個元素都是1個字節,它們會不會像你所說的一樣嗎? – Mahir

0

malloc返回的指針是一個void *指針,這意味着它返回一個指向內存地址的指針。看起來被返回的寬度和高度都是0.這可以解釋爲什麼你只能爲你的數組分配4個字節。

你也說你試過

int n = lipBorder.size.width *lipBorder.size.height*4*2; //lipBorder holds the image's dimensions, I tried multiplying by 2 because there are 2 pixels for every CGPoint in retina 
    CGFloat f = rawData[n];  

,每次都收到不同的值。考慮到你的數組只有4個字節長,並且你正在訪問內存領域更遠的內存區域,所以這種行爲是可以預料的。值改變的原因是您正在訪問不在陣列中的內存,但在內存位置 lipBorder.size.width *lipBorder.size.height*4*2 - 4字節通過陣列的末尾。 C絕不會阻止您訪問程序中的任何內存。如果您訪問的內存超出了您的程序範圍,那麼您將收到分段錯誤。

因此您可以訪問n + 1n + 2或元素。這隻意味着你正在訪問傳遞數組尾部的內存。

遞增指針rawdata會將內存地址移動一個字節。遞增和int指針會遞增移動內存地址4個字節(sizeof(int))。