Pointers: does referring to the first element help locate the entire array? - c

I am translating C code to another language. I am confused about pointers.
Say I have this code. The function foo, calls function bob, and they are both pointers.
double
*foo(double *x, double *init, double *a){
double *y = (double*)malloc(5*sizeof(double));
double *z = (double*)malloc(5*sizeof(double));
double *sum, *update;
sum = (double*)bob(y, z) //<---Q1: why y and z don't need stars in front of them?
//I thought they are pointers?
for (i<0; i<5; i++){
z[i]=y[i] //Q2: howcome it's ok to assign y to z?
} //aren't they pointer?(i.e.hold memory address)
}
double
*bob(*arg1, *arg2){
something...
}
So,
1) Why y and z don't need stars in front of them, isn't y and z just address?
2) Why sum doesn't have a star, I thought sum is declared as a pointer.
3) Why it's ok to assign y to z?
I've learned these, but they've soooo long, could someone give me a hint?

double
*foo(double *x, double *init, double *a){
// x is a pointer to a double, init is a pointer to a double, a is a pointer to a double
// foo is a function returning a pointer to a double
// and taking three pointers to doubles as arguments
double *y = (double*)malloc(5*sizeof(double));
// y is a pointer to a double. It is assigned a pointer returned by malloc.
// That pointer returned by malloc points to memory space for 5 doubles.
double *z = (double*)malloc(5*sizeof(double));
// z is a pointer to a double. It is assigned a pointer returned by malloc.
// That pointer returned by malloc points to memory space for 5 doubles.
double *sum, *update;
// sum and update are pointers to doubles
sum = (double*)bob(y, z) //<---Q1: why y and z don't need stars in front of them?
//I thought they are pointers?
// sum (whose type is pointer to double)
// is assigned a pointer to double returned by bob
for (i<0; i<5; i++){
y[i] = z[i] //and are z and y pointers?!?!
// y[i] === *(y+i)
// (y + i) points to the i-th element in the space previously allocated by malloc
// *(y + i) dereferences that pointer
// equivalently, y[i] accesses the i-th element from an array
}
if(sum<0)
z=y //Q2: howcome it's ok to assign y to z?
//aren't they pointer?(i.e.hold memory address)
// after the assignment, z contains the same address as y (points to the same memory)
}
double
*bob(*arg1, *arg2){
something...
}

Values y and z don't need stars because adding a star dereferences them, and you want to pass the pointer not the value.
Again, you want the pointer and not the value. Although from the code it appears you actually DO want the value, so there probably should be a star there.
You can assign a pointer to another pointer, this means change the address that the pointer points to. So when y=z, y now points where z points.

They don't need a star because you do not dereference them, but pass as pointers.
You can compare pointer, but that's probably not what you want.
Assigning pointers is okay, note, though, that it's not the same as copying values.

Ans for Q1: You are passing y and z to another function which take in pointers as arguments, why would you pass the value of the pointer?
Ans2: They are pointers and you are assigning one to another

Basic pointer notions:
double a = 42.0; // a is a double
double b; // b is a double
double *x; // x is a pointer to double
x = &a; // x is the pointer, we store the address of a in pointer x
b = *x; // *x is the pointee (a double), we store the value pointed by x in b
// now b value is 42.0

With regard to 2) and why z[i] = y[i] is acceptable, I think it best to point you to this page which describes arrays and pointers in some detail, especially 2.1 through 2.8. What's happening in that particular expression (not necessarily in order) is start at location y, fetch the pointer, add i to the pointer, then fetch the value pointed to at that location. Start at z, fetch the pointer, add i to the pointer, and assign the value (y[i]) to that location.

Related

Pointer Swapping Rules

I have a few questions regarding the rules of using pointers and arrays, as I am little confused about the rules regarding passing arrays around.
void f1(int* x, int* y) {
int * ptr = x;
x = y;
y = ptr;
}
void f2(int* x, int* y) {
int val = *x;
*x = *y;
*y = val;
}
void f3(int* x, int* y) {
int val = *x;
x = y;
y = &val;
}
So let's say I have two arrays, a[3] = {0,2,4} and b[3] = {1,3,5}.
If I run the lines f1(arr_a, arr_b); & printf("%d\n", *arr_a); it will print out 0. I am assuming this is because since you are only passing a pointer of the array to the function, it is only a copy of the array, so nothing is actually modified. Would this assumption be correct?
Now, if I run f2(arr_a + 1, arr_b + 1) and printf("%d\n", *(arr_a + 1));, it would result in a value of 3, and this is because since I am not using a pointer this time, I am directly using an integer (val), which is being set equal to the value of the array at an index of 1, and swapping those values. I am assuming because this manually changes the address, unlike the first function, which uses a pointer, which is a copy of the array?
And finally, for the third one, if I run f3(arr_a + 1, arr_b + 1) and printf("%d\n", *(arr_a + 1)); the value should be 2 for x and 3 for y, since x is not swapped with y because the * operator is not used (so addresses are not swapped), and y is being set to the address of val, which is some random address, which also regardless does not get swapped?
Thank you
First, when passing an array type as a function argument, the array isn't actually passed, but instead the address of the first element is passed. So for an array a, the following two calls are equivalent:
f(a);
f(&a[0]);
Regarding your specific examples:
The call f1(arr_a, arr_b); passes the address of the first element of arr_a and the address of the first element of arr_b. It's equivalent to f1(&arr_a[0], &arr_b[0]);.
Nothing is copied, other than the addresses that are passed to the function. The function itself is given its own local copies of the two address. Even though it modifies them, those changes are confined to the function, and have no effect on the caller. All it's doing is making some local variable assignments. In fact, a good optimizer would completely eliminate the function body, since it doesn't do anything.
The call f2(arr_a + 1, arr_b + 1); passes the addresses of the second elements of arr_a and arr_b. It is equivalent to f2(&arr_a[1], &arr_b[1]); Again, nothing is copied. However, function f2 dereferences those pointers, swapping their targets. So the values at index 1 in arr_a and arr_b are swapped.
The call f3(arr_a + 1, arr_b + 1); passes the addresses of the second elements of arr_a and arr_b. It is equivalent to f3(&arr_a[1], &arr_b[1]); Again, nothing is copied. The function f3 loads the value of arr_a[1], then does a few local assignments. Like f1, this function has no effect, and a good optimizer would completely eliminate the function body.
To summarize, functions f1 and f3 do nothing and their bodies will likely be optimized away. Function f2 is the only one that does something useful, which is to swap the targets of its two pointer arguments.
it is only a copy of the array, so nothing is actually modified. Would this assumption be correct?
There is no copy of array is created. When you access an array, it is converted to a pointer to first element (there are few exceptions to this rule). So, it is just the pointer to first element of array arr_a and array arr_b assigned to function f1() parameters (integer pointers) x and y respectively. In f1() function, the pointers x and y get swapped i.e. y will point to first element of array arr_a and x will point to first element of array arr_b. Function f1() result in no change in any element of array arr_a and arr_b. After calling this function, the print statement
printf("%d\n", *arr_a);
is printing 0 because *arr_a is equivalent to arr_a[0]1) which is nothing but first element of array arr_a whose value is 0.
*arr_a -> *(arr_a + 0) -> *((arr_a) + (0)) -> arr_a[0]
I am assuming because this manually changes the address, unlike the first function, which uses a pointer, which is a copy of the array?
No, it does not change the address, it changes value at the address, pointed by pointer x and y, which you have passed to function f2() as arguments. Pointer x is holding the address of second element of array arr_a and at that address, an integer value exist. When you dereference x (i.e. *x), that means, you are accessing value at that address. When you assign any value to *x, that means, you are modifying the value at that address. Same is with pointer y. When the function f2() returns the change persist because you have modified the value at the address passed to this function (using the pointer x and y).
Now the arr_a elements are {0, 3, 4} and arr_b elements are {1, 2, 5}.
The print statement
printf("%d\n", *(arr_a + 1));
will result in printing the second element of array arr_a whose value is 3.
the value should be 2 for x and 3 for y, since x is not swapped with y because the * operator is not used (so addresses are not swapped), and y is being set to the address of val, which is some random address, which also regardless does not get swapped?
In function f3(), you are passing the address of second element of array arr_a and arr_b. They get assigned to parameter x and y respectively. Lets look, what is happening after execution of each statement of function f3() body:
Statement I of f3()
int val = *x;
Pointer x is pointing to second element of array arr_a. Dereferencing x (i.e. *x) will give the value at that address which is 3 and this value assigned to a local variable val of function f3().
Statement II of f3()
x = y;
Pointer y is pointing to second element of array arr_b. After this statement, both x and y will point to second element of array arr_b.
Statement III of f3()
y = &val;
Pointer y is assigned the address of local variable val which hold the copy of value of second element of array arr_a.
So, before exiting the function f3(), x is pointing to second element of arr_b and y is pointing to a local variable val.
No changes made to any value at address passed to f3(), hence the array arr_a and arr_b state will be same after returning from function f3().
The arr_a elements are {0, 3, 4} and arr_b elements are {1, 2, 5} and printing the second element of arr_a will result in output 3.
From C Standards#6.5.2.1
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))..
it is only a copy of the array, so nothing is actually modified. Would
this assumption be correct?
In this call:
f1(arr_a, arr_b);
that would be more correctly to write like:
f1(a, b);
because you declared arrays a and b there is nothing copied. The array designators a and b are implicitly converted to pointers to their first elements. The call above is equivalent to:
f1( &a[0], &b[0]);
These pointers are passed to the function f1 by value. That is the function deals with copies of the values of the pointers.
Within the function:
void f1(int* x, int* y) {
int * ptr = x;
x = y;
y = ptr;
}
these copies are swapped. Changing the copies does not influence on the original arrays used as arguments. After exiting the function the local variables x and y will not be alive.
To make it clear consider the following code snippet. Let's assume that there are two variables a and b of the type int:
int a = 0;
int b = 1;
and then there is the following code:
int x = a;
int y = b;
int tmp = x;
x = y;
y = tmp;
As you can see it is copies of the values of the variables a and b assigned to the variables x and y were swapped. The variables a and b stay unchanged.
Now, if I run f2(arr_a + 1, arr_b + 1) and printf("%d\n", *(arr_a +
1));, it would result in a value of 3, and this is because since I am
not using a pointer this time, I am directly using an integer (val),
which is being set equal to the value of the array at an index of 1,
and swapping those values. I am assuming because this manually changes
the address, unlike the first function, which uses a pointer, which is
a copy of the array?
In this call:
f2(a + 1, b + 1);
you are again using pointers but now they are pointers to second elements of the arrays. Within the function f2:
void f2(int* x, int* y) {
int val = *x;
*x = *y;
*y = val;
}
there are swapped the second elements of the arrays pointed to by the pointers. That is for example dereferencing the pointer x like:
*x = *y;
you get a direct access to the object pointed to by the pointer x and can change the object.
The third function f3:
void f3(int* x, int* y) {
int val = *x;
x = y;
y = &val;
}
just does not make a sense. It swaps nothing. In the first declaration of the function the local variable val gets the value of the object pointed to by the pointer x:
int val = *x;
Then the local variable x gets the value of another local variable y:
x = y;
And at last the local variable y gets the address of the local variable val:
y = &val;
After exiting the function all its local variables val, x, and y will not be alive. Neither object in the arrays a and b passed to the function through pointers were not changed.

New to pointers in C

In the following code I would like to understand better what is happening with int *z = malloc(sizeof(int);
To me that creates a pointer to an int. Then *z gets the sum of the value that x points to (2) and the value that y points to (4).
Now *z = 6. Does that mean *z does not point to anything? It just stores an int? I thought *z was a pointer and a pointer is an address? Thank you for any help understanding.
int *add(int *x, int *y)
{
int *z = malloc(sizeof(int));
*z = (*x) + (*y);
return z;
}
int main(void)
{
int a = 2;
int b = 4;
int *ptr = add(&a, &b);
printf("sum = %i\n", *ptr);
}
Now *z = 6. Does that mean *z does not point to anything? It just stores an int? I thought *z was a pointer and a pointer is an address? Thank you for any help understanding.
You are correct with *z = 6 however you are wrong with how this happens.
z is a pointer and so it point somewhere into the memory. Earlier in your program, with int *z = malloc(sizeof(int)); you have allocated a space the z points to.
Then when you did *z = (*x) + (*y); you've basically put the result of the addition into that allocated space.
z still points to that space (because it is a pointer). *z is called dereferencing and has a meaning of reaching directly for the value the pointer points to.
In other words: the 6 is stored in a place the z points to and *z is a way to grab that value.
*z = 6 assigns 6 to the location pointed at by ptr. That's what a pointer does, it points to things, but in order to put a value at where it's pointing as opposed to changing the pointer you need to de-reference with the * operator.1
Imagine your memory as, conceptually, a number of bytes each of which has a number. A pointer to an int represents a particular location in memory which is presumed to hold an int, or 4 bytes worth of data.
*z = 6 means "put an integer value of 6 in the memory location described by z", which translates into machine instructions that are largely the same.
z absolutely does not "store an int", it stores a location. That location may exist, or may be NULL, or may be invalid. There's no guarantees unless you've checked your code carefully to ensure the pointer is valid. That's your responsibility as a programmer.
That's also why pointers can be tricky and frustrating. They introduce indirection in your code.
1 In C pointers are also largely interchangeable with arrays so you can do z[0] = 6, though as z only points to a single int, any index other than 0 is invalid.
int *z = malloc(sizeof(int));
this will envoke a system call for allocating one integer on the heap. z is the address of this integer return from malloc (if malloc fails to allocate z will be null)
z is a pointer to buffer allocated on the heap (if malloc success). in your case this buffer hold one integer so its a pointer to this integer.
see malloc description in man pages. malloc_man_pages
*z = (*x) + (*y);
you are right. you are assigning the value that sets in the address x and the value that sets in the address y to the place that z points to.
you dont check the return vale from malloc and this is a very bad thing. always check if malloc successd! see below. maybe you need to check the pointers that you get in x and y ?! (thats up to you, but i recommend to check).
int* add(int *x, int *y)
{
int *z = NULL;
if(x && y)
{
z = malloc(sizeof(int));
if(z)
{
*z = (*x) + (*y);
}
}
return z;
}

using pointers that have ** in c

I am very new to C and currently having some trouble with pointers and I am not sure if my logic is correct on this question clarification would be great.
Is the second expression legal? Why or Why not? What does it mean?
int** x = ....;
... **x ...
This is all the question gives and I came up with the following answer (I think its in the ballpark)
The int** x will initialize a pointer x to whatever address/value that is after the equal sign.
**x ... will dereference the pointer to a value/variable
The question link that was proposed in the edit was just showing the difference between int* p and int *p which is nothing what i asked i understand this already.
int *x is a pointer to int. int** y defines y as a pointer to pointer to int, so it points to a pointer, and the latter points to an int. Example:
int n = 42;
int* x = &n; // points to n
int** y = &x; // points to x, which points to n
In this case y is a pointer to pointer. First indirection *y gives you a pointer (in this case x), then the second indirection dereferences the pointer x, so **y equals 42.
Using typedefs makes everything looks simpler, and makes you realize that pointers are themselves variables as any other variables, the only exception being that they store addresses instead of numbers(values):
typedef int* pINT;
int n = 42;
pINT x = &n;
pINT* y = &x; // y is a pointer to a type pINT, i.e. pointer to pointer to int
If you use double * you are telling the compiler you want a pointer pointing to another pointer:
int x = 4;
int *pointer = &x;
int **pointer_pointer = &pointer;
printf("%d\n",**pointer_pointer); // This should print the 4

Pointers and Memory Allocation in C

Program:
int x;
int *y;
int **z;
z = (int **) malloc (sizeof(int *));
y = (int *) malloc (sizeof(int));
x = 1;
*z = &x;
*y = x;
.
.
.
Question:
What is the difference between:
*z = &x;
*y = x;
From what I understand *z points to the address of x and *y points to x, but for *y to point to x doesn't that require the address of x? I don't really understand what's going on with these two variables.
Edit:
I also want to know when do we know when a variable is allocated on the stack or on the heap?
Why is x,y, and z allocated on the stack?
Why is *y, **y, *z, **z, allocated on the heap?
Finally, does changing *z, change **z?
z is a pointer to a pointer (which will typically point to a dynamically allocated array of pointers).
y is a pointer to int. Again, more often than not it'll point to a dynamically allocated array of ints.
So, the *z = &x; is setting the pointer that z refers to to point at x. I.e., z points at a pointer, which (in turn) points to x.
*y = x; is taking the value of x and assigning it to the int pointed to by y.
For things like this, a picture is often helpful. So, our basic definitions give us this:
The we do:
z = (int **) malloc (sizeof(int *));
y = (int *) malloc (sizeof(int));
Which gives us this:
Then we do:
*z = &x;
*y = x;
Which gives us this:
In all of these, a dashed line signifies a pointer from one place to another, while the solid line indicates copying a value from one place to another.
We can then consider the long-term differences between them. For example, consider what happens if we add x=2; after all the assignments above.
In this case, *y will still equal 1, because we copied the value 1 from x to *y. **z will equal 2 though, because it's just a pointer to x -- any change in x will be reflected in **z.
This line stores the address of variable x in the memory pointed to by z:
*z = &x;
This line stores the value of x into memory pointed to by y:
*y = x;
The two assignment statements are unrelated: the second one makes a copy, while the first one does not. If you change the value of x and then retrieve **z, you will see the new value of x; however, retrieving *y would give you back the old value of x (i.e. 1).

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