Differences between double *vec and double vec[] - c++

In our legacy C/C++ code I encounter two versions of signatures
void foo1(double *vec, int n)
and
void foo2(double vec[], int n)
But there is no difference in the handling of the parameter vec inside of the methods e.g.:
void foo2(double vec[], int n){
for(int i=0;i<n;i++)
do_something(vec[i]);
}
Is there any difference between the first version (double *) and the second (double ..[])? In which situations should a version be preferred over the other?
Edit: After the hint of #Khaled.K I tried to compile:
void foo(double *d, int n){}
void foo(double d[], int n){}
and got a compile error due to redefinition of void foo(double *d, int n). So double *vec and double vec[] mean the same.
The still open question is which version should be used when.

It's the same. From the standard:
After determining the type of each parameter, any parameter of type “array of T” or of function type T is adjusted to be “pointer to T”
So there is no difference. I would use * instead of [] to avoid confusion, unless it's something like char* argv[], then it might be passable.

Here is the relevant quote from K&R 2nd (*), starting at the bottom of page 99:
As formal parameters in a function definition,
char s[];
and
char *s;
are equivalent; we prefer the latter because it says more explicity that the parameter is a pointer. When an array name is passed to a function, the function can at its convenience believe that it has been haded either an array or a pointer, and manipulate it accordingly. It can even use both notations if it seems appropriate and clear.
(*) Kernighan & Ritchie: "The C Programming Language" (second edition)

There is no bound check in c. As you know that the array name itself act as a pointer(with special properties). Whenever you pass an array as an argument to a function, it will internally passed as a pointer of the corresponding type. That is why you need to pass the length of the array as well if you want to do some operation on bound check. Compiler generates the same signature(object code) for both pointer and array as a formal argument. You can use both invariable as per your choice.
Below is a simple example:
#include <iostream>
void arrayParamTest(int arr[])
{
}
int main()
{
int arr[] = {10, 20};
arrayParamTest(arr);
}
Now compile this and lets see the symbols:
techie#gateway2:myExperiments$ nm a.out | grep "arrayParamTest"
00000000004006e7 t _GLOBAL__I__Z14arrayParamTestPi
0000000000400674 T _Z14arrayParamTestPi
See compiler generates symbol with "Pi" as argument. Pi means pointer of type int.
Hope this will help. :-)

Array and pointers are different but some properties of array and pointers are look similar.
In this case there is no difference between double *vec and double vec[].
But whenever you taken array and initialized with some values and then you passed that array as function argument.
In function signature if you use double *vec then unexpectedly u would try to free that memory dynamically in function definition then it will throw an exception at runtime i.e this may due to a corruption of the heap.
example:
#include<stdio.h>
#include<stdlib.h>
void foo1(int *arr);
int main()
{
int arr[] = {10, 20};
foo1(arr);
return 0;
}
void foo1(int *arr)
{
printf("in array\n");
free(arr);
}
Why means
--> Arrays are static in nature once you allocated memory you cannot free and resize dynamically.
--> This is the one case which confuses using double *vec.
--> Except like this situations both signatures are similar.

double *vec implies that there is only one double value that is pointed to by vec. And double []vec implies that there is an array of doubles. From the code you show it appears that the array of doubles is what you want. Using double *vec for array operations is bound to lead to trouble.

Related

Does the size of a pointer to an array matter when passed as a parameter to a function [duplicate]

I don't understand why the following example compiles and works:
void printValues(int nums[3], int length) {
for(int i = 0; i < length; i++)
std::cout << nums[i] << " ";
std::cout << '\n';
}
It seems that the size of 3 is completely ignored but putting an invalid size results in a compile error. What is going on here?
In C++ (as well as in C), parameters declared with array type always immediately decay to pointer type. The following three declarations are equivalent
void printValues(int nums[3], int length);
void printValues(int nums[], int length);
void printValues(int *nums, int length);
I.e. the size does not matter. Yet, it still does not mean that you can use an invalid array declaration there, i.e. it is illegal to specify a negative or zero size, for example.
(BTW, the same applies to parameters of function type - it immediately decays to pointer-to-function type.)
If you want to enforce array size matching between arguments and parameters, use pointer- or reference-to-array types in parameter declarations
void printValues(int (&nums)[3]);
void printValues(int (*nums)[3]);
Of course, in this case the size will become a compile-time constant and there's no point of passing length anymore.
I don't see what compile error you are referring to - arrays passed to a function decay to pointers and you lose the array type information. You might as well have used:
void printValues(int* nums, int length);
You can avoid the decay to pointers by using references:
void printValues(int (&nums)[3], int length);
Or simply use pointers if you don't want fixed-sized arrays.
The size of the array is not ignored, it is part of the type of the argument. You should get a compiler error if you try to pass an array of any other size into the function.
On the other hand C and C++ don't do bounds checking on array accesses, so in that sense they are ignored. But that's true in any other context as well, not just for function parameters.

How to resolve this MISRA c++ compliant warning

int foo(const uint8_t array[]) {
int x;
for(i=0;i<5;i++){
x= array[i];
}
return 0;
}
it gives a warning as below,
"parameter array could be declared const" ==> i already have declared the array const, i am programming in C++.
First thing to note is that int foo(const uint8_t array[]) is equivalent to int foo(const uint8_t* array), i.e. the function takes a pointer to a const uint8_t, not an array. The pointer itself it not const, the pointee is. The signature should be:
int foo(const uint8_t* const array)
For the record, I don't find this warning particularly useful. The parameter is taken by value and the caller couldn't care less what the function does with it. Furthermore, top level const qualifiers on parameters are ignored when comparing function signatures, and this can lead to some confusion.
void foo(int) and void foo(const int), for example, are identical signatures.
EDIT:
So, according to your comment, MISRA doesn't know that you can't pass arrays by value and complains that array indexing works differently than pointer arithmetic. Shudder... The problem is that you can't add top level const using the array syntax, which makes fixes to these two warnings mutualy exclusive.
Try tricking it like this, then:
typedef const uint8_t Array[];
int foo(const Array arr);
Remember that, despite the syntax, the function actually takes a pointer, and is equivalent to
int foo(const uint8_t * array)
So array points to an array of constant bytes; but is not itself constant. The warning is pointing out that, since the function doesn't modify the pointer, it could (and, at least according to this rule, should) be constant:
int foo(const uint8_t * const array)
There is another way and it seems to be under the <iterator>
To move your pointer forward 'safely' you simply use std::advance(array, 1) then to access that value you simply dereference (*array), the location, this seems to get rid of the MISRA warning in question.

declared as array of references of type float&

I'm getting declared as array of references of type float& error in XCode when I declare a function as :
void calcCoeff(float sigma, float& ap[], float& bp[], float& an[], float& bn[]);
can anyone tell me what could be the problem? I also tried
void calcCoeff(float sigma, float &ap[5], float &bp[5], float &an[5], float &bn[5]);
thanks...
The problem is exactly as described by the error message: float& ap[] declares an array of references, and that's not a legal type in C++, just as pointers to references and references to references are prohibited.
If it were legal you can think of what it would mean by thinking of an array of pointers. A reference is in some ways conceptually similar to a pointer; a reference is meant to refer to another entity and when a reference requires a runtime representation C++ implementations typically use pointers.
So, if you were to pass an array of pointers to a function you would need to construct an initialize it:
float a, b, c;
float *arr[] = {&a, &b, &c}; // or in fictional array-of-references syntax: float &arr[] = {a, b, c};
Or if you already have an array of floats, and you want an array of pointers to those elements:
float a[3];
float *b[] = {&a[0], &a[1], &a[2]); // or in fictional array-of-references syntax: float &b[] = {a[0], a[1], a[2]};
Presumably what you actually want is to pass an array, by reference, to a function so that the function can write into the array and the changes will be visible to the caller. (or simply because you want to avoid copying the array). Since normally function parameters are passed by value, and the way to pass by reference is to stick & in there you did the same for an array type. This is a pretty good instinct, but there are a few wrinkles in C++ that messed it up for you.
The first is simply the odd syntax for declaration in C++. You can read about the 'spiral rule' or 'declaration mimics use' elsewhere, but suffice it to say that it matters whether that & is 'closer' (syntactically) to the variable name or float. float &arr[] is an array of references. You need a couple parentheses to put the ampersand closer to the variable: float (&arr)[] declares a reference to an array.
Next is that C++ unfortunately inherits some strange behaviors from C intended to make arrays and pointers pretty much interchangeable. The relevant behavior in your case is that if you declare a function that takes an array parameter:
void foo(int arr[], int size);
the language specifically says that the type is 'adjusted' to be a pointer. The result is the same as:
void foo(int *arr, int size);
What this means is that arrays do not behave like value types. Trying to pass an array 'by value' does not result in a modifiable copy of the array being passed to the function; instead the function effectively receives the array 'by reference'.
A second consequence is that array parameters do not need to have complete array types, i.e. the array size can be omitted, because the array type is adjusted and the size is never used anyway. This means that if you naively convert an 'array parameter' that doesn't specify a size into a reference to an array, you have to specify the size in addition to adding the &. float (&arr)[10].
Using raw array as parameters is highly undesirable in my opinion. First because it discards type information:
void foo(int arr[10]) { // same as void foo(int *arr)
int x = arr[9];
}
int bar[3];
foo(bar); // no compile error! the special array rules discarded the size of the array
And because raw arrays are not consistent with other built-in types, all of which have value semantics. For these reasons raw arrays should be avoided. Instead you can use std::array which avoids all the 'special' rules for built-in arrays and therefore behaves as built-in arrays ought to.
void foo(std::array<int, 10> arr); // Takes arr by value, modifications will not be visible externally
std::array<int, 3> bar;
foo(bar); // compile error
And if you need a dynamically sized array then you can use std::vector instead.
Change it to:
void calcCoeff(float sigma, float ap[], float bp[], float an[],
float bn[]);
You will be able to modify the values just fine. The [] notation in function arguments is equivalent to a pointer. So it's the same as this:
void calcCoeff(float sigma, float* ap, float* bp, float* an,
float* bn);
Which means that in both cases, you get a pointer to the data rather than a copy. The [] syntax is just a stylistic decision; even though float a[] means the same thing as float* a, the [] syntax is a hint to the caller of the function that it can work on arrays rather than single variables.

C like array syntax?

what is this syntax for double x[]?
Is it a C way to declare an array?
If I have a function like
void evaluate(double x[], double *f)
{
// evaluate
}
Can I pass a parameter x with any length?
A parameter of array type behaves exactly like it is a pointer. You can not truly pass an array as a function argument. However, this syntax gives the illusion that you can for the sake of readability. So your function is equivalent to:
void evaluate(double *x, double *f)
{
// evaluate
}
From §8.3.5/5 of ISO/IEC 14882:2011:
After determining the type of each parameter, any parameter of type “array of T” or “function returning T” is adjusted to be “pointer to T” or “pointer to function returning T,” respectively.
An expression that denotes an array will decay to a pointer to its first element, so you can still do this:
void evaluate(double x[]);
int array[] = {1, 2, 3, 4, 5};
evaluate(array); // The array decays to a pointer to its first element
From §4.2:
An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.
So yes, you can indeed pass an array of any length. In reality, you are just passing a pointer to the first element. You will, however, need to pass the length of the array as well, if you need it.
Arrays can be confusing, because in most contexts the name of an array decays into a pointer to its first element. So:
double x[3]; // x is an array of 3 doubles
void f(double x[3]); // f takes a pointer to double
f(x); // calls f with the address of x[0]
The reason for having the array type decay into a pointer for f is so that you don't have to have a separate function for every array size:
double x[3];
double y[4];
void f(double x[3], int size) {
for (int i = 0; i < size; ++i)
std::cout << x[i] << ' ';
std::cout << '\n';
}
f(x, 3);
f(y, 4);
It works the same way if the argument is double*x, double x[], double x[3], double x[17], double x[]; in all of these cases, x is treated as double*.
Inside the parameter list of a function, double x[] is same as double *x.
can I pass a parameter x with any length?
Yes, you can pass. But there's no way to know the length of the array x in the function evaluate. So you probably want to pass the length as well.
C FAQ, Section 6.4
Since arrays decay immediately into pointers, an array is never actually passed to a function. You can pretend that a function receives an array as a parameter, and illustrate it by declaring the corresponding parameter as an array:
void f(char a[])
{ ... }
Interpreted literally, this declaration would have no use, so the compiler turns around and pretends that you'd written a pointer declaration, since that's what the function will in fact receive:
void f(char *a)
{ ... }
There's nothing particularly wrong with talking about a function as if it ``receives'' an array, if the function is traditionally used to operate on arrays, or if the parameter is naturally treated within the function as an array.
This conversion of array-like declarators into pointers holds only within function formal parameter declarations, nowhere else. If the conversion bothers you, you're under no compulsion to make use of it; many programmers have concluded that the confusion it causes outweighs the small advantage of having the declaration ``look like'' the call or the uses within the function. (Note that the conversion happens only once; something like char a2[][] won't work. See questions 6.18 and 6.19.)
In other words, in a function parameter declaration, an array with unspecified length is the same as a pointer.
void evaluate(double x[], double *f)
{
// evaluate
}
is actually equivalent to:
void evaluate(double *x, double *f)
{
// evaluate
}
in C and C++.
It means the type of the x parameter is double * in both cases.
The argument x to your function is an array of unspecified length. That means that you can pass any array of type double to it, no matter the size. You can also pass a pointer to a double as argument.
There is one caveats though: You can't use the sizeof operator on the array x, as it doesn't have a size.
yes in c the array is declared like that
good read
Char array declaration and initialization in C
Simple C array declaration / assignment question

Arguments in a function prototype

My question is: when i write a function prototype in C like this:
void foo(int *vector);
It's the same thing to do:
void foo(int vector[MAX_LENGTH]);
To the function, is passed always as a pointer? The code it's the same?
Thanks in advance.
This is subtle. Arrays in C are not pointers, but C does not allow arrays to be passed as function parameters. So when you have void foo(int vector[MAX_LENGTH]);, essentially all you're doing is telling other programmers (and your future self) that this function expects an array of MAX_LENGTH to be passed to it. The compiler won't help you. It will silently cast your array to a pointer.
This explains it pretty well.
Yes an array type is implicitly converted to a pointer type when passed to a function.
So
void foo(int *a) and void foo(int a[]) are identical.
You can easily check that using sizeof() operator inside the function definition
For example
void foo(int a[])
{
std::cout<<sizeof(a); //prints sizeof(int*)
}
int main()
{
int a[]={1,2,3,4};
foo(a);
}
EXTRA (Printing size of an array inside a function)
[C++ Only]
template<typename T,size_t n>
void size_of_array(T (&a)[n]) //Array passed by reference. Template argument deduction
{
std::cout<<sizeof(a); //prints sizeof(n*sizeof(int))
}
int main()
{
int a[]={1,2,3,4,5};
size_of_array(a);
}
This is one of the rough edges of the C language(s). Two declaration that look exactly the same (but for the names), one in the prototype and one as a stack variable, result in the declaration of two different types of variables.
void foo(int A[10]) {
int B[10];
}
Inside the scope of foo, A is pointer to int and B is array of ten elements of type int. As somebody else mentioned, even their sizes computed with sizeof are different.
C++ inherited the rule, so for your example code the prototypes of both functions should be the same.
C99 complicates this matter even further by introducing the new keyword static ;-)
void foo(int A[static 10]) {
int B[10];
}
this doesn't change the rules on how A and B are seen from the inside, but provides an information to the caller side of howmuch array elements are expected. For the moment gcc accepts this new syntax and simply ignores this information.
there's little else it could pass! the [] contraint lets the compiler do more checks though.