I am writing a shader for OpenGL and I need to be able to pass in an array of data. I need to be able to pass by reference because I cannot copy the whole array. I know that you cannot define a pointer to an array of structs with Vertices *v[100]; because this will create an array of pointers.
I think you can pass the memory location of the first element in the c array with bindArrayFunction(&v); but then how should I use it? Would I increase the pointer by the size of the struct to get every vertex?
Any help or comments would be appreciated.
In C and C++, an array is never passed by value.
When an array type appears in a function declaration (as in void f(int a[])), the type is implicitly converted to the corresponding pointer type (as in void f(int* a)).
When you use the name of an array in most expressions, it is implicitly converted to a pointer to its first element. So, given int v[100], when you call f(v), a pointer to the initial element of v is passed. (There are several exceptions to the implicit conversion, most notably when the array is the operand of the sizeof or unary & operator).
Pointer arithmetic is always done in terms of the size of the pointed-to element. So, given v + 1, the array v is implicitly converted to a pointer to its initial element (equivalent to &v[0]) and is incremented by sizeof(int) bytes, to point to v[1].
Just reference it as though it were an array.
void bindArrayFunction(Vertices *v, int size) {
for (int i = 0; i < size; ++i) {
process(v[i]);
}
}
In most situation, an array decays to a pointer to its first element. So if you have a function:
void foo(int *p)
{
printf("%d\n", p[2]);
}
then these two calls are identical:
int array[10];
foo(array);
foo(&array[0]);
In both case, a single pointer is passed to the function, allowing the function to access the entire array.
Related
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.
int array[5];
Expressions such as
array[3] gets converted to *(array+3)
Or in
void fun ( int *array[] );
*array[] gets converted to int **array
I was wondering what does the array declaration
int array[5];
Get converted to? Is it
int *(array+5)
If yes, what does this even mean? And how does one interpret it and/or read it?
array[i] gets converted to *(array+i)
Correct, given that array[i] is part of an expression, then array "decays" into a pointer to its first element, which is why the above holds true.
Void fun ( Int *array[] );
*array[] gets converted to Int **array
Yes because of the rule of function parameter adjustment ("decay"), which is similar to array decay in expressions. The first item of that array is an int* so after decay you end up with a pointer to such a type, a int**.
This is only true for functions with the specific format you posted, there is otherwise no relation between pointer-to-pointers and arrays.
I was wondering what does the array declaration
Int array[5];
Get converted to?
Nothing, declarations don't get converted. It is an array of 5 integers.
To sum this up, you actually list 3 different cases.
When an array is used as part of an expression, it "decays" into a pointer to the first element.
When an array is used as part of a function parameter declaration, it "decays" too - it actually has its type replaced by the compiler at compile-time - into a pointer to the first element. C was deliberately designed this way, so that functions would work together with arrays used in expressions.
When an array is declared normally (not part of a parameter list), nothing happens except you get an array of the specified size.
I think you are confusing two things.
*(array+i)
cannot be used for declaration, only for accessing the memory location (array being the starting address and i the offset)
also, the following declaration will create an array of 5 integers onto the stack
int array[5];
You can access any element from the array with the other notation, because values are being pushed onto the stack. The following two yielding in the same result:
int a = *(array+3);
int b = array[3];
if (a == b) printf("Same value");
else printf("Not same value");
So this was presented in our class (I was absent that time):
typedef struct{
int *items;
int size;
int max;
}list;
and a list was passed to a function:
void append(list *l, int x){
if(l->size==l->max){
expand(l);
}
l->items[l->size++] = x;
}
My question is, how can an int pointer have an index? I thought indexes were used on arrays? Can that be done?
I'm new to C. So yeah.
A pointer can point at either 1 or n elements of its type. There is no way of telling which it is just from the declaration. We can assume that items is the address of the first element of an array. Since arrays store their elements in sequence, when you index the pointer, you really apply an offset from the first address. Hence, you index into the array that the pointer points at.
int values[5]; // Simple array.
int* p = values; // p points to the first element of the array values.
p[2] = 34; // Equivalent to values[2] = 34;
A pointer is simply the address to the memory space allocated for your object/array/int.
You can have a pointer to anything memory-related in C. You just say, here is my int, here is my array, etc...
How to turn an int pointer to an array
Strictly speaking: You cannot.
Any pointer can be treated as an array. An array is a sort of 2nd class citizen, and in most places the compiler treats an array as a pointer, and whenever an array is passed to a function, the compiler actually passes the address of the first element of the array. In fact, a[b] is considered to be *(a + b) (which can lead to some pretty incomprehensible code!)
So in your structure, items can be treated as a plain integer pointer, or the address of an array (as is done here).
This is causing me a great deal of confusion.
If I have the following array:
int arr[6];
// I then fill indices 0-5 with ints
And I want to pass that to a function that uses the array as a parameter, what does the function header look like?
Would it be void saveArray(int *arr) or void saveArray (int arr)? And then how would I call the function? saveArray(arr) or saveArray(&arr)?
As I understand it, while that initial array is not a pointer, it effectively acts as one as it decays into a pointer to the first element. So my intuition it that I should pass it like saveArray(arr) and the header should be void saveArray(int *arr). Would that be right?
Why do I want a pointer to the initial array and not just the array itself? What does &arr even represent?
In C, parameters passed in functions can only be passed by value.
In addition to that, in C you can't pass an array as a parameter to a function. However, you can pass by value a pointer to the first cell of the array.
Thus, your function's prototype would be:
void saveArray(int *arr)
which you'd call by
saveArray(arr);
Why do I want a pointer to the initial array and not just the array
itself?
That's because you cannot pass an array to a function. An array is not a first-class object in C unlike int, float, struct etc. This means an array is not copied to the function parameter. What actually gets passed is a pointer to the first element of the array. Therefore, the function parameter should be a pointer to the array element type. Also, you have to pass the length of the array to function as well since that information cannot be had in the function from the pointer that is passed to it.
An array is a different type than a pointer. There are some cases when it decays or is implicitly converted to a pointer to its first element. Therefore, your function should have the prototype
void saveArray(int *arr, int len);
// or
void saveArray(int arr[], int len);
// in main, for example
int arr[6];
saveArray(arr, sizeof arr);
// equivalent to
saveArray(&arr[0], sizeof arr);
What does &arr even represent?
The address of operator & evaluates the address of its operand which must be an lvalue. Here arr is of type int[6], i.e., an array of 6 integers. Therefore &arr is of type int (*)[6], i.e., a pointer to an array of 6 integers. Please note that the value &arr is equal to the base address of the array but its type is not int *. It is a different type and has different pointer arithmetic. This is, in fact, one of the cases where an array does not decay into a pointer to its first element.
Yes
void saveArray(int *arr)
But for it to be useful, pass the array length too.
void saveArray(int *arr, int len)
Otherwise how will you know how long it is?
Call then like so:
saveArray(arr, 6);
The question "Would it be void saveArray(int *arr) or void saveArray (int arr)?" has already been answered. I am going to answer the question "What does &arr even represent?"
In your case, &arr has the same numerical value as &arr[0]. However, if you did something a bit different,
int* arr = malloc(sizeof(int)*6);
Then the numerical value of &arr will be different than that of &arr[0] even though you will be able to call saveArray(arr) without any difference in meaning for both cases.
In the first case, both &arr and &arr[0] are addresses on the stack.
In the second case, &arr is an address on the stack while &arr[0] is an address in the heap.
Hope that helps.
If you use this prototype:
void saveArray(int *arr)
you loose information about the array length (e.g. number of elements).
Unless your function is supposed to operate on arrays with fixed length (e.g. some functions doing 3D math calculations may just consider 3D vectors, with fixed size of 3 double elements), you should specify the array length (e.g. element count) as an additional parameter:
void saveArray(int * arr, int count);
If your function just observes the content of the input array and does not modify it, you can use const to make your code const-correct and more precise:
void saveArray(const int * arr, int count);
Sometimes size_t is used as a type to specify length/count parameters:
void saveArray(const int * arr, size_t count);
About the other option you listed in your question:
void saveArray(int arr)
That is wrong, since in this case arr is just a single integer (not an array).
Instead, in the first (correct) case of passing [const] int*, you passed the address of the first item in the array, and since the array elements are stored in contiguous memory locations, just the address of the first item and the item count define the whole array.
At the call site, you can call your function like this:
int arr[<<some size here>>];
...
saveArray(arr, <<same size as above>>);
Or if you already have a pointer (e.g. since you allocated the array using malloc()), you can just specify the pointer itself:
int* arr;
arr = malloc( numberOfElements * sizeof(int) );
...
saveArray(arr, numberOfElements);
I want to manipulate an array of integers in a function, but I am not sure if I should use the address prefix or the pointer prefix:
void shuffle(int *deck[]){
//statements
}
or
void shuffle(int &deck[]){
//statements
}
Further, when I directly want to manipulate the values of the array, I'm not sure if I should use (within the function)
*deck[4] = 34
or something else.
Any clarification is appreciated.
There are no references in C(your Q is tagged C only) so you will have to use the pointer version.
When you say pass an array to the function, what you essentially pass to the function is the pointer to its first element, both of the following two syntaxes mean one and the same thing to the compiler:
void shuffle(int *p_deck);
void shuffle(int deck[]);
Neither.
Since arrays can be passed by reference only, you don't need to do tricks, just pass a pointer and dereference it. (That syntax involving the & in your 2nd function is not valid, anyway). So:
void shuffle(int arr[])
{
arr[0] = 1337;
}
or
void shuffle(int *arr)
{
}
etc. And you can pass it like this:
int deck[52];
shuffle(deck);
You would have to use the pointer version, but because of the Right-Left Rule, I believe your:
int * deck[] would actually be an array of int pointers, instead of an array of ints.
http://cseweb.ucsd.edu/~ricko/CSE131/rt_lt.rule.html
You should just pass a reference to the first element in the array:
int * deck but you may want to pass in the size of the array so you avoid going out of bounds.
Arrays decay into pointers when passed to functions, so there's no point in using an additional level of indirection here.
According to §6.3.2.1 of the C99 standard,
Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
void shuffle(int deck[]) {
...
}
Note that C does not support references, only pointers. You're probably thinking of C++.
You can pass an array by reference in C++, if you specify the size of the array:
void shuffle(int (&deck)[52])
{
deck[4] = 34;
}
If you don't know the size, or if you're limited to C, you need to use pointers.
The other (C++) option is to use a vector for the deck and pass a reference to the vector instead.
C doesn't have references (a), that's C++.
In C, arrays of X decay into a pointer to X[0] when passed to functions, so one way is to use:
void shuffle (int *pDeck) {
// use pDeck[something]
}
:
int deck[] = {0,1,2,3,4,5,6,7,8,9};
shuffle (deck);
I actually prefer that method to the void shuffle (int pDeck[]) variant since the former makes it absolutely clear that you're now dealing with a pointer rather than an array.
The reason this is important is because you lose the size information when you do that, so you may want to pass that in as well:
void shuffle (int *pDeck, size_t sz) {
// use pDeck[0 thru sz-1]
}
:
int deck[] = {0,1,2,3,4,5,6,7,8,9};
shuffle (deck, sizeof (deck) / sizeof (*deck));
(a): Although they are a very nice feature. I do hope that ISO considers them for the next C standard, since a large number of problems newcomers to the language have are involved with pointers, and references can hide the complexity of that very well.