c - Access violation when reading array - c

I am trying to read an array of data and receiving an access violation. I can read the data from the array within the function that the array was allocated using:
AllCurrentData[newLineCount].data[tabCount] = malloc(length + 1);
strcpy( AllCurrentData[newLineCount].data[tabCount], buffer );
printf("%s", AllCurrentData[newLineCount].data[tabCount]);
But can't read it outside of the function. This is where I get the access violation, looks like it is trying to read a null location.
How can I access the data in the array AllCurrentData in a different function? thanks!
Extra info:
typedef struct current{
char **data;
}CurrentData;
AllCurrentData is declared in main:
CurrentData *AllCurrentData = '\0';
Function call
getCurrentData(current, AllCurrentData);
printf("%s", AllCurrentData[0].data[0]); //<----- error here

CurrentData *AllCurrentData = '\0';
This declares a pointer. This pointer is a variables that holds a number that is interpreted as an address. You initialize the pointer to '\0' (null).
getCurrentData(current, AllCurrentData);
Here you pass this pointer as parameter to function getCurrentData. As a pointer is a variable, this variable is passed by value, meaning that the function receives a copy of that value (the number that represents an address).
When inside the function if you write
AllCurrentData = malloc...
you modify that copy of the pointer, so outside the function AllCurrentData will still be '\0'.
You need to pass a pointer to that pointer (Inception, I know).
getCurrentData(current, &AllCurrentData);
getCurrentData(.., CurrentData **p_AllCurrentData) {
*p_AllCurrentData = malloc(...);
}
Let me explain this concept on a simpler example:
int *v = NULL; // here v is a pointer. This pointer has value 0 (invalid address)
v = malloc(10 * sizeof(int)); // here the pointer is assigned a valid address, lets say 0x41A0
f(v);
void f(int *x) {
// here the pointer x receives a copy of the value of the pointer v, so x will be, like v, 0x41A0
x[0] = 4;
/*this is ok as you modify the memory at the address 0x41A0,
so this modification is seen from outside the function, as v points to the same address.*/
x = malloc(...);
/* this is NOT ok, as x receives a new address, lets say 0xCC12.
But because x has a copy of the value from v, v will still be unmodified.*/
}
so if you want to allocate a pointer inside a function this is not ok:
int *v = NULL; // here v is a pointer. This pointer has value 0 (invalid address)
f(v);
void f(int *x) {
// here the pointer x receives a copy of the value of the pointer v, so x will be, like v, NULL
x = malloc(...);
/*this is NOT ok, as x receives a new address, lets say 0xCC12.
But because x has a copy of the value from v, v will still be unmodified,
it will still have NULL.*/
}
The right way to do is:
int *v = NULL; // here v is a pointer. This pointer has value 0 (invalid address)
// as v is a variable (of type pointer to int), v has an address, lets say 0xAAAA.
f(&v);
void f(int **p_x) {
/* here the p_x is a pointer to (a pointer of int),
so this pointer receives a copy of the value the address of p, so p_x is 0xAAAA.*/
*p_x = malloc(...);
/* lets say malloc returns the address 0xBBBB. This will be the address of our vector.
*p_x= says we modify the value at the address p_x. So the value found at the adress 0xAAAA
will be 0XBBBB. But because 0xAAAA is the address of v, we effectively modified the value of v
to 0xBBBB. So now v has the address of our starting vector.*/
// if you want to modify values inside this vector you need:
(*p_x)[0] = ...
}

Related

Double pointers as arguments in C

I am having some problems with double pointers as arguments in C.
From what I know so far:
when I have a function that takes a pointer as an argument, say a function called functionX(int *y)
then when I call functionX, let's say by: functionX(&randomvar),where randomvar is an integer containing a certain value (let's say 5), then C will create a pointer that is also called 'randomvar' that contains the address of randomvar. So the output of *randomvar will be 5.
Is my understanding correct?
If so, then when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the address of randomvar, another that contains the address of the first pointer.
I'm a bit stumped here I'm not sure if it's correct.
From what I know so far: when I have a function that takes a pointer
as argument, says a function called functionX(int *y) then when I
call functionX, let's say by: functionX(&randomvar),where
randomvar is an integer containing a certain value (let's say 5),
then C will create a pointer that is also called 'randomvar' that
contains the addresse of randomvar. So the ouput of *randomvar
will be 5.
Is my understanding correct?
No.
The situation you describe would be along these lines:
void functionX(int *y) {
// ...
}
int main(void) {
int randomvar = 5;
functionX(&randomvar);
}
The expression &randomvar in the main() function of that code does evaluate to the address of that function's local variable randomvar. The expression has type int *, the same as parameter y to function functionX(), so it is well suited for use as an argument to that function. All well and good so far.
But the expression &randomvar designates only a value, not an object. There is no storage reserved for it, and therefore it does not have an address. It also has no name, and in particular, it is not named 'randomvar'. Inside function functionX(), (a copy of) that value can be accessed as y, and the expression *y will evaluate to 5. Nowhere in the code presented is *randomvar a semantically valid expression.
If so
It is not so.
, then when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the adresse of randomvar, another that contains the adresse of the first pointer.
Not at all. &randomvar is a single expression. Evaluating it produces one value, which, as I've already covered, has type int *. This is does not match a function parameter of type int **. An int ** is a pointer to an int *. To obtain one, you might take the address of an object (not a value) of type int *:
void functionY(int **z) {
// ...
}
int main(void) {
int randomvar = 5;
int *varptr = &randomvar;
functionY(&varptr);
}
When done that way, there are indeed two pointers, one an int * and the other an int **, but the former needs to be declared explicitly.
Visualize it this way:
void foo(int a);
void bar(int *b);
void baz(int **c);
// main function
{
int x = 5;
int *p = &x;
foo(x);
bar(p);
baz(&p);
}
// **main** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
ABCD:4000 x 5
ABCD:4008 p ABCD:4000
// **foo** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:2000 a 5
// a new variable is created.
// any changes made on 'a' will not affect 'x' in 'main'
// **bar** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:4000 b ABCD:4000
// a new pointer is created pointing to 'x'
// 'b' points to 'x' and '*b' means 'the value stored in ABCD:4000'
// any changes made on '*b' will affect 'x' in main
// **baz** mem space
virtual mem address var name (conceptual) value
=================== ===================== =====
BCDE:8000 c ABCD:4008
// a new pointer is created pointing to 'p'
// 'c' points to 'p' and '*c' means 'the value stored in ABCD:4008'
// any changes made on '*c' will change the value of 'p' in main
// if '**c = 7' is executed, x will be assigned '7'
// if '*c = ABCD:8000' is executed, p will no longer point to 'x'
hen when I call functionX, let's say by: functionX(&randomvar),where
randomvar is an integer containing a certain value (let's say 5), then
C will create a pointer that is also called 'randomvar' that contains
the addresse of randomvar
The name of the pointer in the function functionX is y because you wrote yourself that it is the name of the function parameter functionX(int *y).
If so, then when the function has double pointers : functionX(int **y)
and by doing functionX(&randomvar) creates 2 pointers, one that
contains the adresse of randomvar, another that contains the adresse
of the first pointer. If you have a function declared for example like
The operator & creates one pointer not two pointers.
If you have a function declared for example like
void functionX(int **y);
and a variable declared like
int randomvar = 5;
then such a call of the function like
functionX( &randomvar );
generates a compilation error because the type of the argument is int * while the type of the parameter according to the function declaration is int **.
You may not write for example like
functionX( &&randomvar );
because using the first operator & creates a temporary object of the type int *. And you may not apply the operator & to a temporary object.
To call the function you could write
int *p = &randomvar;
functionX( &p );
In this case the type of the argument will be int ** as it is required by the parameter type.
Here is a demonstrative program.
#include <stdio.h>
void f( int *p )
{
printf( "The value of p is %p\n"
"the pointed value is %d\n",
( void * )p, *p );
}
void g( int **p )
{
printf( "The value of p is %p\n"
"the pointed value is also a pointer %p\n"
"the pointed value by the dereferenced pointer is %d\n",
( void * )p, ( void * )*p, **p );
}
int main(void)
{
int x = 5;
f( &x );
putchar( '\n' );
int *p = &x;
g( &p );
return 0;
}
Its output might look for example like
The value of p is 0x7ffced55005c
the pointed value is 5
The value of p is 0x7ffced550060
the pointed value is also a pointer 0x7ffced55005c
the pointed value by the dereferenced pointer is 5
You can just keep chaining pointers forever if you like. Here's some code that demonstrates this:
#include<stdio.h>
void foo(int ***A, int **B, int *C) {
printf(" %p A\n %p *A\n %p **A\n %d ***A\n", A, *A, **A, ***A);
printf(" %p B\n %p *B\n %d **B\n", B, *B, **B);
printf(" %p C\n %d *C\n ", C, *C);
}
int main(void) {
int D = 8;
int* C = &D;
int** B = &C;
int*** A = &B;
foo (A,B,C);
printf("%p &D (in main)\n", &D);
return 0;
This will give results like this for the dereferenced pointers, each '*' comes off just as it goes on, so notice how **A = *B = C = &D
0x7ffc81b06210 A
0x7ffc81b06218 *A
0x7ffc81b06224 **A
8 ***A
0x7ffc81b06218 B
0x7ffc81b06224 *B
8 **B
0x7ffc81b06224 C
8 *C
0x7ffc81b06224 &D (in main)
Note finally that the call foo (&B, &C, &D) will produce the same result.
There is no pointer made of the same name as the passed variable when invoking a function with an address of a passed variable as argument. It simply passes the address of a certain variable when preceded by the & operator. Inside the called function the pointer which holds this address can have any valid identifier.
when the function has double pointers : functionX(int **y) and by doing functionX(&randomvar) creates 2 pointers, one that contains the adresse of randomvar, another that contains the adresse of the first pointer.
You cannot pass the address of an int object, which is of type int*, when the function expects an object of type int**.
Speaking for passing double pointers in general, the concept is the same as said above.
No, your understanding is not correct. C doesn't "create" anything in the sense you assumed -- most variables are simply labels of memory locations (not only though, they may "alias", or label, CPU registers) -- your randomvar in the scope where functionX is called is a label of a memory area allocated to store an integer and which is interpreted as integer. The value of &randomvar unary expression (operator & with a single operand randomvar) is the address of the data. That address is what is passed to functionX as y, meaning that a memory location (or CPU register) is reserved and stores the address (not the value) of randomvar.
As an example, say your program declares a variable like int randomvar; -- when executed, a part of RAM -- 4 bytes for an int typically -- is reserved to hold the variable value of randomvar. The address isn't known until the program is executing in memory, but for the sake of the example let's imagine the address 0xCAFEBABEDEADBEEF (8 bytes) is the one that points to the 4 bytes to hold the integer value. Before the variable is assigned a value, the value at the address is indeterminate -- a declaration of a variable only reserves the space to hold the value, it doesn't write anything at the address, so before you assign a value to the variable, you shouldn't even be using the value at all (and most C compilers can warn you about this).
Now, when the address is passed to functionX this means that for the function, label y is 8 bytes reserved at some memory location, to store an address of an integer variable. When called like functionX(&randomvar), y stores 0xCAFEBABEDEADBEEF. However, y also [typically] has an address -- the former value (address of randomvar) has to be stored somewhere! Unless a CPU register stores the value, in which case there is no [RAM] address, naturally.
For a pointer to a pointer like int * * y, y labels a memory location reserved to store an address to an address of an integer variable.

If p is a pointer to int where would one use &p

In the following code p is pointer to an int. It is quite clear that p points to the address of i. Through my research i know &p points to the address of pointer p. But i don't get why would you need separate address for that. And also when would you use &p.
int main() {
int i = 3, *p = &i;
printf("%p",&p);
printf("%p",p);
return 0;
}
If p is pointer to int then
int **q = &p;
When you want to use pointer to pointer, then use the address of a single pointer to assign it to pointer to pointer.
Just to make a point that pointer is also a data-type and it stored in the memory location and it holds a valid memory location as its value. The address in which this valid memory location is stored is given by &p
Your printf() also needs to be fixed. %p expects void *
printf("%p",(void *)p);
But i don't get why would you need separate address for that
You don't, but there exists the address of operator so you can take the address of a pointer, which is what
printf("%p\n", &p);
is printing.
And also when would you use &p
There are cases where this might be useful, consider for example that you need to pass a pointer to a function which could be reassigned into the function, you can do something like this
int allocateIntegerArray(int **pointerToPointer, size_t someSize)
{
if (pointerToPointer == NULL)
return 0;
*pointerToPointer = malloc(someSize * sizeof(int));
return (*pointerToPointer != NULL);
}
then you could use this funciton the following way
int *pointer;
if (allocateIntergerArray(&pointer, 10) == 0)
{
fprintf(stderr, "Error, cannot allocate integer array\n");
/* do some extra cleanup or recover from this error, or exit() */
exit(0);
}
The pointers themselves are also variables and as such they need to be sotred somewhere, so the address of a pointer tells you where is the pointer stored, it's value tells you where it is pointing to.
By knowing where it is stored you can do things like the one explained above.
A trivial example:
int nochange(int *c, int *val)
{
c = val; // Changes local pointer c to point to val
// Note that C passes copies of the arguments, not actual references.
}
int do_change(int **c, int *val)
{
*c = val; // Accesses the real pointer c at its real location and makes
// that one point to val
// Even though c is a pointer-to-pointer copy, its value is
// copied too, and the value is the address of the real c
}
int main()
{
int a = 1;
int b = 2;
int *c = &a; // A pointer is also a datatype that resides in memory
printf("%d\n", *c); // Will print 1
nochange(c, &b);
printf("%d\n", *c); // Will print 1
do_change(&c, &b);
printf("%d\n", *c); // Will print 2 because c now points to b
}
I have a similar answer with a bit more detail here about pointer vs pointer-to-pointer: pointer of a pointer in linked list append

C - modify the address of a pointer passed to a function

I don't understand why the modification of pointer address passed as parameter to a function isn't persisted outside of this function (the address of ptr doesn't change after this function is called):
void advance(int *ptr) {
ptr = ptr + 1
}
When I can inside this same function modify the value pointed by ptr: *ptr = *ptr + 1.
PS: I know that I can achieve what I want using a pointer to a pointer: **ptr.
This behaviour is because parameters to functions in C are always passed by value. What you are passing by value here is an address. When you modify ptr you are modifying a copy of the caller's value.
To modify the caller's value you need an extra level of indirection:
void advance(int **ptr) {
*ptr = *ptr + 1;
}
When you define the function void advance(int *ptr) it means that a pointer in the stack will be created, which pointer points to the same addres as the original pointer. To see the proof try printing the address of orig pointer (&orig) and the address of the parameter pointer (&param), and the "pointed to" addresses (orig,param). The pointer addresses will differ, but the pointed to addresses will be the same.
So we have two pointers that points to the same area, if you modify the param, it will point to the new area, but the orig value will not be changed, it points to the same area as before.
That's why you need a pointer to a pointer. If you use a pointer to a pointer (int **ppointer = &orig), you will have a pointer that directly points to the area where orig stores the "pointed to" address (to where the orig points currently). By changing the value of the *ppointer, you will directly change the value of the orig as well.
Because C is not call by reference, it is always call-by-value, even with references/pointers as arguments.
It is not like other languages, where it can differentiate between argument types.
You actually answered you own question ;)
the modification of pointer address passed as parameter to a function isnt persisted outside of this function
Inside the function you are managing a copy of your parameter.
You can modify the value pointed because you are explicitly asking for change at a specific address.
****** /---\
* 20 * ----> | 2 |
****** \---/
i 20-24
Here i is a pointer pointing to the memory location 20 which has a value 2 i.e. when the binary data in 20 + sizeof(int) - 1 is interpreted as a decimal number. Now, when you pass i to advance, which has an argument ptr, what really happens is
****** /---\ ******
* 20 * ----> | 2 | &lt---- * 20 *
****** \---/ ******
i 20-24 ptr
ptr = i; i.e. the value of i is set to the value of ptr, which are really addresses here, since i and ptr are pointers.
When you increment ptr it'll just make the pointer point to a different address and not change anything with respect to i since ptr is a copy and not i itself. However, if you change the value at ptr using the operator * i.e. as *ptr = 10; then the 2 above will change to 10 thereby change *i as well, which is also pointing to 20. Again notice that i's address or value is untouched, only the location to which it is pointing to underwent a change. Had there been 10 pointers pointing to the address 20, even then none of them get changed, but all their pointed-to value gets changed.
See the function:
void demonstrate(int num) {
num = num + 1; // type of num is int
} // destroys "num", because num's scope is only "demonstrate" function
In your function:
void advance(int *ptr) {
ptr = ptr + 1; // type of ptr is int* and ptr is incremented
} // destroys "ptr" for the similar reason
But you want a function that modifies an address (IN pointer). So the complete solution should be:
#include <stdio.h>
void advance(int **ptr) { //ptr is a pointer to a pointer
// so *ptr is the pointer that is pointed by ptr
*ptr = *ptr + 1; // incrementing the address IN the pointer pointed by ptr
} // destroys "ptr" for the reason above
int main() {
int x = 5;
// initially assign "ptrToChange"
int *ptrToChange = &x;
// "ptrToChange" now points to x
// passing address OF "ptrToChange" to "advance" function
advance(&ptrToChange);
// now "ptrToChange" does NOT point to x
return 0;
}

Address of a pointer is equal to a pointer to pointer?

I'm trying to understand how the pointers in this piece of code works:
void allocateArray( int **arr, size_t size, int value )
{
*arr = malloc( size * sizeof( int ));
if ( *arr != NULL )
for ( size_t i = 0; i < size; ++i )
*( *arr + i ) = value;
}
int main( void )
{
int *vector = NULL;
allocateArray(&vector,5,45);
free( vector );
return 0;
}
If I declared a pointer to an int ( *vector ), how passing its address makes it a pointer to a pointer to int ( **arr )? I mean, how does it work, now that vector's address in the memory will be overwritten!
C passes function parameters by value. So, to allow a function to modify a variable provided by the caller, a pointer to it must be passed. And the function must dereference the pointer to make the modification.
void foo_1 (int a) {
a += 1; /* caller will not see any change to a */
}
void foo_2 (int *ap) {
*ap += 1; /* caller will see value has changed */
}
int a = 0;
foo_1(a); /* a is still 0 after return */
foo_2(&a); /* a becomes 1 after return */
The & operator results in a value that represents the address to the object it is applied to, and the resulting type is "pointer to (type of the object)". In the above example, the result of &a is "pointer to int".
Nothing is fundamentally different if the variable is a pointer type.
void foo_1 (int *a) {
a = malloc(sizeof(int)); /* caller will not see any change to a */
}
void foo_2 (int **ap) {
*ap = malloc(sizeof(int)); /* caller will see value has changed */
}
int *a = 0;
foo_1(a); /* a is still 0 after return */
foo_2(&a); /* a becomes initialized to memory allocated by malloc */
In the above example, since a is a pointer to int, type of &a is "pointer to pointer to int".
A pointer is a term that is used to refer to the address of an object. The address of an object is a value that represents where the object resides in memory. Knowing that address means the object can be read and modified. A pointer variable is a variable that can store the address of an object.
Normally, the name of a variable is used to represent the object. By object, I just mean the memory used by the variable, and its semantic representation, aka, its type (often, the terms variable and object are used interchangeably, but to me, the difference is that a variable has a name). Reading and modifying the object is done through the name. One way to obtain a pointer to an object is to apply the unary & operator to the name of a variable. A pointer variable holding that address is thus a pointer to that object. And now, that same object can be read and modified via the pointer by dereferencing the pointer, using the unary * operator.
int a = 0;
int *ap = &a;
a += 1; /* a now has the value 1 */
*ap += 1; /* a now has the value 2 */
A dynamically created object, i.e. through malloc(), does not have a name. But, malloc() returns a pointer through which the object can be read and modified.
int *ap = 0; /* ap initialized to NULL */
ap = malloc(sizeof(int)); /* ap points to dynamically allocated int */
*ap = 0; /* int pointed to by ap now holds value 0 */
*ap += 1; /* int pointed to by ap now holds value 1 */
Your allocateArray() function combines both of these uses of a pointer into a single function.
int *vector = NULL; /* vector is pointer to int variable initialized to NULL */
allocateArray(&vector,5,45); /* the address of vector is passed to allocateArray */
Since the address of vector is passed to allocateArray(), that function now has the means to modify the object named vector by derferencing the pointer value it received. The pointer value is received in the arr argument:
void allocateArray( int **arr, size_t size, int value )
And, by dereferencing arr, it is updating the vector object with the value returned by malloc():
*arr = malloc( size * sizeof( int ));
Perhaps the function would have been more clear if the allocation, initialization of the memory, and then the update of the vector variable happened in multiple steps.
void allocateArray( int **arr, size_t size, int value )
{
int *vec = malloc( size * sizeof( int )); /* vec points to size contiguous int */
if ( vec != NULL )
for ( size_t i = 0; i < size; ++i )
vec[i] = value; /* vec[i] set to value */
*arr = vec; /* return vec into first parameter */
}
Some background:
Parameters in C are always passed by value. For example, consider the code
void some_func(int i) { i = i + 2; printf("i = %d\n", i); }
void main_func() {
int n = 5;
some_func(n);
printf("n = %d\n", n);
}
Output:
i = 7
n = 5
The main function passes the value 5 to some_func, which changes its own local copy in i but cannot change n in the calling function.
Now, suppose you want to write a function that does change the caller's value. You can do this by passing the address of the variable you want to change:
void new_func(int *i) { *i = *i + 2; printf("*i = %d\n", *i); }
void main_func() {
int n = 5;
some_func(&n);
printf(" n = %d\n", n);
}
Output:
*i = 7
n = 7
The "trick" is that new_func doesn't change the value of its parameter; it changes some other value -- the variable its parameter points to. So the rule is:
If you want a function to alter a variable, you pass the address of that variable.
In other words, if you want a function to change foo, you pass a pointer to foo.
Application to your code:
The main function declared a pointer, vector, that has no memory allocated to it. Its value is NULL. It calls allocateArray() to allocate memory and assign it to vector. But that means it must change the value of vector from NULL to the address of the newly-allocated memory. Following the same rule as above, in order to change vector, you need to pass its address to allocateArray(). And since vector is of type pointer-to-int, its address is of type pointer-to-pointer-to-int.
To be clear: you haven't changed the type of vector; you've simply passed its address. So within allocateArray(), arr is of type int **, and *arr is of type int *. Syntactically, you use *arr exactly as you would use vector.
So vector is a pointer to an int, so the address of vector is a pointer to a pointer to an int(&vector is equivalent to int **). vector = *arr, not &vector = *arr. Therefore vector is gets the address that the call to malloc returns, not the address of vector. I think the confusion is between the address of vector and the address that vector points to.
Inside the function main(), vector is a single variable on the stack (probably 4 bytes). The address of the first of those 4 bytes is &vector. When you call allocateArray(), you allocate a chunk of memory on the heap. The address of those bytes has to be stored somewhere. The function stores that 4-byte address at the memory address passed to it, i.e., the bytes allocated on the stack.
So when we return to main(), the variable vector now points to the start of the allocated block. Because it is declared as a pointer to int, that memory will be accessed as an array of ints.
Memory addresses are just numbers like any other number. The "type" you assign to it in C just tells the compiler what you plan to do with the memory at that address. Declaring vector as an int * simply tells the compiler to fetch an int from memory when it sees *vector. The memory used to store the value of the variable itself is just the stack, exactly as if it had been a regular int, and that memory has nothing to do with the memory it points to.
We need to take the address of the stack variable because otherwise allocateArray() would have no way to affect the value of the variable vector, which is not defined in its scope, so we just have to tell it where to look.
Probably a better way to implement this is to remove that first argument to allocateArray() and have it return the address of the allocated block. Then we can just assign vector to that return value in main() where it's in scope.
int main( void )
{
int *vector = NULL;
allocateArray(&vector,5,45);
free( vector );
return 0;
}
As you see in the main function, when the statement allocateArray(&vector,5,45); executed,
the memory address of a 5-element array will be passed to the vector variable; However, if you use allocateArray(vector,5,45);(assume that was corrected modified), then the memory address would not passed to the vector variable, because the function allocateArray(vector, 5, 45) now just passed a value of vector into the function.

What is double star (eg. NSError **)?

So, I saw this:
error:(NSError **)error
in the apple doc's. Why two stars? What is the significance?
A "double star" is a pointer to a pointer. So NSError ** is a pointer to a pointer to an object of type NSError. It basically allows you to return an error object from the function. You can create a pointer to an NSError object in your function (call it *myError), and then do something like this:
*error = myError;
to "return" that error to the caller.
In reply to a comment posted below:
You can't simply use an NSError * because in C, function parameters are passed by value—that is, the values are copied when passed to a function. To illustrate, consider this snippet of C code:
void f(int x)
{
x = 4;
}
void g(void)
{
int y = 10;
f(y);
printf("%d\n", y); // Will output "10"
}
The reassignment of x in f() does not affect the argument's value outside of f() (in g(), for example).
Likewise, when a pointer is passed into a function, its value is copied, and re-assigning will not affect the value outside of the function.
void f(int *x)
{
x = 10;
}
void g(void)
{
int y = 10;
int *z = &y;
printf("%p\n", z); // Will print the value of z, which is the address of y
f(z);
printf("%p\n", z); // The value of z has not changed!
}
Of course, we know that we can change the value of what z points to fairly easily:
void f(int *x)
{
*x = 20;
}
void g(void)
{
int y = 10;
int *z = &y;
printf("%d\n", y); // Will print "10"
f(z);
printf("%d\n", y); // Will print "20"
}
So it stands to reason that, to change the value of what an NSError * points to, we also have to pass a pointer to the pointer.
In C everything is pass by value. If you want to change the value of something you pass the address of it (which passes the value of the memory address). If you want to change where a pointer points you pass the the addres of the pointer.
Take a look here for a simple explanation.
In C, a double star is a pointer to a pointer. There are a couple of reasons to do this. First is that the pointer might be to an array of pointers. Another reason would be to pass a pointer to a function, where the function modifies the pointer (similar to an "out" parameter in other languages).
The double star (**) notation is not specific to initializing a variable in a class. It is simply a double indirect reference to an object.
float myFloat; // an object
float *myFloatPtr; // a pointer to an object
float **myFloatPtrPtr; // a pointer to a pointer to an object
myFloat = 123.456; // initialize an object
myFloatPtr = &myFloat; // initialize a pointer to an object
myFloatPtrPtr = myFloatPtr; // initialize a pointer to a pointer to an object
myFloat; // refer to an object
*myFloatPtr; // refer to an object through a pointer
**myFloatPtrPtr; // refer to an object through a pointer to a pointer
*myFloatPtrPtr; // refer to the value of the pointer to the object
Double pointer notation is used where the caller intends that one of its own pointers need to be modified by a function call, so the address of the pointer, instead of the address of the object, is passed to the function.
An example might be the use of a linked list. The caller maintains a pointer to the first node. The caller invokes functions to search, add, and remove. If those operations involve adding or deleting the first node, then the caller's pointer has to change, not the .next pointer in any of the nodes, and you need the address of the pointer to do that.
If it is anything like C then ** means a pointer to a pointer.

Resources