Could you help me understand Pointers please? - objective-c

I know this has been asked previously but one thing that these other questions didn't touch upon is why
Allow me to explain. I just ran through a tutorial that outputted integers and pointers to show you how to do it.
int anInteger = 50;
int *anIntPointer = &anInteger;
So, to set up a pointer I assign a variable value as normal, and then I assign that variable to a pointer. This I understand, but as I've already said, this is the how not the why.
If I wanted to return the value 50 I could just NSLog anInteger so why would I need a pointer. Why would I need to NSLog *anIntPointer if I could just NSLog anInteger which does exactly the same thing?
Okay, I know this is very trivial and there are probably perfect circumstances to use a pointer, but so far no tutorial that I've read or watched will give me a perfect circumstance. They all deal with the how
Please help me find the why.

Pointers have many uses. One obvious one is that you want to call a function and have it modify one of your variables:
void f(int *i) { *i = 42; }
int g() { int i; f(&i); return i; }
Another is to return a large struct without a huge amount of copying:
struct big_struct *f() {
big_struct *bs = malloc(sizeof(big_struct));
// Populate the big_struct;
return bs;
}
Yet another is to manage arrays who's size you don't know at compile:
struct item *fetch_items(int n) {
item *i = malloc(n*sizeof(item));
load_items(i, n);
return i;
}
Still another is recursive data types, such as linked lists:
struct node {
int value;
struct node *next;
};
And this is just a sampling. Pointers are like nails to a carpenter. They are a key tool in almost any non-trivial programming problem.

The main reasons why we use pointers (in C and C-derived languages) are:
To mimic pass-by-reference semantics
To track dynamically-allocated memory
To create self-referential and dynamic data structures
Because sometimes the language forces you to
To mimic pass-by-reference semantics: In C, all function arguments are passed by value. The formal parameters and the actual parameters are different objects in memory, so writing to the formal parameter has no effect on the actual parameter. For example, given the code
void swap(int a, int b)
{
int tmp = a; a = b; b = tmp;
}
int main(void)
{
int x = 2, y = 3;
printf("before swap: x = %d, y = %d\n", x, y);
swap(x, y);
printf("after swap: x = %d, y = %d\n", x, y);
return 0;
}
a and x are physically distinct objects; writing to a does not affect x or vice versa. Thus, the before and after output in the program above will be the same. In order for swap to modify the contents of x and y, we must pass pointers to those objects and dereference the pointers in the function:
void swap(int *a, int *b)
{
int tmp = *a; *a = *b; *b = tmp;
}
int main(void)
{
int x = 2, y = 3;
printf("before swap: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("after swap: x = %d, y = %d\n", x, y);
return 0;
}
a and x are still distinct objects in memory, but the expression *a refers to the same memory as the expression x; thus, writing to *a updates the contents of x and vice versa. Now the swap function will exchange the contents of x and y.
Note that C++ introduced the concept of a reference, which sort of acts like a pointer but doesn't require an explicit dereference:
void swap(int &a, int &b)
{
int tmp = a; a = b; b = tmp;
}
int main(void)
{
int x = 2, y = 3;
std::cout << "before swap: x = " << x << ", y = " << y << std::endl;
swap(x, y);
std::cout << "after swap: x = " << x << ", y = " << y << std::endl;
return 0;
}
In this case, the expressions a and x do refer to the same memory location; writing to one does affect the other. This is a C++-ism, though.
I'm not familiar enough with Obj-C to know if they have a similar mechanism.
To track dynamically-allocated memory: The C memory allocation functions malloc, calloc, and realloc, along with the C++ operator new all return pointers to dynamically allocated memory. If you have to allocate memory on the fly, you have to use pointers to refer to it. Again, I'm not familiar enough with Obj-C to know if they use a different memory allocation mechanism.
To create self-referential and dynamic data structures: Aggregate types such as struct or union types cannot contain an instance of themselves; for example, you can't do something like
struct node
{
int value;
struct node next;
};
to create a linked list node. struct node is not a complete type until the closing }, and you cannot declare objects of an incomplete type. However, a struct can contain a pointer to an instance of itself:
struct node
{
int value;
struct node *next;
};
You can declare a pointer to an incomplete type, so this works. Each node in the list can refer to the node immediately following it. And since you're dealing with pointers, you can add or delete nodes from the list reasonably easily; you just have to update the pointer values, instead of physically moving data around.
I can pretty much guarantee that any container type in Obj-C uses pointer manipulation under the hood.
Because sometimes the language forces you to: In C and C++, an expression of array type will implicitly be converted to a pointer type in most circumstances. Array subscripting is done in terms of pointer arithmetic; the expression a[i] is evaluated as though it were written *(a + i). IOW, you find the address of the i'th element after a and dereference it.

Pointers are not specific to Objective-C, in fact they are used in C and [usually not so much C++]. Basically, it is how you pass objects by reference.
void thisFunctionModifiesItsArgs(int *x, int *y, int *z)
{
*x = 4;
*y = *z;
*z = 100;
}
int main()
{
int a = 0;
int b = 1;
int c = 2;
thisFunctionModifiesItsArgs(&a, &b, &c);
// now, a = 4, b = 2, and c = 100
}

the most obvious reasons:
1) you want the object pointed to to live beyond the scope of its use, so you create an allocation. accessing the int's address beyond its scope is asking for trouble -- the address is likely used by something else at that point. if you create a unique memory location for it, that problem is solved (or... maybe displaced).
2) you want to pass it by reference/pointer/address. this is useful to mutate an object, or as an optimization when the type is large.
3) support for polymorphism and/or opaque types
4) pointer to implementation (abstraction, dependency reduction)
and on... (i wouldn't expect you to understand all those cases at this stage)
so, the example you show is so trivial that it does not represent (any of) those cases -- it only attempts to introduce the syntax.
there are many cases, and they are used regularly in real world C, C++, ObjC, etc. programs for many different reasons.

A simple answer: because there are variables that are more complex than simple integers. The tutorial is giving you a very simple case to explain the concept, but the simple case they describe would almost never be used.

Justin's answer is spot on for what you're asking. If you need a good tutorial then I recommend chapter 5 of "Beginning Mac Programming" which explains how the memory addressing works and how this is essential for working with pointers, and the reasons why.

Computer Science 001
Computers (the computer chip) can only do three things, but they can do them million or even billions of times per second.
They can store information (a number) into memory.
They can do arthimetic on those numbers.
They can make simple decsions based on the arthimetic, like if a = b then go to address X.
Thats it.
A very simple analogy I use to explain pointers to beginners in assembler programming is to think of memory like a row of mailboxes. The first mailbox has address 0 and the next is one plus and so forth.
When a computer starts up, it is told to go to mailbox 0 and get the content.
The content can be information or a command, mailbox 0 always holds a command. The command might be Go to mailbox 1 and get its content.
The content of a mailbox can only hold so much information, just like a real mailbox can only hold so much information. If the postman need to deliver a package for example, he will put a notice in the mailbox to go to the post office to pick it up. The notice is like a pointer. The pointer does not hold the information, the real information is located where the pointer says it is located, in this case the post office.
You could even get to the post office to find out there is nothing but another pointer to another location. We would call that a "handle" or a pointer to a pointer.

If you want to copy a byte sequence from one place to other place, (naturally) you have to know the source and destination addresses. To express it in the language's abstraction level, you can use pointers, which represents the memory locations.
Beside notes has been written already, in lower levels, pointers are very often used. A very simple example: Writing to the 80x25 screen. For example the base address of the screen is 0xb8000, where the first character of the screen is stored. You can use pointers, with wich you can write a character to the appropriate position in the screen. e.g. : unsigned short* sc = (unsigned short*)0xb8000; *sc = 'A' | (attr) << 8; . And so on...
N.B.: Pointers embodies indirection, and it is possible, you can have "multiple" pointers: ** (imagine the C main functions signature, and the char** in it!). Or e.g. you want to create a list structure with malloc in a separate function. Then you can pass a struct list** or what have you parameter and in the function you can assign a value (a memory address) to the list, which means you have created the list in the memory.

Related

Why putting pointer* for Strings not for Integers in Objective-C

I learnt Swift firstly , maybe this should have been after learning Obj-C, so now I trying full understand Obj-C, I have trouble with issue below :
Obj-C variables
NSInteger score = 556;
NSString *name = #"matt";
in Swift everything is same for variables
var score = 556
var name = "matt"
Why objective-c use for strings * although integers are not * using, Why there is a such a different ? It is related run time ?
Can you explain to me with practical examples ? Thanks
You know, without pointers Objective-C is just Swift with semicolons.
Suppose you need to allocate a region of memory for your own use. You can store integers there, or an image, or a dictionary of objects or a sound clip. The pointer is your handle on that piece of memory. It tells you primarily the location of the region of memory you got, but in Objective-C, it also keeps track of e.g. a reference count so that you do not need to worry about allocating and releasing it. So things can get pretty complex pretty quick.
Let us assume the simplest possible scenario. You need some memory to store an object. Say a string, but that does not matter. Also, to all the purists out there, this is a general discussion not meant to be technically correct, but to illustrate the idea to OP.
First you will alloc that object
NSString * p = [NSString alloc];
This will ask the OS for a region of memory of the correct size to store a string and the OS will respond with a pointer that points to the newly allocated area, that address now stored in p. This is just an area of memory and you can do what you want with it. You need not even store a string there but things can go pear shaped pretty quick if you wander off like that.
Now the OS just gave you a region of memory. That memory is not blank, it holds some left over bits from whatever it was used for before. So your first task is to clear the memory - to initialise it. So the next step is to initialise it
p = [p init];
After this the area of memory has been prepared by some initialiser, e.g. it was zeroed or loaded some default values into the area of memory for a more complex class.
Note in reality this is a bit different - see the edit below.
In C you have alloc and malloc and calloc to do this. Some of these will just allocate memory and others will allocate the memory and set it all to 0 - clearing all the bits. In Objective-C you typically do this as a single step
p = [[NSString alloc] init];
Since the OS allocated a region of memory you need to tell it when you are done to free it, e.g.
[p release];
or in C you'd use free when done.
Now this is just academic, as ARC will do this automatically for you by keeping an internal reference counter to the object to determine when it goes out of scope and then to release it, but I digress. Let us just for now assume you need not worry about releasing that block of memory back to the OS, ARC will take care of it for you.
Let us also for now assume a more complex class, say
p = [[Invoice alloc] init];
Then when you e.g. do
p.items = 100;
the compiler will know that it needs to copy the integer value of 100 to the correct place inside that block of memory and it will do so for you. There are many variations on this theme, but basically as you assign values to ivars those values gets copied into the allocated area of memory and as you read them they get copied back from the correct spot into the local variable as well.
On the other hand, if you assign a value to a simple int variable
int items = 100;
this is not copied to your pre-allocated area. In stead, the message or function has a special local working area called a stack where these variables are created and later discarded dynamically. So the statement above will load the value 100 onto the stack and will note the position so that later if you refer to items it will know where to find and read or write its value on the stack.
Likewise
Invoice * p = [[Invoice alloc] init];
is loaded on the stack, but here the pointer's value or memory address is loaded on the stack, not the contents it points to. The fact that it is a pointer indicates to you that it points to some region of interest somewhere else.
If later you do
Invoice * q = p;
you load (on the stack) the same pointer value of p into q, and now p and q both point to the same area of memory where the actual object is stored. So pointers add this one layer of separation between the value of the pointer that can be interpreted as pointing to an address in memory, and the data that is stored at this address. This can go on, e.g. you can and do get pointers to pointers and so on.
Since you can not allocate memory yourself on the dynamic stack, you can not store objects on the stack, but you can store pointers to objects there.
Pointers give you incredible power as you access memory directly. You can e.g. write a general function to allocate memory or to write memory to disk or to clear memory or to transfer a block of memory through the network or to load a block of memory to a screen area. Modern compilers take care of these things for us so it does not sound like such a big deal, but the powerful thing is that you use the same routine for all your objects. If your array stores pointers then you can store anything in the array as another example.
Pointers also outlive the stack. The stuff you put on the stack e.g.
int items = 100;
only survives as long as you are inside the function. The stack is discarded when the function returns so you need a specially allocated area of memory to communicate in a way that transcends functions and sometimes even applications.
Here is a deeper example, using only integer pointers, not Objective-C object ones, to further illustrate the difference between pointers and values on the stack.
In C you'd do
int * p = malloc ( 10 * sizeof( int ) );
which will allocate enough space to store 10 integers and return the pointer to the allocated space in p. p is now on the stack and contains the address of the area of memory just returned.
Next if you do
int q = 123;
the value 123 is stored onto the stack and under the moniker q which the compiler will translate to this specific location on the stack as you work with q e.g. assign a value to it.
Next, if you do
* p = q;
* ( p + 1 ) = q / 2;
this will load the value of q (123) from the stack and into the area of memory pointed to by p, which points to the first of the 10 integers. Next you calculate q / 2 and store that value into the location of the next integer, the 1 after the first, pointed to by p and referenced by * ( p + 1 ). The compiler can do this easily as it knows the size of an integer so it knows how to translate
* ( p + 1 )
into the correct area that points to the integer shifted 1 away from the base p.
This is another topic with pointers, it allows for incredibly efficient pointer arithmetic that you can use to traverse areas of memory. Also, this is why sizeof is such an important keyword in C as it is directly linked to how the language handles memory through pointers.
In C, when done, you need to release the area back to the OS so you'd do
free( p );
when done.
This seems simple enough, but in practise it is difficult to keep track of all the allocated regions of memory. It easily happens that you do not release one or that you load data into an area already released. The former leaks memory and the latter can have disasterous consequences.
This is why Objective-C's ARC represents such a big step in the development of the language as it takes care of this for you. In the ARC world the allocation and freeing of memory, a BIG topic in pointers, is no longer that important or visible - so it can also shield some understanding of pointers from its users.
In e.g. Swift this allocation and freeing happens completely behind the scenes and you do not really worry about allocating or freeing memory directly. This makes it difficult to understand the difference between pointing to memory and the memory being pointed to, which is at the heart of pointers.
You know, without pointers Objective-C is just Swift with semicolons.
I started and now ended with this somewhat controversial statement.
Why?
When I was a programmer struggling with the concept of pointers, I had a mind to give it up completely. This was before objects and you could (try to) do all you needed to on the stack and side step pointers that way.
I just came from Pascal (where you do not use pointers that much) and struggled with C, especially with pointers, and then read somewhere that, without pointers, C is just Pascal with curly braces! I knew C was powerful, more so than Pascal, but to grasp for that I had to master pointers.
Note - as mentioned by Sulthan, Pascal also has pointers and it is very debatable if one is more powerful than the other.
Here is a nice sample to illustrate a lot of these concepts, also how you can use pointers to iterate through memory.
int main(int argc, const char * argv[]) {
#autoreleasepool
{
// insert code here...
int a = 10; // a loaded on stack
int * b = & a; // b now points to a
NSLog ( #"a pointer %p value %d", & a, a );
NSLog ( #"b value %p points to %d", b, * b );
int * p = malloc ( 10 * sizeof ( int ) );
int * q = p;
// Show p on the stack and * p allocated somewhere
// Note the values, & p agrees with & a of earlier e.g.
NSLog ( #"p address %p on stack but points to %p", & p, p );
for ( int i = 0; i < 10; i ++ )
{
* q = i; // loads value i into area pointed to by q
NSLog ( #"i now %d", i );
// Note the huge difference between addresses on the stack and addresses alloc'd
NSLog ( #"\tp %p p + i %p value pointed to is %d", p, p + i, * ( p + i ) );
NSLog ( #"\tq %p value pointed to is %d", q, * q );
q ++; // Increment pointer, not value, now points to next int
}
// Of course ...
free ( p );
}
return 0;
}
EDIT Objective-C alloc
I mention in the text that the memory needs to be initialised after an Objective-C alloc. I could not find any documentation now, but I am pretty sure that Objective-C's alloc, e.g. something like
NSString * s = [NSString alloc];
will in fact both allocate and clear or zero the memory. The init is not really meant to zero but for the class to initialise its members properly.
But, since we are discussing pointers and since you are looking for programming examples, what better than to write a piece of code to test this.
The code below will create two Objective-C classes of your choice. One will only be alloc'd and one will be alloc'd and init'd. Then it compares these two classes byte for byte using pointers to see if there is a difference. Another nice example of using pointers.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
// The object we will test
#define TEST_OBJECT NSFileManager
int main(int argc, const char * argv[]) {
#autoreleasepool {
// Allocate some complex class
TEST_OBJECT * obja = [TEST_OBJECT alloc];
TEST_OBJECT * obji = [[TEST_OBJECT alloc] init];
// Size of this class
unsigned long n = class_getInstanceSize ( TEST_OBJECT.class );
NSLog ( #"Object size is %lu", n );
NSLog ( #"\tLocation in memory %p", obja );
NSLog ( #"\t %p", obji );
// Get pointers to the two instances
void * p = ( __bridge void * ) obja;
void * q = ( __bridge void * ) obji;
// Compare the two
int cmp = memcmp( p, q, n );
NSLog ( #"Result is %d - %#", cmp, cmp ? #"different" : #"same" );
// Dump the actual bytes side by side
for ( int i = 0; i < n; i ++ )
{
int l = ( unsigned ) ( * ( ( unsigned char * ) p + i ) ); // Left
int r = ( unsigned ) ( * ( ( unsigned char * ) q + i ) ); // Right
NSLog ( #"Byte %3d | %3d | %3d | %#", i, l, r, l != r ? #"***" : #"" );
}
}
return 0;
}
If you understand the difference between a value type and a reference type in Swift, then in Objective-C using a pointer simply denotes a reference type.
During assignments, either the value is copied:
// swift
var score = 10
// obj-c
NSInteger score = 10;
or the reference is copied, or, in other words, we are not assigning the value itself but the pointer to the value:
// swift
class MyObject {}
var object = MyObject();
// obj-c
#interface MyObject: NSObject
#end
MyObject *object = [[MyObject alloc] init];
Also note that in Objective-C string (NSString), arrays (NSArray) and similar are all reference types. Even numeric types which are value types (NSInteger) have reference type wrappers (e.g. NSNumber) because otherwise you cannot put them into an array. Even null value has a corresponding reference type NSNull.
Of course, even with value types you can use a pointer:
NSInteger score = 10;
NSInteger *scorePointer = &score; // assign pointer to score
*scorePointer = 20; // change value of score through the pointer
NSLog(#"%#", #(score)); // 20
In the same way you can also have pointers to other pointers, which is useful in many situations (e.g. inout method parameters).

Expanding an array within a structure in C

I've got a question about what I think boils down to C syntax and memory considerations. I have a callback in an Objective-C class that processes some audio, and one of the arguments is bufferListInOut. It represents a mono audio signal that I'd like to convert to stereo. Here's my code:
static void tap_ProcessCallback(MTAudioProcessingTapRef tap,
CMItemCount numberFrames,
MTAudioProcessingTapFlags flags,
AudioBufferList *bufferListInOut,
CMItemCount *numberFramesOut,
MTAudioProcessingTapFlags *flagsOut){
// Retrieve mono audio data into bufferListInOut
MTAudioProcessingTapGetSourceAudio(tap, numberFrames, bufferListInOut, NULL, NULL, NULL);
// Copy the mono channel's data
float *channelLeft = malloc(numberFrames * sizeof(float));
channelLeft = bufferListInOut->mBuffers[0].mData;
// Attempt to create a second channel which is (currently) a copy of the first
bufferListInOut->mNumberBuffers = 2; // 2 for stereo, 1 for mono
bufferListInOut->mBuffers[1].mNumberChannels = 1;
bufferListInOut->mBuffers[1].mDataByteSize = numberFrames * sizeof(Float32);
bufferListInOut->mBuffers[1].mData = channelLeft;
// Set number of frames out
*numberFramesOut = numberFrames;
}
Some notes:
In this code, the new channel is just a copy of the original, but in practice it will undergo some processing.
The naming is a little weird, but mNumberBuffers is indeed meant to be 2 and mNumberChannels is meant to be 1.
This crashes with an EXC_BAD_ACCESS error on a rendering thread down the line. So, my question is what is the right way to add a new buffer to this struct? I don't delve into C too often, so I'm sure I'm missing some basics here. Any pointers on this would be great. Thanks for reading.
You cannot do what you are attempting, at least in the way you are trying to do it. The type AudioBufferList is declared as:
struct AudioBufferList { UInt32 mNumberBuffers; AudioBuffer mBuffers[1]; };
This is a classic C pattern for a variable sized struct. To create a struct for N buffers a single block of memory is allocated with the size:
sizeof(UInt32) + N * sizeof(AudioBuffer)
The address of that block is assigned to a AudioBufferList * variable and the field mNumberBuffers set to N. You cannot simply increase the mNumberBuffers to increase the size of the array, instead you must either allocate a new complete struct, or realloc the existing one - realloc increases the size of memory block if possible or allocates a new one and copies the existing data into it if not.
Given your tap_ProcessCallback() function is passed a AudioBuuferList * value and does not return one, there is no way it can change the size of the struct (i.e. the number of buffers) it is passed.
As pointed out in comments you are also doing pointer assignment when you intend to copy memory - see memcpy and friends.
So you need a redesign - your goal is possible, just not how and where you've attempted it.
HTH

What is int foo[] = {1200,100} and how do I recreate it in Swift?

Testing out some third party objective-C code I see the following:
int beepData[] = {1200,100};
What am I looking at here? An int is being created from a pair of other integers? I've not seen this feature before.
I would also like to know how to create the same variable in Swift.
EDIT
I assumed this was returning an int, not an array. The code I'm reviewing looks like this:
int beepData[] = {1200,100};
[[DTDevices sharedDevice] barcodeSetScanBeep:TRUE volume:10 beepData:beepData length:sizeof(beepData) error:nil];
Where the method signature I am intending to pass the variable to is:
-(BOOL)barcodeSetScanBeep:(BOOL)enabled volume:(int)volume beepData:(int *)data length:(int)length error:(NSError **)error;
I guess the right question might have been - what is (int *) and how might I create one in Swift?
What am I looking at here?
That is an array of ints, with two elements.
[How can I] create the same variable in Swift?
The same variable in swift might be declared as:
var beepData : [Int] = [ 1200, 100 ]
You might find this answer about different ways to declare an array in C useful
What is (int *)
It's an int pointer, it points to the memory address of an int. Incrementing it would move along the memory addresses (in int-sized chunks) and point to the next bit of memory.
[1][3][5][4][2]
^
This little arrow represents an int*. Even though it currently points to 1,
incrementing it doesn't equal 2. In this case it would equal 3, the value of the int in the next block of memory.
[1][3][5][4][2]
^
How might I create one in Swift?
To be quite honest, I'm not sure if Swift has pointers in the normal sense. I've not used it a great deal. However, if you are porting that method, I'd probably give it an array of ints.
func barcodeSetScanBeep(enabled : Bool, volume : Int, beepData: [Int], length : Int, error : NSError)
That's a C array, declared with 1200 and 100 as the members of the array.
Its declared with the type, and a bracket with the size (or empty for compiler deduced size), such as int cArrayOfInts[] = blahblahblah.
Note how the members of the array can be primitives, instead of objects. This isn't possible in Objective-C.
To recreate this in swift, simply use var beepData = [1200, 100] and it will be type inferred to an array of Ints.
James already answered the particulars of your question - consider this some additional information.
Declarations in C are based on the types of expressions, not objects. If you have an array of integers and you want to access the i'th integer, you would write
x = arr[i];
The type of the expression arr[i] is int, so the declaration of arr is written as
int arr[N]; // arr is an N-element array of int
Similar logic applies to pointer declarations; if you have a pointer to a double and you want to access the pointed-to value, you'd write
y = *p;
The type of the expression *p is double, so the declaration of p is written as
double *p;
Same for function declarations; you call a function that returns an integer as
x = f();
The type of the expression f() is int, so the declaration of the function is written as
int f( void ); // void means the function takes no parameters
C declaration syntax uses something called a declarator to specify an object's array-ness, pointer-ness, or function-ness. For example:
int x, arr[10], *p, f(void);
declares x as a plain int, arr as a 10-element array of int, p as a pointer to an int, and f as function taking no parameters and returning int.
You'll occasionally see pointer declarations written as T* p, however they will be parsed as T (*p); the * is always part of the declarator, not the type specifier.
C declaration syntax allows you to create some pretty complex types in a compact format, such as
int *(*(*f[N])(void))[M];
In this declaration, f is an N-element array of pointers to functions returning pointers to M-element arrays of pointers to int.
In your declaration
int beepData[] = {1200, 100};
beepData is being declared as an array of an unknown size; the size is taken from the number of elements in the initializer {1200, 100}, in this case 2.
I know nothing about Swift, so I wouldn't know how to translate the C code to it. The best I can do is explain how the C code works.

Odd use of curly braces in C

Sorry for the simple question but I'm on vacation reading a book on core audio, and don't have my C or Objective C books with me...
What are the curly braces doing in this variable definition?
MyRecorder recorder = {0};
Assuming that MyRecorder is a struct, this sets every member to their respective representation of zero (0 for integers, NULL for pointers etc.).
Actually this also works on all other datatypes like int, double, pointers, arrays, nested structures, ..., everything you can imagine (thanks to pmg for pointing this out!)
UPDATE: A quote extracted from the website linked above, citing the final draft of C99:
[6.7.8.21] If there are fewer initializers in a brace-enclosed list
than there are elements or members of an aggregate, [...] the remainder of the
aggregate shall be initialized implicitly the same as objects that
have static storage duration.
Its initializing all members of recorder structure to 0 according to C99 standard. It might seem that it initializes every bit of the structure with 0 bits. But thats not true for every compiler.
See this example code,
#include<stdio.h>
struct s {
int i;
unsigned long l;
double d;
};
int main(){
struct s es = {0};
printf("%d\n", es.i);
printf("%lu\n", es.l);
printf("%f\n", es.d);
return 0;
}
This is the output.
$ ./a.out
0
0
0.000000
It is an initialization of a structure.
Actually, it don't initliaze all the elements of the structure, just the first one. But, the others are automatically initialized with 0 because this is what the C standard ask to do.
If you put:
MyRecorder recorder = {3};
The first element will be 3 and the others weill be 0.
MyRecorder could be one of the following and you are attempting to initialize all the elements of that with zero
typedef struct _MyRecorder1 {
int i;
int j;
int k;
}MyRecorder1;
typedef int MyRecorder2[3];
Unlike C++11, in C99 there has to be at least one element in initializer braces.
C++11 struct:
MyRecorder recorder{};
C struct:
MyRecorder recorder = {0};

Replace array with another array in C

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.