Experimenting with pointers of arrays in C - c

I have an array a whose values I wish to modify through another function. This is the code that I have:
#include "stdlib.h"
#include "stdio.h"
void myfunc(int* );
int main() {
int *a, i;
a = (int*) calloc(10,sizeof(int));
myfunc(&a);
for (i=0; i<10; i++) printf("%d\n", a[i]);
return 0;
}
void myfunc(int* a) {
int i;
for (i=0; i<10; i++) *a[i] = i;
}
Obviously something is wrong with my syntax and I Was wondering if someone could lend me a hand :)
Thanks!

In the main function, you've got a pointer to an integer, a. Then you pass the address of this pointer to myfunc, but myfunc is expecting a pointer to an int, not a pointer to a pointer to an int. You need to change your call to myfunc to this:
myfunc(a);
But, you've also got a problem inside myfunc. You don't need to dereference a[i] since that indexes into an array a. These are (effectively) the same thing:
a[i]
and
*(a+i)
(This isn't 100%, I think, because in C pointers and arrays are not completely the same thing, so some expert C programmer can correct me)
You're probably just get a bit confused by the collection of syntax around pointers and arrays:
&a
*a
a[i]
*(a+i)
The first one is the address of a, the second dereferences a as a pointer, the third is an index into an array and the fourth is dereferencing a as a pointer with an offset.
You would only want to do this *(a[i]) if you had an array of pointers, not a pointer to an int.

you already declare "a" as a pointer when you say its type is "int*". Therefore, when you try and call your function "myfunc" you don't need to take the address of "a". This will make it a pointer to pointer or "int**". If you want to change the location of where a pointer is pointing, you might use that, but in your case where you just want to change the data it is pointing at, your myfunc is declared fine and you should just change the call of your function from:
myfunc(&a);
to
myfunc(a);
Also inside your function the "a" variable is already a pointer so to access an element in the array it is pointing to, you don't need to dereference it first. You should just use a[i] instead of *a[i].

It is enought to call myfunc(a) instead of myfunc(&a), then inside the function you use a[i] directly. By declaring myfunc(&a) you are passing an int ** that allow you to allocate the array from *inside the function and returning to the caller to use it.

You don't need *a[i] = i; you can just put a[i] = i; (and modify your function call as Felice pointed out).

Since a is int* , &a will be int**. So you should change your function signature to void myfunc(int** a);

Related

c pointer being passed to a function

int func(int a[]);
int main()
{
int c = 21;
int *b;
b=&c;
printf("%d",b);
func(b);
return 0;
}
int func(int a[]){
printf("\n%d",(a));
printf("\n%d",*(a));
printf("\n%d",(a[0]));
printf("\n%d",(a[1]));
printf("\n%d",(a[2]));
}
this is something I'm trying to understand how these pointers work with arrays.
this is the output.
-680548828
-680548828
21
21
-680548828
32767
the first two 680548828 and the two 21s I understand. simply printing a would be the first element of array a[]. a[0] is like writing *a. what I dont get is why a[1] would have 680548828 in it. a[1] is the element in the array after the element where the pointer to 21 is stored(a[0])? sorry for the confusion please help. Thank you.
In your code
printf("%d",b);
invokes undefined behaviour, as you;re trying to print a pointer using %d. The correct way would be to use
%p format specifier
cast the argument to void *
The same logic is applicable to the called function also, remember, an array name decays to the pointer to teh first element, basically yields a pointer type, in most of the cases (including this specific usage).
That said, you are trying to access invalid memory in the called function. You passed a pointer to one int, and in the called function, you're trying to access memory outside the memory region, by saying a[1], a[2] etc. You cannot do that. It again invokes undefined behaviour.

How to properly allocate memory for an array pointer passed as an argument in C

I am mixed up on my pointers and references. I want to create a pointer in a main function and set it to null. I would like to pass that pointer to another function that creates an array on the heap, fills it, and returns the size of the created array.
I tried to find another article about this topic but failed to find one that allocated memory from within the function. The example code below illustrates the concept but I am not writing a program to accomplish any specific task.
int fillarray(/* pointer to an array */){
// malloc the array to size n
// fill array with n elements
return n;
}
int main(){
int* array = NULL;
int size = fillarray(/* pass the pointer by reference */);
for(int i = 0; i < size; i++) printf("%d\n", array[i]);
free(array);
return 0;
}
UPDATE:
Thank you all for your comments. I learned a ton about pointers working through this problem. The code below accomplishes what I need it to. Thank you #Lundin. Your answer led me to the actual solution. Thank you #ssd as well. Your visual helped me gain some intuition on what I was looking at in the code.
int fillarray(int** array){
*array = (int*)malloc(2 * sizeof(int));
(*array)[0] = 0;
(*array)[1] = 1;
return 2;
}
int main(){
int* array = NULL;
int size = fillarray(&array);
for(int i = 0; i < size; i++) printf("%d\t", array[i]);
return 0;
}
Strictly speaking there are no "references" in C, everything is passed by value. Although the term "pass by reference" is language agnostic and really just means pass an address to the data. (C++ has a language concept called references, but it's really just glorified read-only pointers.)
So to achieve what you want, you have to pass the address of the pointer itself. That way, the function can access the pointer and set it to point at a new address. Thus declare the function as int fillarray (int**)call the function as fillarray(&array). The result of malloc needs to be assigned to where the pointer-to-pointer points at - it points at the address of the original pointer declared variable in main().
As for allocating a variable size, you will have to add an additional plain integer parameter to the function for that.
I do agree & consent Lundin's answer but to be more conceptual, I'll add the drawing below, for I had the same pain in the past understanding pointers.
The first integer pointer below (int *a) is at memory address 4c4b40 and its value is set to zero (which means this pointer a is set to null).
The second integer pointer (int *b) is at memory address 4c4b48 and its value is set to 4c4b58 (which means, this pointer points to memory address 4c4b58 with a length of integer). If that address corresponds to variable int x = 16 (hexadecimal 10 is equal to 16), then dereferencing pointer b will give you an integer value of 16 (*b = 16 because x = 16).
The third memory is another character string pointer, which points to a memory address somewhere down below.
Returning to the answer:
If you are to change the address of the first pointer (a) in order to point to the variable x, then the function you're calling needs to receive the address of the pointer (not the pointer, itself); i.e. &a instead of a, which corresponds to 4c4b40. The function called will receive the address 4c4b40 as a memory address and change its value from 000000 to 4c4b58. The function decoration, of course, will contain an int **; for, if an integer pointer is an int *, a pointer to a pointer will be an int **.

passing structure array to function

I've been learning C for about 2 months, still a novice:(
I know there are other similar questions on this site. I've read them, but still couldn't really understand, so here I am. Below is my code:
//naming my structure as ball
typedef struct ball_room {
int enter;
int exit;
} ball;
//I've omitted some irrelevant details for brevity
int i, n, max;
scanf("%d", &n);
ball person[n];
.../*assign values to ball.enter and ball.exit with user input*/
max = 1;
for (i = 0; i < n; i++)
if (ball_room(person, person[i].enter, n) > max)
max = ball_room(person, person[i].enter, n);
printf("%d\n", max);
return 0;
}
and below is my function receiving the array:
//This function returns the number of people in the ballroom
//when b[j](person[j] in "main") enters
int ball_room(ball *b, int i, int n)
{
int people = 0, j;
for (j = 0; j < n; j++)
if (b[j].enter <= i && b[j].exit > i)
people++;
return people;
}
my question is that why is it b[j].enter instead of b[j]->enter, which my compiler wouldn't accept?
In my limited experience, when manipulating structure itself (the object), I use . to go inside the structure, and when it's a pointer (the address), I use -> (hope this is correct.)
And in this case, I pass the array to function using ball *b, which represent the address of person[0], so I can access the whole array. But shouldn't ball *b be in the form of a pointer and therefore I should use -> to access its content? It's just an address that I pass to the function.
This is my first time doing something with an array of structures, please help me get this clear, thank you!
Given ball *b, b[j] is an element from the elements that b points to. Thus b[j] is not a pointer; it is a struct. Since it is a struct, you use . to refer to members in it.
The definition of b[j] in the C standard is that it is *((b)+(j)). So it takes the pointer b, moves j elements beyond it, and then applies *.
Since * is already applied in b[j], you do not need ->, just ..
you use . instead of -> because of this declaration of parameters:
int ball_room(ball *b, int i, int n)
b is expected to be pointer to data with type ball, so you can access it in various ways:
array way: e.g. b[5].somefield = 15 - you use dot here, because if b is of type ball *, it means that b is pointer OR it is array of objects with type b, if it's array of objects with type b (which is your case) you use . to access fields of object
pointer way: e.g. (b+5)->somefield = 15 - it will do exactly same thing as code above, but you will access data in pointer way
In C/C++ an array devolves into the address of it's first member. So when you pass the array to ball_room what actually gets passed is &ball[0].
Now inside ball_room the reverse happens. b is a pointer to ball. But here you use it as an array b[j]. So it un-devolves back into an array of structs. So what b[j] gives you is the struct and not a pointer to a struct. Consequently you access it using . instead of ->.
You can also use (b + j)->somefield. Or for even more fun how about writing j[b].somefield. The later being a really confusing left-over from the eraly compiler days when a[b] truly got turned into *(a + b) internally.
For explanation of the current issue, see Eric's answer; in some of the answers given so far there is dangerous wording applied, so just to make clear: When do we have an array and when a pointer???
Consider the following:
int a[7];
As long as we can refer to a directly, we still have an array and can use any operations that are valid on, e. g. getting size:
size_t n = sizeof(a); // size in bytes, not ints, i. e. 7*sizeof(int)
You can pass arrays to functions or even do pointer arithmetics on:
f(a);
a + 1;
In both cases, the array "decays" to a pointer, though, and the result is a pointer as well. Be aware that you can assign new values to a pointer, but not to an array itself (you can assign new values to the array's elements, directly or via pointer), so you cannot do things like ++a either.
When an array decays to a pointer, it gets a pointer to its first element:
int* ptr = a;
int* ptr = &*a; // only pointers can be dereferenced -> a decays!
int* ptr = &a[0]; // short for &*(a + 0)...
All result in exactly the same; however, the following is invalid:
int* ptr = &a;
Taking the address of an entire array actually is possible, but the resulting pointer is not of type "pointer to element" nor of type "pointer to pointer to element" (int** in the example), but of type "pointer to array of specific size". Syntax for is ugly, though, but the following would be legal again:
int(*aptr)[7] = &a;
You need to read: if I dereference ptr, I get int[7]...
Once decayed, there is only a pointer to the array left (more precisely: to one of the array elements, directly after decaying, to the first; array and first element always share the same address, so, although of different type, both pointers ptr and aptr from above hold exactly the same value). Pointers can be moved around within the array, but they do not hold as much information as the array itself, especially, the array size gets lost. This is why one needs to pass the array's length together with the pointer to functions (if needed; another variant is a sentinel value denoting the array end such as the terminating null character in strings or the null pointer following the string arguments in main's arguments list):
int a[7];
f(a, sizeof(a)/sizeof(*a)); // division: sizeof is in bytes, dividing by size
// of first element gives number of elements
Possibly with f as:
void f(int b[], size_t n)
// ^^^^^^^ in function parameter lists, just alternative syntax for int* b !!!
// however, we can show more explicitly that we expect a pointer
// to an array this way...
{
size_t m = sizeof(b); // as b is a POINTER, gives the constant (but hardware specific!)
// size of a pointer (on typical modern 64-bit hardware 8 bytes),
// no matter what size of the array being pointed to is!!!
while(n)
{
*b++ = n--;
// ^^ advances pointer, NOT array!
}
}
Hope this helps to avoid confusion.
In C, the array name is a pointer to array’s first element, hence your function declaration has name ball *band works when you pass a ball[] instance.
Try dynamically allocating the memory by using malloc() and passing that pointer to your function.

Copy of address in C?

I know that this code:
void incVar(int i){
i++;
}
We know this will create a copy of the integer and then increase that value, but not the actual value.
By nature: Methods in C create copies of parameters in their Stack Frame and not the original variable.
But:
void incVar(int *i){
(*i)++;
}
Is supposed to increase the actual value of the integer by the pointer dereference.
But then, why doesn't C just create a copy of the pointer *i instead? If this is the normal behavior with regular integers, then why doesn't the same thing happen with pointers?
It is the same with pointers. All variables in C are passed by value, even pointers.
You copy the address stored in the pointer outside the function, into its parameter.
But you can use that address to reference a variable which can be allocated anywhere. So in the following code:
int j = 0;
incVar(&j);
incVar receives by-copy the address of j. But it can use that address to read or modify j (in)directly.
In fact the same thing as with values happens with pointers. Just make sure to understand the syntax correctly. You are not passing the integer *i by copy to incVar, but you are passing the pointer i of type int* by copy. No matter how often you copy the pointer to an address, it always points to the same address. So i in your second incVar example points to the integer the caller took the address of. So by derefencing the copy of the pointer (in (*i)++), you are acessing the integer of the caller.
Its better to see int *i; as a variable named i of type pointer-to-int, instead of a pointer named *i.
In your example:
void incVar(int *i) {
(*i)++;
}
We probably use it as such in the main function:
int a = 5;
incVar(&a); //After this line, a is now 6.
What happens in incVar(..) is this:
A variable i is created, of type pointer-to-int.
It holds a copy of the value of &a.
Although i is a copy, its value is the same as that of the value of &a, and it still points to the same integer a.
As a result, by de-referencing i, I refer to the integer a.
Increment the integer a, which obviously is at the address pointed to by i.

Store pointer value

As I know, when a pointer is passed into a function, it becomes merely a copy of the real pointer. Now, I want the real pointer to be changed without having to return a pointer from a function. For example:
int *ptr;
void allocateMemory(int *pointer)
{
pointer = malloc(sizeof(int));
}
allocateMemory(ptr);
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays? Not by subscript, but by pointer arithmetic. Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself. For example:
int *a;
why not:
allocateMemory(*a)
but
allocateMemory(a)
I know I always have to do this, but I really don't understand why. Please explain to me.
The last thing is, in a pointer like this:
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer? I always think a is the memory address of the actual value it is pointing, but I am not sure about this. By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
I'll try to tackle these one at a time:
Now, I want the real pointer to be changed without having to return a pointer from a function.
You need to use one more layer of indirection:
int *ptr;
void allocateMemory(int **pointer)
{
*pointer = malloc(sizeof(int));
}
allocateMemory(&ptr);
Here is a good explanation from the comp.lang.c FAQ.
Another thing, which is, how can I allocate memory to 2 or more dimensional arrays?
One allocation for the first dimension, and then a loop of allocations for the other dimension:
int **x = malloc(sizeof(int *) * 2);
for (i = 0; i < 2; i++)
x[i] = malloc(sizeof(int) * 3);
Again, here is link to this exact question from the comp.lang.c FAQ.
Is this:
int array[2][3];
array[2][1] = 10;
the same as:
int **array;
*(*(array+2)+1) = 10
ABSOLUTELY NOT. Pointers and arrays are different. You can sometimes use them interchangeably, however. Check out these questions from the comp.lang.c FAQ.
Also, why do I have to pass in the memory address of a pointer to a function, not the actual pointer itself?
why not:
allocateMemory(*a)
It's two things - C doesn't have pass-by-reference, except where you implement it yourself by passing pointers, and in this case also because a isn't initialized yet - if you were to dereference it, you would cause undefined behaviour. This problem is a similar case to this one, found in the comp.lang.c FAQ.
int *a;
Is a the address of the memory containing the actual value, or the memory address of the pointer?
That question doesn't really make sense to me, but I'll try to explain. a (when correctly initialized - your example here is not) is an address (the pointer itself). *a is the object being pointed to - in this case that would be an int.
By the way, when printing such pointer like this:
printf("Is this address of integer it is pointing to?%p\n",a);
printf("Is this address of the pointer itself?%p\n",&a);
Correct in both cases.
To answer your first question, you need to pass a pointer to a pointer. (int**)
To answer your second question, you can use that syntax to access a location in an existing array.
However, a nested array (int[][]) is not the same as a pointer to a pointer (int**)
To answer your third question:
Writing a passes the value of the variable a, which is a memory address.
Writing *a passes the value pointed to by the variable, which is an actual value, not a memory address.
If the function takes a pointer, that means it wants an address, not a value.
Therefore, you need to pass a, not *a.
Had a been a pointer to a pointer (int**), you would pass *a, not **a.
Your first question:
you could pass a pointer's address:
void allocateMemory(int **pointer) {
*pointer = malloc(sizeof(int));
}
int *ptr;
allocateMemory(&ptr);
or you can return a pointer value:
int *allocateMemory() {
return malloc(sizeof(int));
}
int *ptr = mallocateMemory();
I think you're a little confused about what a pointer actually is.
A pointer is just variable whose value represents an address in memory. So when we say that int *p is pointer to an integer, that just means p is a variable that holds a number that is the memory address of an int.
If you want a function to allocate a buffer of integers and change the value in the variable p, that function needs to know where in memory p is stored. So you have to give it a pointer to p (i.e., the memory address of p), which itself is a pointer to an integer, so what the function needs is a pointer to a pointer to an integer (i.e., a memory address where the function should store a number, which in turn is the memory address of the integers the function allocated), so
void allocateIntBuffer(int **pp)
{
// by doing "*pp = whatever" you're telling the compiler to store
// "whatever" not in the pp variable but in the memory address that
// the pp variable is holding.
*pp = malloc(...);
}
// call it like
int *p;
allocateIntBuffer(&p);
I think the key to your questions is to understand that there is nothing special about pointer variables. A pointer is a variable like any other, only that the value stored in that variable is used to represent a position in memory.
Note that returning a pointer or forcing the caller to move the pointer in an out of a void * temp variable is the only way you can make use of the void * type to allow your function to work with different pointer types. char **, int **, etc. are not convertible to void **. As such, I would advise against what you're trying to do, and instead use the return value for functions that need to update a pointer, unless your function by design only works with a specific type. In particular, simple malloc wrappers that try to change the interface to pass pointer-to-pointer types are inherently broken.

Resources