Pass an array by reference into function argument - c

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.

Related

C Different method of passing matrix of pointers to function

I want to pass this two dimensional array of pointers to a function:
array:
*cmd[maxCmdSize][maxArgSize]
function:
void performCmd(char *cmd[maxCmdSize][maxArgSize])
How to achieve this without declaring the size of the dimensions in the function?
How to achieve this without declaring the size of the dimensions in the function?
You cannot omit the second dimension of the array.
So you need to have your prototype like this:
void performCmd(int *cmd[][maxArgSize]);
and call the method like this:
performCmd(cmd);
With VLA parameters (VLAs, i.e., variadic-length arrays, are an optional standard extension of C11), you can
pass the size as another parameter (which needs to preceede the VLA).
The innermost index, where the array decays to a pointer (an int *cmd[][maxArgSize] in a function parameter is equivalent to int *(*cmd)[maxArgSize]) need not be passed an does not affect multidimensional array-based pointer arithmetic.
int performCmd(int maxArgSize, char *cmd[][maxArgSize]);
int performCmd(int maxArgSize, char *cmd[][*]); //compatible alternative declaration
int performCmd(int maxArgSize, char *cmd[][maxArgSize])
{
return &cmd[1][0]-&cmd[0][0]; //returns maxArgSize
}
Also in a declaration (but not definition), the VLA size can be replaced with *.
(In the definition then, the size can also be any nonconst expression (including possibly a function call) not necessarily just a simple variable reference.)
Without VLA support you can simply pass a pointer to the base type and the dimensions, and then use that to emulate multidimensional pointer arithmetic on the base array.
Given, for example char x[2][3][4][5];, &x[1] means (char(*)[3][4][5])x + 1, (i.e., (char*)x+1*(3*4*5)), &x[1][1] means (char (*)[4][5])((char(*)[3][4][5])x+1) + 1 (i.e., (char*)x+1*(3*4*5)+1*(4*5)), etc. This works the same when the array dimensions are dynamic, and then you can use this math to translate a dynamic dimension, a base pointer, and a set of indices into an offset without having to rely on VLA support.
You would probably have to pass a char double pointer, and the two dimensions as other parameters.
void performCmd(char** cmd, int maxCmdSize, int maxArgSize) {
//do whatever this function does
}

C pointer notation compared to array notation: When passing to function

My question is base on the following code:
int myfunct(int ary[], int arysize)
int myfunct2(int *ary, int arysize)
int main(void){
int numary[10];
myfunct(numary, 10)
myfunct2(numary, 10)
return;
}
int myfunct(int ary[], int arysize) {
//Whatever work is done
}
int myfunct2(int *ary, int arysize) {
// Whatever work is done
}
Is there a reason to use one of these over the other? To elaborate, when concerned with numeric arrays, is there any reason one would want to use pointer notation over array notation. If one uses pointer notation then within the function pointer arithmetic would be used etc.. AND if one uses the [] array notation, one could work with the array as usual. I'm new to programming and I currently do not see any benefit to using the pointer notation.
My precise question, is there any reason to pass a numeric array to a function using pointer notation and therefore using pointer manipulations within the function.
When you declare a function parameter as an array, the compiler automatically ignores the array size (if any) and converts it to a pointer. That is, this declaration:
int foo(char p[123]);
is 100% equivalent to:
int foo(char *p);
In fact, this isn't about notation but about the actual type:
typedef char array_t[42];
int foo(array_t p); // still the same function
This has nothing to do with how you access p within the function. Furthermore, the [] operator is not "array notation". [] is a pointer operator:
a[b]
is 100% equivalent to:
*(a + b)
There is no real functional difference between the two notations. In C, when you pass an array variable to a function, it decays to a pointer regardless of the notation. However, in my opinion, the pointer notation is preferable. The problem with [] notation in function definitions is that, in my opinion, it is somewhat misleading:
void foo(int array[])
{
}
A ubiquitous mistake among novice C programmers is to assume that sizeof(array) will give you the number of elements in the array multiplied by sizeof(int), like it would if array were an array variable declared on the stack. But the reality is that array has been decayed to a pointer, despite the misleading [] notation, and so sizeof(array) is going to be sizeof(int*). array is really just a pointer to the first element, or possibly a pointer to a single integer allocated anywhere.
For example, we could call foo like this:
int x = 10;
foo(&x);
In which case the [] notation in the definition of foo is kind of misleading.
Those declarations are absolutely identical. To quote the standard:
A declaration of a parameter as "array of type" shall be adjusted to
"qualified pointer to type"
C99 standard section 6.7.5.3 paragraph 7
In modern C that has variable length arrays since C99, the array notation is preferable if is an array, I think. For one dimensional arrays, you can do things like
int myfunct(size_t size, int array[size]) {
... array[i] ..
}
and for two dimensional
int myfunct(size_t size, int array[size][size]) {
... array[i][j] ..
}
So array notation fits much better in the general picture. A sophisticated compiler could then even do bounds checking, but I don't know of any that does this yet.
In my opinion, the main reason to prefer pointer notation over empty array notation in function prototypes is that the latter is not consistent with structure definitions:
struct person {
char *firstname;
char *lastname;
};
void setperson(struct person *p, char firstname[], char lastname[])
{
p->firstname = firstname;
p->lastname = lastname;
}
In structures you will have to use the pointer notation anyway because empty array notation is only valid, at least since C99, for the last member when you want to make it a flexible array member.
You only need to use the array notation for multidimensional arrays. (You do not have to provide the size of the first dimension).

How to point to an array

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.

Passing in array to a function

int main(){
int right[2][3] = {
{1,4,6}, {2,7,5}
}
....
calc(right);
}
int calc(int ** right){
printf("%i", right[0][0]);
}
I calc function that calculate some numbers based on a matrix, but I dont' know why i get seg fault when I access the variable right within the calc function. does any body know the solution?
edit:
right now that is all it's doing at calc function. I have some calc stuff but it's all commented out trying to figure out how to access this variable.
Two-dimensional arrays in C don't work the way you think they do. (Don't worry, you're not alone -- this is a common misconception.)
The assumption implicit in the code is that right is an array of int * pointers, each of which points to an array of int. It could be done this way -- and, confusingly, the syntax for accessing such an array would be the same, which is probably what causes this misconception.
What C actually does is to make right an array of 12 ints, layed out contiguously in memory. An array access like this
a=right[i][j];
is effectively equivalent to this:
int *right_one_dimensional=(int *)right;
a=right[i*3 + j];
To pass your array to the calc function, you need to do this:
int calc(int *right, size_t d){
// For example
a=right[i*d + j];
}
and then call it like this:
int right[2][3] = {
{1,4,6}, {2,7,5}
};
calc(&right[0][0], 3);
Edit: For more background on this, the question linked to in Binary Worrier's comment is definitely worth looking at.
Although a one-dimensional array is automatically converted to a pointer, the same does not hold for a multi-dimensional array and multi-level pointers.
If you change the order of the calc and main functions (or if you provide a prototype for calc before main), you will get a complaint from the compiler that it can convert right to the type int**.
The reason is that right is declared as an "array of 4 arrays of 3 int". This can be automatically converted to "pointer to array of 3 int" (int (*)[3]), but that is where the conversions stop.
calc on the other hand expects a "pointer to a pointer to int", which is a completely different beast from a "pointer to array of 3 int".
There are two possible solutions:
Change calc to accept a pointer to an array (or array of arrays):
int calc(int right[][3])
Change right to be a pointer to a pointer:
int temp_array[4][3];
int* temp_array2[4] = { temp_array[0], temp_array[1], temp_array[2], temp_array[3] };
int** right = temp_array2;

Pointer arithmetic and arrays: what's really legal?

Consider the following statements:
int *pFarr, *pVarr;
int farr[3] = {11,22,33};
int varr[3] = {7,8,9};
pFarr = &(farr[0]);
pVarr = varr;
At this stage, both pointers are pointing at the start of each respective array address. For *pFarr, we are presently looking at 11 and for *pVarr, 7.
Equally, if I request the contents of each array through *farr and *varr, i also get 11 and 7.
So far so good.
Now, let's try pFarr++ and pVarr++. Great. We're now looking at 22 and 8, as expected.
But now...
Trying to move up farr++ and varr++ ... and we get "wrong type of argument to increment".
Now, I recognize the difference between an array pointer and a regular pointer, but since their behaviour is similar, why this limitation?
This is further confusing to me when I also consider that in the same program I can call the following function in an ostensibly correct way and in another incorrect way, and I get the same behaviour, though in contrast to what happened in the code posted above!?
working_on_pointers ( pFarr, farr ); // calling with expected parameters
working_on_pointers ( farr, pFarr ); // calling with inverted parameters
.
void working_on_pointers ( int *pExpect, int aExpect[] ) {
printf("%i", *pExpect); // displays the contents of pExpect ok
printf("%i", *aExpect); // displays the contents of aExpect ok
pExpect++; // no warnings or errors
aExpect++; // no warnings or errors
printf("%i", *pExpect); // displays the next element or an overflow element (with no errors)
printf("%i", *aExpect); // displays the next element or an overflow element (with no errors)
}
Could someone help me to understand why array pointers and pointers behave in similar ways in some contexts, but different in others?
So many thanks.
EDIT: Noobs like myself could further benefit from this resource: http://www.panix.com/~elflord/cpp/gotchas/index.shtml
The difference is because for farr++ to have any effect, somewhere the compiler would need to store that farr will evaluate to the address of the second element of the array. But there is no place for that information. The compiler only allocates place for 3 integers.
Now when you declare that a function parameter is an array, the function parameter won't be an array. The function parameter will be a pointer. There are no array parameters in C. So the following two declarations are equivalent
void f(int *a);
void f(int a[]);
It doesn't even matter what number you put between the brackets - since the parameter really will be a pointer, the "size" is just ignored.
This is the same for functions - the following two are equivalent and have a function pointer as parameter:
void f(void (*p)());
void f(void p());
While you can call both a function pointer and a function (so they are used similar), you also won't be able to write to a function, because it's not a pointer - it merely converts to a pointer:
f = NULL; // error!
Much the same way you can't modify an array.
In C, you cannot assign to arrays. So, given:
T data[N];
where T is a type and N is a number, you cannot say:
data = ...;
Given the above, and that data++; is trying to assign to data, you get the error.
There is one simple rule in C about arrays and pointers. It is that, in value contexts, the name of an array is equivalent to a pointer to its first element, and in object contexts, the name of an array is equivalent to an array.
Object context is when you take the size of an array using sizeof, or when you take its address (&data), or at the time of initialization of an array. In all other contexts, you are in value context. This includes passing an array to a function.
So, your function:
void working_on_pointers ( int *pExpect, int aExpect[] ) {
is equivalent to
void working_on_pointers ( int *pExpect, int *aExpect ) {
The function can't tell if it was passed an array or a pointer, since all it sees is a pointer.
There are more details in the answers to the following questions:
type of an array,
sizeof behaving unexpectedly,
Also see this part of C for smarties website, which is very well-written.
Trying to increment farr or varr fails because neither one is a pointer. Each is an array. The name of an array, when evaluated by itself (except as the operand of the sizeof or address-of operator) evaluates to a value (an rvalue) that's of the correct type to be assigned to a pointer. Trying to increment it is a bit like trying to increment 17. You can increment an int that contains the value 17, but incrementing 17 itself won't work. The name of an array is pretty much like that.
As for your second part, it's pretty simple: if you attempt to declare a function parameter of array type, the compiler silently "adjusts" it to a pointer type. As such, in your working_on_pointers, aExpect and pExpect have exactly the same type. Despite the array-style notation, you've defined aExpect as having type 'pointer to int'. Since the two are the same, it's entirely expected that they'll act the same.
Have a look at this answer I posted in relation to differences between pointers and arrays here on SO.
Hope this helps.
okay, i may be wrong. but arrays and pointers can be used alternately.
int * ptr = (int *)malloc(2* sizeof(int));
ptr[0]=1;
ptr[1]=2;
printf ("%d\n", ptr[0]);
printf ("%d\n", ptr[1]);
here i declared a pointer and now i am treating it as array.
moreover:
As a consequence of this definition,
there is no apparent difference in the
behavior of the "array subscripting"
operator [] as it applies to arrays
and pointers. In an expression of the
form a[i], the array reference "a"
decays into a pointer, following the
rule above, and is then subscripted
just as would be a pointer variable in
the expression p[i] (although the
eventual memory accesses will be
different, as explained in question
2.2). In either case, the expression x[i] (where x is an array or a
pointer) is, by definition, identical
to *((x)+(i)).
reference: http://www.lysator.liu.se/c/c-faq/c-2.html
you need to understand the basic concept of arrays.
when you declare an array i.e
int farr[]
you are actually declaring a pointer with this declaration
const int * farr
i.e; a "constant" pointer to integer. so when you do farr++ you are actually trying to add up to a pointer which is constant, hence compilers gives you an error.
if you need to understand, try to declare a pointer with the above declaration and you would not be able to do the arithmetic which are legal on normal pointers.
P.S:
its been quiet a while i have coded in C so i am not sure about exact syntax. but bottom line is the difference between a pointer and a constant pointer.

Resources