How can I specify that a method should take as parameter a pointer to a location in memory that can hold a specified number of values? For example, if I have:
- (void)doSomethingWith:(int *)values;
I'd like to make it clear that the int * passed in should point to an allocated space in memory that's able to hold 10 such values.
To directly answer your question, use an array argument with a bounds, e.g.:
- (void)takeTenInts:(int[10])array
Which specifies that the method takes an array of 10 integers.
Only problem is the C family of languages do not do bounds checking, so the following is valid:
int a[10], b[5];
[self takeTenInts:a]; // ok
[self takeTenInts:b]; // oops, also ok according to the compiler
So while you are specifying the size, as you wish to do, that specification is not being enforced.
If you wish to enforce the size you can use a struct:
typedef struct
{
int items[10];
} TenInts;
- (void)takeTenInts(TenInts)wrappedArray
Now this doesn't actually enforce the size at all[*], but its as close a you can get with the C family (to which the word "enforcement" is anathema).
If you just wish to know the size, either pass it as an additional argument or use NSArray.
[*] It is not uncommon to see structures in C following the pattern:
typedef struct
{
// some fields
int data[0];
} someStruct;
Such structures are dynamically allocated based on their size (sizeof(someStruct)) plus enough additional space to store sufficient integers (e.g. n * sizeof(int)).
In other words, specifying an array as the last field of a structure does not enforce in anyway that there is space for exactly that number of integers; there may be space for more, or fewer...
Why use "(int *)" when you have the power (and "count") of "NSArray" to work with?
But anyways, looking at this potentially related question, couldn't you just do a "sizeof(values)" to get the size of a statically/globally allocated pointer?
If that doesn't work (which would be in the case of a dynamically allocated array), you really would probably need some kind of "count:" parameter in your "doSomethingWith:" method declaration.
There are a several ways. You could just name the method appropriately:
- (void)doSomethingWithTenInts:(int *)tenInts;
Or you could use a struct:
typedef struct {
int values[10];
} TenInts;
- (void)doSomethingWithTenInts:(TenInts *)tenInts;
Or you could make the user tell you how many ints he is giving you:
- (void)doSomethingWithInts:(int *)ints count:(int)count;
Related
I'm trying to do the following, but NSValue's creation method returns nil.
Are C bitfields in structs not supported?
struct MyThingType {
BOOL isActive:1;
uint count:7;
} myThing = {
.isActive = YES,
.count = 3,
};
NSValue *value = [NSValue valueWithBytes:&myThing objCType:#encode(struct MyThingType)];
// value is nil here
First and foremost, claptrap makes a very good point in his comment: why bother using bitfield specifiers (which are mainly used to either do micro-optimization or manually add padding bits where you need them), to then wrap it all up in an instance of NSValue).
It's like buying a castle, but then living in the kitchen to not ware out the carpets...
I don't think it is, a quick canter through the apple dev-docs came up with this... there are indeed several issues to take into account when it comes to bit fields.
I've also just found this, which explains why bit-fields + NSValue don't really play well together.
Especially in cases where the sizeof a struct can lead to NSValue reading the data in an... shall we say erratic manner:
The struct you've created is padded to 8 bits. Now these bits could be read as 2 int, or 1 long or something... From what I've read on the linked page, it's not unlikely that this is what is happening.
So, basically, NSValue is incapable of determining the actual types, when you're using bit fields. In case of ambiguity, an int (width 4 in most cases) is assumed and under/overflow occurs, and you have a mess on your hands.
Since the compiler still has some liberty as to where what member is actually stored, it doesn't quite suffice to pass the stringified typedef sort of thing (objCType: #encode(struct YourStruct), because there is a good chance that you won't be able to make sense of the actual struct itself, owing to compiler optimizations and such...
I'd suggest you simply drop the bit field specifiers, because structs should be supported... at least, last time I tried, a struct with simple primitive types worked just fine.
You can solve this with a union. Simply put the structure into union that has another member with a type supported by NSValue and has a size larger than your structure. In your case this is obvious for long.
union _bitfield_word_union
{
yourstructuretype bitfield;
long plain;
};
You can make it more robust against resizing the structure by using an array whose size is calculated at compile time. (Please remember that sizeof() is a compile time operator, too.)
char plain[(sizeof(yourstructuretype)/sizeof(char)];
Then you can store the structure with the bitfield into the union and read the plain member out.
union converter = { .bitfield = yourstructuretypevalue };
long plain = converter.plain;
Use this value for NSValue instance creation. Reading out you have to do the inverse way.
I'm pretty sure that through a technical correctum of C99 this became standard conforming (called type punning), because you can expect that reading out a member's value (bitfield) through another members value (plain) and storing it back is defined, if the member being read is at least as big as the member being written. (There might be undefined bits 9-31/63 in plain, but you do not have to care about it.) However it is real-world conforming.
Dirty hack? Maybe. One might call it C99. However using bitfields in combination with NSValue sounds like using dirty hacks.
I have seen this question and its answers and they clear up some of my confusion, but I'm still concerned about a couple things:
Consider this:
int someCArray[5]={1,2,3,4,5};
[self processingTheArray:someCArray];
The method is described as:
-(void)processingTheArray:(int)theCArray;
Now, the above works, even though I gather it is not the right way to do it. It does provide a compiler warning: Incompatible pointer to integer conversion. Need I be concerned since this is working anyway?
Using the method in the above linked SO question, I could do this:
-(void)processingTheArray:(int)theCArray size:(NSUInteger)length;
However, what do I do with length inside processingTheArray?
someCArray is of type int*, not Byte*. int and Byte are different sizes, and are incompatible.
By changing your method to -(void)processingTheArray:(int*)theCArray;, it will work without warning.
However, the method takes your array in as a pointer, and it does not know if theCArray includes one int, 5 ints, or 500 ints inside. Unless the array is always the exact same length, you want a length parameter to specify the array size, so inside the method, you can loop or do whatever you want.
You could have something like:
for (int i = 0; i < length; i++) {
theCArray[i]; // do something
}
inside of your processingTheArray: function.
I'm sorry if this is a bit of a C-noob question: I know I need to swot up on my pointers. Unfortunately I'm on a deadline so don't have time to work through a whole book chapter, so I'm hoping for a bit more targeted advice.
I want to store some objective-C objects in a C array. I'm using ARC. If I were on the Mac I'd be able to use NSPointerArray instead, but I'm on iOS and that's not available.
I'll be storing a three-dimensional C array: conceptually my dimensions are day, height, and cacheNumber. Each element will either be a pointer to an objective-C object, or NULL.
The number of caches (i.e. the size of the cacheNumber dimension) is known at compile time, but the other two are not known. Also, the array could be very large, so I need to dynamically allocate memory for it.
Regarding ownership semantics, I need strong references to the objects.
I would like the whole three-dimensional array to be an instance variable on an objective-C object.
I plan to have a method that is - tableForCacheNumber:(int)num days:(int*)days height:(int*)height. That method should return a two-dimensional array, that is one specific cache number. (It also passes back by reference the size of the array it is returning.)
My questions:
What order should I put my dimensions so that I can easily return a pointer to the subarray for one specific cache number? (I think it should be first, but I'm not 100%.)
What should the return type of my method be, so that ARC doesn't complain? I don't mind if the returned array has an increased reference count or not, as long as I know which it's doing.
What type should my instance variable that holds the three dimensional array be? I think it should just be a pointer, since that ivar just represents the pointer to the first item that's in my array. Correct? If so, how do I specify that?
When I create the three-dimensional array (for my ivar), I guess I do something like calloc(X * Y * Z, sizeof(id)), and cast the result to the type for my ivar?
When accessing items from the three-dimensional array in the ivar, I believe I have to dereference the pointer each time, with something like (*myArray)[4][7][2]. Correct?
Will the two-dimensional array I return from the method be similarly accessed?
Do I need to tag the returned two-dimensional array with objc_returns_inner_pointer?
I'm sorry once again that this is a bit of a bad Stack Overflow question (it's too long and with too many parts). I hope the SO citizens will forgive me. To improve my interweb karma, maybe I'll write it up as a blog post when this project has shipped.
First off: while you don't have NSPointerArray, you do have CFMutableArrayRef and you can pass any callbacks you want for retain/release/description, including NULL. It may be easier (and performance is something you can measure later) to try that first.
Taking your points in order:
you should define your dimensions as [cacheNumber][days][height], as you expect. Then cache[cacheNumber] is a two-dimensional array of type id *[][]. As you've said performance is important, be aware that the fastest way to iterate this beast is:
for (/* cacheNumber loop */) {
for (/* days loop */) {
for (/* height loop */) {
//...
}
}
}
it should be of type __strong id ***: that's a pointer to a pointer to a pointer to id, which is the same as array of (array of (pointer to id)).
your ivar needs to be __strong id **** (!), because it's an array of the above things.
you guess incorrectly regarding allocating the array.. If you're using a multidimensional array, you need to do this (one dimension elided for brevity):
- (__strong id * * *)someArray {
__strong id * * *cache = (__strong id * * *)malloc(x*y*sizeof(void *));
id hello = #"Hello";
cache[0] = (__strong id * *)malloc(sizeof(void *)); //same for cache[1..x-1]
cache[0][0] = &hello; // for all cache[x][y]
return (__strong id * * *)cache;
}
correct, that is how you use such a pointer.
yeah, the two-D array works in the same way, sans the first dimension.
I don't think so, you're handing out __strong object pointers so you should be grand. That said, we're at about the limit of my ability with this stuff now so I could well be wrong.
Answering my own question because this web page gave me the missing bit of info I needed. I've also upvoted Graham's answer, since he was very helpful in getting my head round some of the syntax.
The trick I was missing is knowing that if I want to refer to items in the array via the array[1][5][2] syntax, and that I don't know the sizes of my array at compile time, I can't just calloc() a single block of data for it.
The easiest to read (although least efficient) method of doing that is just with a loop:
__strong Item ****cacheItems;
cacheItems = (__strong Item ****)calloc(kMaxZooms, sizeof(Item ***));
for (int k = 0; k < kMaxZooms; k++)
{
cacheItems[k] = (__strong Item ***)calloc((size_t)daysOnTimeline, sizeof(Item **));
for (int j = 0; j < daysOnTimeline; j++)
{
cacheItems[k][j] = (__strong Item **)calloc((size_t)kMaxHeight, sizeof(Item *));
}
}
I'm allocating a three dimensional array of Item *s, Item being an objective-C class. (I have of course left out the error handling code in this snippet.)
Once I've done that, I can refer to my array using the square brackets syntax:
cacheItems[zoom][day][heightToUse] = item;
The web page I linked to above also describes a second method for performing the memory allocations, that uses only one call to calloc() per dimension. I haven't tried that method yet, as the one I've just described is working well enough at the moment.
I would think of a different implementation. Unless it is a demonstrable (i.e. you have measured and quantified it) performance issue, trying to store Objective-C objects in plain C arrays is often a code smell.
It seems to me that you need an intermediate container object which we will call a Cache for now. One instance will exist for each cache number, and your object will hold an NS(Mutable)Array of them. Cache objects will have properties for the maximum days and height.
The Cache object would most easily be implemented with an NSArray of the objects in it, using simple arithmetic to simulate two dimensions. Your cache object would have a method -objectAtDay:Height: to access the object by its coordinates.
This way, there is no need at all to worry about memory management, ARC does it for you.
Edit
Given that performance is an issue, I would use a 1D array and roll my own arithmetic to calculate offsets. The type of your instance variable would be:
__strong id* myArray;
You can only use C multilevel subscripts (array[i][j][k]) if you know the range of all the dimensions (except the first one). This is because the actual offset is calculated as
(i * (max_j * max_k) + j * max_k + k) * sizeof(element type)
If the compiler doesn't know max_j and max_k, it can't do it. That's precisely the situation you are in.
Given that you have to use a 1D array and calculate the offsets manually, the Apple example will work fine for you.
As the title suggests, I'm having trouble understanding exactly what a pointer is and why they're used. I've searched around a bit but still don't really understand. I'm working in Objective-C mainly, but from what I've read this is really more of a C topic (so I added both tags).
From what I understand, a variable with an asterisks in front points to an address in memory? I don't quite understand why you'd use a pointer to a value instead of just using the value itself.
For example:
NSString *stringVar = #"This is a test.";
When calling methods on this string, why is it a pointer instead of just using the string directly? Why wouldn't you use pointers to integers and other basic data types?
Somewhat off topic, but did I tag this correctly? As I was writing it I thought that it was more of a programming concept rather than something language specific but it does focus specifically on Objective-C so I tagged it with objective-c and c.
I don't quite understand why you'd use a pointer to a value instead of
just using the value itself.
You use a pointer when you want to refer to a specific instance of a value instead of a copy of that value. Say you want me to double some value. You've got two options:
You can tell me what the value is: "5": "Please double 5 for me." That's called passing by value. I can tell you that the answer is 10, but if you had 5 written down somewhere that 5 will still be there. Anyone else who refers to that paper will still see the 5.
You can tell me where the value is: "Please erase the number I've written down here and write twice that number in its place." That's called passing by reference. When I'm done, the original 5 is gone and there's a 10 in its place. Anyone else who refers to that paper will now see 10.
Pointers are used to refer to some piece of memory rather than copying some piece of memory. When you pass by reference, you pass a pointer to the memory that you're talking about.
When calling methods on this string, why is it a pointer instead of just using the string directly?
In Objective-C, we always use pointers to refer to objects. The technical reason for that is that objects are usually allocated dynamically in the heap, so in order to deal with one you need it's address. A more practical way to think about it is that an object, by definition, is a particular instance of some class. If you pass an object to some method, and that method modifies the object, then you'd expect the object you passed in to be changed afterward, and to do that we need to pass the object by reference rather than by value.
Why wouldn't you use pointers to integers and other basic data types?
Sometimes we do use pointers to integers and other basic data types. In general, though, we pass those types by value because it's faster. If I want to convey some small piece of data to you, it's faster for me to just give you the data directly than it is to tell you where you can find the information. If the data is large, though, the opposite is true: it's much faster for me to tell you that there's a dictionary in the living room than it is for me to recite the contents of the dictionary.
I think maybe you have got a bit confused between the declaration of a pointer variable, and the use of a pointer.
Any data type with an asterisk after it is the address of a value of the data type.
So, in C, you could write:
char c;
and that means value of c is a single character. But
char *p;
is the address of a char.
The '*' after the type name, means the value of the variable is the address of a thing of that type.
Let's put a value into c:
c = 'H';
So
char *p;
means the value of p is the address of a character. p doesn't contain a character, it contains the address of a character.
The C operator & yields the address of a value, so
p = &c;
means put the address of the variable c into p. We say 'p points at c'.
Now here is the slightly odd part. The address of the first character in a string is also the address of the start of the string.
So for
char *p = "Hello World. I hope you are all who safe, sound, and healthy";
p contains the address of the 'H', and implicitly, because the characters are contiguous, p contains the address of the start of the string.
To get at the character at the start of the string, the 'H', use the 'get at the thing pointed to' operator, which is '*'.
So *p is 'H'
p = &c;
if (*p == c) { ... is true ... }
When a function or method is called, to use the string of characters, the only the start address of the string (typically 4 or 8 bytes) need be handed to the function, and not the entire string. This is both efficient, and also means the function can act upon the string, and change it, which may be useful. It also means that the string can be shared.
A pointer is a special variable that holds the memory location of an other variable.
So what is a pointer… look at the definition mentioned above. Lets do this one step at a time in the three step process below:
A pointer is a special variable that holds the memory location of an
other variable.
So a pointer is nothing but a variable… its a special variable. Why is it special, because… read point 2
A pointer is a special variable that holds the memory location of an
other variable.
It holds the memory location of another variable. By memory location I mean that it does not contain value of another variable, but it stores the memory address number (so to speak) of another variable. What is this other variable, read point 3.
A pointer is a special variable that holds the memory location of an
other variable.
Another variable could be anything… it could be a float, int, char, double, etc. As long as its a variable, its memory location on which it is created can be assigned to a pointer variable.
To answer each of your questions:
(1) From what I understand, a variable with an asterisks in front points
to an address in memory?
You can see it that way more or less. The asterisk is a dereference operator, which takes a pointer and returns the value at the address contained in the pointer.
(2) I don't quite understand why you'd use a pointer to a value instead of
just using the value itself.
Because pointers allow different sections of code to share information, better than copying the value here and there, and also allows pointed variables or objects to be modified by called function. Further, pointers enabled complex linked data structures. Read this short tutorial Pointers and Memory.
(3) Why wouldn't you use pointers to integers and other basic data types?
String is a pointer, unlike int or char. A string is a pointer that points to the starting address of data that contains the string, and return all the value from the starting address of the data until an ending byte.
string is a more complex datatype than char or int, for example. In fact, don't think sting as type like int of char. string is a pointer that points to a chunk of memory. Due to its complexity, having a Class like NSString to provide useful functions to work with them becomes very meaningful. See NSString.
When you use NSString, you do not create a string; you create an object that contains a pointer to the starting address of the string, and in addition, a collection of methods that allows you to manipulate the output of the data.
I have heard the analogy that an object is like a ballon, an the string you're holding it with is the pointer. Typically, code is executed like so:
MyClass *someObj = [[MyClass alloc] init];
The alloc call will allocate the memory for the object, and the init will instantiate it with a defined set of default properties depending on the class. You can override init.
Pointers allow references to be passed to a single object in memory to multiple objects. If we worked with values without pointers, you wouldn't be able to reference the same object in memory in two different places.
NSString *stringVar = #"This is a test.";
When calling methods on this string, why is it a pointer instead of just using the string directly?
This is a fairly existential question. I would posit it this way: what is the string if not its location? How would you implement a system if you can't refer to objects somehow? By name, sure... But what is that name? How does the machine understand it?
The CPU has instructions that work with operands. "Add x to y and store the result here." Those operands can be registers (say, for a 32-bit integer, like that i in the proverbial for loop might be stored), but those are limited in number. I probably don't need to convince you that some form of memory is needed. I would then argue, how do you tell the CPU where to find those things in memory if not for pointers?
You: "Add x to y and store it in memory."
CPU: OK. Where?
You: Uh, I dunno, like, where ever ...
At the lowest levels, it doesn't work like this last line. You need to be a bit more specific for the CPU to work. :-)
So really, all the pointer does is say "the string at X", where X is an integer. Because in order to do something you need to know where you're working. In the same way that when you have an array of integers a, and you need to take a[i], i is meaningful to you somehow. How is that meaningful? Well it depends on your program. But you can't argue that this i shouldn't exist.
In reality in those other languages, you're working with pointers as well. You're just not aware of it. Some people would say that they prefer it that way. But ultimately, when you go down through all the layers of abstraction, you're going to need to tell the CPU what part of memory to look at. :-) So I would argue that pointers are necessary no matter what abstractions you end up building.
Out of pure curiosity, I started playing with array's in ways that I have never used before. I tried making a data structure array, and set it equal to another:
typedef struct _test {
float value;
} test;
Simple enough struct, so I tried this:
test struct1[10];
test struct2[20];
struct1 = struct2;
I didn't think this would work, and it didn't even compile. But, this interests me a lot. Is it possible to take an array of 10 and increase the size to 20, while copying the data?
Objective-C
I am actually doing this with Objective-C, so I'd like to hear from the Objective-C people as well. I want to see if it is possible to change the size of struct1 in this file.
#interface Object : NSObject {
test struct1;
}
Remember: This is only out of curiosity, so everything is open to discussion.
Something else that is not exactly pertinent to your question but is interesting nonetheless, is that although arrays cannot be assigned to, structs containing arrays can be assigned to:
struct test
{
float someArray[100];
};
struct test s1 = { /* initialise with some data*/ };
struct test s2 = { /* initialise with some other data */ };
s1 = s2; /* s1's array now contains contents of s2's array */
This also makes it possible to return fixed-length arrays of data from functions (since returning plain arrays is not allowed):
struct test FunctionThatGenerates100Floats(void)
{
struct test result;
for (int i = 0; i < 100; i++)
result.someArray[i] = randomfloat();
return result;
}
As others have said, arrays allocated like that are static, and can not be resized. You have to use pointers (allocating the array with malloc or calloc) to have a resizable array, and then you can use realloc. You must use free to get rid of it (else you'll leak memory). In C99, your array size can be calculated at runtime when its allocated (in C89, its size had to be calculated at compile time), but can't be changed after allocation. In C++, you should use std::vector. I suspect Objective-C has something like C++'s vector.
But if you want to copy data between one array and another in C, use memcpy:
/* void *memcpy(void *dest, const void *src, size_t n)
note that the arrays must not overlap; use memmove if they do */
memcpy(&struct1, &struct2, sizeof(struct1));
That'll only copy the first ten elements, of course, since struct1 is only ten elements long. You could copy the last ten (for example) by changing &struct2 to struct2+10 or &(struct2[10]). In C, of course, not running off the end of the array is your responsibility: memcpy does not check.
You can also you the obvious for loop, but memcpy will often be faster (and should never be slower). This is because the compiler can take advantage of every trick it knows (e.g., it may know how to copy your data 16 bytes at a time, even if each element is only 1 byte wide)
You can't do this in C with static arrays, but you can do it with dynamically allocated arrays. E.g.,
float *struct1, *struct2, *struct3;
if(!(struct1 = malloc(10 * sizeof(float))) {
// there was an error, handle it here
}
if(!(struct2 = realloc(struct1, 20 * sizeof(float))) {
// there was an error, handle it here
// struct1 will still be valid
}
if(!(struct3 = reallocf(struct2, 40 * sizeof(float))) {
// there was an error, handle it here
// struct2 has been free'd
}
In C, I believe that's a good place to use the realloc function. However, it will only work with dynamically allocated arrays. There's no way to change the memory allocated to struct1 by the declaration test struct1[10];.
In C arrays are constants, you can't change their value (that is, their address) at all, and you can't resize them.
Clearly if you declare your array with a fixed size, test struct1[10] then it cannot be resized. What you need to do is to declare it as a pointer:
test *struct1;
Then you must use malloc to allocate the array and can use realloc to resize it whilst preserving the contents of the original array.
struct1 = malloc(10*sizeof(*struct1));
//initialize struct1 ...
test *struct2 = realloc(struct1, 20*sizeof(*struct1));
If you're using Objective C, you know you can just use NSMutableArray, which automatically does the realloc trick to reallocate itself to store however many objects you put in it, up the limit of your memory.
But you're trying to do this with struct? What would that even mean? Suppose you increase the amount of memory available to struct1 in Object. It's still a struct with one member, and doesn't do anything more.
Is the idea to make Object be able to contain an expanded struct?
typedef struct _test2 {
float value;
NSObject *reference;
} test2;
But then you still can't access reference normally, because it's not a known part of Object.
Object *object2;
...
NSLog(#"%#", object2.struct1.reference); // does not compile
If you knew you had one of your modified objects, you could do
Object *object2;
...
NSLog(#"%#", ((test2)(object2.struct1)).reference);
And also you could still presumably pass object2 to anything that expects an Object. It only has any chance of working if struct1 is the last member of Object, and don't mess with subclassing Object either.
Some variety of realloc trick might then work, but I don't think realloc in particular, because that's intended to be used on objects that are allocated with malloc, and the details of what C function is used to allocate objects in not exposed in Objective C, so you shouldn't assume it's malloc. If you override alloc then you might be able to make sure malloc is used.
Also you have to watch out for the fact that it's common in Objective C for more than one pointer to an object to exist. realloc might move an object, which won't be semantically correct unless you correct all the pointers.