Sizeof C array with integers (in Obj-C) - objective-c

myclass.h:
#define BUTTON_NAVI 41;
#define BUTTON_SETTINGS 42;
#define BUTTON_INFO 43;
myclass.m:
int btnNavi = BUTTON_NAVI;
int btnSettings = BUTTON_SETTINGS;
int btnArray[2] = {btnNavi, btnSettings};
NSLog(#"count = %i", sizeof(btnArray));
[self addToolbarButtons:btnArray];
-> Log: count = 8
8?! What did I do wrong?
And inside "addToolbarButtons" count is 4... :-(
EDIT:
- (void)addToolbarButtons:(int[])buttonIdArray {
NSLog(#"count = %i", sizeof(buttonIdArray));
}
-> Log: count = 4

sizeof is giving you the size in bytes, 8 bytes sounds right for 2 integers (32-bit or 4 bytes each).
If what you want is the length of the array, you can do sizeof(arr) / sizeof(arr[0]) which will give you the size of the entire array divided by the size of each element. In this case you will get 8 / 4 == 2, which is what I take it you expect.
EDIT
To answer your second question, when you pass the array to the method, you're actually passing a pointer to the array. Hence, the size of the pointer is also 32-bits or 4 bytes. If you want the function to know the length of the array, you need to also pass its length along with said pointer.

sizeof is giving the size of the array in bytes. An int is 4 bytes, so a 2-element array of ints will be 8 bytes.
However, sizeof won't do what you want in your method. When a C array is passed into a function (or method), it actually get passed as a pointer, and sizeof will return the size of a pointer. You should modify your method to take a length parameter:
- (void)addToolbarButtons:(int *)buttonIdArray length:(size_t)len
{
NSLog(#"count = %d", len);
}

The sizeof operator gives you the size in bytes of the thing you pass to it. If an int is 4 bytes, then an array of two ints is 8 bytes.
However, sizeof is a compile-time check on the variable itself. At runtime, the bounds of an array are not known — nor are they known outside the scope where the variable was defined. When you declare the argument (int[])buttonIdArray, the compiler desugars that to (int *)buttonArray — it's just a plain int pointer. So when you do sizeof(buttonArray), it tells you the size of a pointer, 4.
Because the language doesn't keep track of their size for you, using C arrays is a pain. You have to pass the number of elements in the array to every function and method that acts on it.

Related

Is this conversion valid?

I've the code in Java where p1 is an object of Pixel class which accesses an array pixels and assigns it the value (at right side) at the proper index. R G and B are some int values.
p1.pixels[index] = 0xff000000 | (R << 16) | (G << 8 ) | B;
I'm converting this code in Objective C as follows.But I don't know whether I have to mention the object name (insert object at p1.pixels) or inserting object at pixels does the same?
int newNumber = 0xff000000 | (R << 16) | (G << 8 ) | B;
NSNumber *yourNumber = [NSNumber numberWithInt:newNumber];
[pixels insertObject:yourNumber atIndex:index];
NSArrays don't have a hard size limit like Java arrays do. They fill from the front, don't have default values (null in Java), and don't allow you to insert to an arbitrary location. The only way that the
[pixels insertObject:yourNumber atIndex:index];
line is safe is if there are greater than or equal to yourNumber elements already in the array.
If you really need that object to exist at a certain index, you should either fill the earlier positions with the other pixel values or a placeholder object like [NSNull null]
Also, int has different sizes on different Macs and iOS devices. If you want a specific sized integer, you should use one of the types like uint32, which is guaranteed to be 32-bits on every machine.
I think if you're manipulating pixels like this you're better off (in terms of performance and memory) to stick to plain-old-C.
If you wanted to create an UIImage object from the pixel data then you would use a buffer allocated using malloc(); for example (code taken from here - see the question for the rest of the code):
char* rgba = (char*)malloc(width*height*4);
for(int i=0; i < width*height; ++i) {
rgba[4*i] = buffer[3*i];
rgba[4*i+1] = buffer[3*i+1];
rgba[4*i+2] = buffer[3*i+2];
rgba[4*i+3] = 255;
}
Note that this is a byte buffer, not a uint32_t buffer, so adjust accordingly.
Using an NSArray populated with NSNumber objects will be much slower and take up much more space.

Converting long to byte array

I have java code:
Long long_value = 1;
ByteBuffer.allocate( 8).putLong( long_value).array();
I have result arrays of bytes: 0, 0, 0, 0, 0, 0, 0, 1 (in this order).
Please how correct port this code to Objective C?
Preamble
You say "in this order". When a multi-byte value is stored in memory the bytes can be stored big-endian - the most significant byte first, or little endian - the least significant byte first. For example the 2-byte hex value 0x1234 is stored as 0x12, 0x34 big-endian and 0x34, 0x12 little-endian. The endian order depends on the computer architecture in use, for example the Intel x86 is little-endian.
ByteBuffer is a Java class which stores values as byte according to its own endian flag, independent of the underlying hardware's endian order. The default setting of ByteBuffer is big-endian. In your sample you do not set this flag and the array you show is in big endian order.
Apple provides the functions described in Byte Order Utilities Reference for manipulating endian order. The function you need is CFSwapInt64HostToBig which takes a 64-bit signed or unsigned int in whatever endian order the host uses and returns an integer with the bytes arranged in big-endian order - the numeric value of the result is effectively meaningless at this point, it is an ordered collection of 8 bytes.
You also say you want 8 bytes, but a long may not be 8 bytes long - that depends on the hardware architecture, language and compiler. For example for OS X they are 8 bytes when compiling for 64-bit. There are two ways to address this, you can use the sizeof standard function which returns the number of bytes in a value or a type, you pass it a variable or a type name; or you can use the pre-defined sized types when you need a particular number of bytes, for example SInt64 is the pre-defined 8-byte signed integer type.
Finally you say you want an "array", but what kind of array? Objective-C/Cocoa has two: C language value arrays, and Objective-C object arrays NSArray and its mutable sibling NSMutableArray.
C language arrays: in C the name of an array variable is of type "pointer to element type", e.g. for the declaration float values[8] the type of values is float *. This means that pointers can be used as arrays, but they are not the same thing - a pointer variable holds a pointer to memory but does not allocate memory to point to, an array declaration allocates memory for its elements.
C Array
How to get a C "array" of bytes in big-endian order:
SInt64 long_value = 0x123456789ABCDEF; // use SInt64 rather than long
UInt64 BE_value = CFSwapInt64HostToBig(long_value); // use UInt64 as this value may not make numeric sense any more
UInt8 *BE_ptr = (UInt8 *)&BE_value; // UInt8 is a byte, take the address of BE_value
// BE_ptr is now a pointer to the 8 bytes of memory occupied by BE_value
// it can be treated as an array
// print it out to demo
for (int ix = 0; ix < 8; ix++)
{
NSLog(#"%d: %2x", ix, BE_ptr[ix]);
}
This will print out 12, 34 etc.
Objective-C array
You can build this on the above. You cannot store a byte directly in an Objective-C object, you must wrap it up as an object using NSNumber, and #() is a shorthand to do that:
SInt64 long_value = CFSwapInt64HostToBig(0x123456789ABCDEF);
UInt8 *BE_ptr = (UInt8 *)& long_value;
NSMutableArray *BE_array = [NSMutableArray arrayWithCapacity:8]; // create an object array
for (int ix = 0; ix < sizeof(long); ix++)
{
[BE_array addObject:#(BE_ptr[ix])]; // #(...) creates an NSNumber
}
NSLog(#"array: %#", BE_array);
This will print out the array (in decimal).
HTH
You could use a char pointer (chars are the same size as a byte, usually).
unsigned char *p = (unsigned char *)&myLong;
char byte1 = p[0];
char byte2 = p[1];
//etc...

How to return a C-style array of integers in Objective-C?

How to return a C-style array of integers from an Objective-C method? This is what my code looks like so far:
Function call:
maze = [amaze getMaze];
Function:
-(int*) getMaze{
return maze;
}
I just started writing in Objective-C today so this is all new to me.
In C if you need to return an array from a function, you need to allocate memory for it using malloc and then return the pointer pointing to the newly allocated memory.
Once you're done working with this memory you need to free it.
Something like:
#include <stdlib.h> /* need this include at top for malloc and free */
int* foo(int size)
{
int* out = malloc(sizeof(int) * size); /* need to get the size of the int type and multiply it
* by the number of integers we would like to return */
return out; /* returning pointer to the function calling foo().
* Don't forget to free the memory allocated with malloc */
}
int main()
{
... /* some code here */
int* int_ptr = foo(25); /* int_ptr now points to the memory allocated in foo */
... /* some more code */
free(int_ptr); /* we're done with this, let's free it */
...
return 0;
}
This is as C style as it gets :) There are probably other (arguably more suitable) ways to do this in Objective C. However, as Objective C is considered a strict superset of C, this would also work.
If I may further expand on the need to do this by pointers. C-style arrays allocated in a function are considered local, once the function is out of scope they are automatically cleaned up.
As pointed out by another poster, returning a standard array (e.g. int arr[10];) from a function is a bad idea as by the time the array is returned it no longer exists.
In C we get around this problem by allocating memory dynamically using malloc and having a pointer that points to that memory returned.
However unless you free this memory adequately, you may introduce a memory leak or some other nasty behavior (e.g. free-ing a malloc-ed pointer twice will produce unwanted results).
Given you explicitly ask about C-style arrays no suggestions here that you should use NSArray etc.
You cannot return a C-style array directly (see below) as a value in Objective-C (or C or C++), you can return a reference to such an array.
Types such as int, double and struct x can all be passed by value - that is the actual bits representing the value are passed around. Other things; such as C-style arrays, dynamically allocated memory, Objective-C style objects, etc.; are all passed by reference - that is a reference to a location in memory that contains the actual bits the represent the value is passed around.
So to return a C-style array from a function/method you can:
Dynamically (malloc et al) an array and return the reference to the allocated memory;
Pass in a reference to an already existing array and have the function fill it up; or
Wrap the array up as a struct...
The normal choices are (1) or (2) - note you cannot return a reference to a stack allocated array, as in:
int *thisIsInvalid()
{
int myValues[5];
...
return myValues; // will not work, the type is correct but once function
// returns myValues no longer exists.
}
If you really want to return a (small) array by value you can actually do it using (3). Remember that struct values are passed by value. So the following will work:
typedef struct
{
int array[5];
} fiveInts;
fiveInts thisIsValid()
{
fiveInts myValues;
...
myValues.array[3] = ...; // etc.
...
return myValues;
}
(Note that there is no overhead from wrapping the array inside a struct when it comes to reading/writing the array - the cost in the above is copying all the values back - hence only advised for small arrays!)
HTH
- (NSArray *)toArray:(int *)maze {
NSMutableArray *retVal = [[NSMutableArray alloc] init];
for (int c = 0; maze[c] != NULL; c++) {
[retVal addObject:[NSNumber numberWithInt:maze[c]]];
}
return [retVal array];
}
I've never been comfortable passing mutable data in and out of methods and not sure why. If you need to change the values later, send the array a mutableCopy message.
you can do it in this way
- (void)getArray:(int *)array withLength:(NSUInteger)length{
for (int i = 0; i < length; i++)
array[i] = i;
}
int array[3];
[object getArray:array withLength:3];
NSLog(#"%d %d %d", array[0], array[1], array[2]); // 1 2 3

Creating an array of ints whose size is based on the size of an NSArray

I'm trying to create and zero an array of ints based on a size that I get at runtime:
size = [gamePiece.availableMoves.moves count]; //debugger shows size = 1;
int array[size]; //debugger shows this as int[0] !
memset(array, 0, size);
indexes = array;
size and indexes are both ivars of this class:
int size;
int* indexes;
I end up with a 0-length array, though. How can I create it with the size indicated by [gamePiece.availableMoves.moves count]?
First of all, you can't do what you're doing. Even when this works, the array is going to disappear when the method returns and the current stack frame is removed. You need to dynamically allocate the array, then you need to remember to free it when your object is deallocated. So:
size = [gamePiece.availableMoves.moves count];
indexes = calloc(size, sizeof(int));
Then, in your -[dealloc] method:
if( indexes ) free(indexes);
Using calloc(3) will ensure that all the memory is zeroed out, so you don't need to call memset(3).
Array size should be a constant integral expression. You need to use malloc.
int *array = malloc( sizeof(int) * size ) ;
Now, you can normally access elements by index operator [].

Problem while converting NSData to int

Using foundation and cocoa frameworks on Mac, I am trying to convert an NSData object in humanly understandable number.
Let say the NSData object is an image of NPIXEL. I know the binary data are coded in big endian and represent 32 bit integer (to be more precise 32 bit two complements integer). I write the piece of code bellow to convert the NSData into an int array. But the value I got are completely wrong (this does not means the measurement are bad, I used a special software to read the data and the value given by the software are different from the one I got with my code).
-(int *) GetArrayOfLongInt
{
//Get the total number of element into the Array
int Nelements=[self NPIXEL];
//CREATE THE ARRAY
int array[Nelements];
//FILL THE ARRAY
int32_t intValue;
int32_t swappedValue;
double Value;
int Nbit = abs(BITPIX)*GCOUNT*(PCOUNT + Nelements); Nbit/=sizeof(int32_t);
int i=0;
int step=sizeof(int32_t);
for(int bit=0; bit < Nbit; bit+=step)
{
[Img getBytes:&swappedValue range:NSMakeRange(bit,step)];
intValue= NSSwapBigIntToHost(swappedValue);
array[i]=intValue;
i++;
}
return array;
}
This piece of code (with minor change) work perfectly when the binary data represent float or double, but I dont when it is 16,32 or 64 bit integer. I also tried changingNSSapBigIntToHostintoNSSwapLittleInttoHost`. I even tried with long, but the results is still the same, I got bad values. What wrong I am doing ?
PS: Some of the variable in my code are already set elsewhere in my program. BITPIX is the bit size of each pixel. In this case 32. GCOUNT is equal to 1, PCOUNT 0 and Nelements is the total number of pixel I should have in my image.
Returning a pointer to a local variable is a very bad idea. array could get overwritten at any time (or if you were to write through the pointer, you could corrupt the stack). You probably want something like:
// CREATE THE ARRAY
int *array = malloc(Nelements * sizeof(int));
Your algorithm seems a bit overkill, too. Why not just copy out the whole array from the NSData object, and then byteswap the entries in place? Something like:
int32_t length = [Img length];
int32_t *array = malloc(length);
[Img getBytes:array length:length];
for (i = 0; i < length/sizeof(int32_t); i++)
{
array[i] = NSSwapBigIntToHost(array[i]);
}