cannot convert 'double (*)[10]' to 'double*' for argument - c++

Please help solving the compile time error. I have the declaration in different files as shown below
type.h
extern block posTime(const int row[MAX_ROW], int Flag, int n,double Time[]=0 );
a.cc
block posTime( const int row[MAX_ROW],
int Flag,
int n,
double* eraseTime[]
)
...
eraseTime[0]=test[1];
..
b.cc
...
double eraseTime[MAX_ROW];
block newB = posTime (0,0,0,&eraseTime);
the last line block newB = posTime (0,0,0,&eraseTime); gives me the error, cannot convertdouble (*)[10] to double* for argument 4
I want to upadte the eraseTime in a.cc and use back in b.cc. Can I do that?

Working solution (GCC 4.9.0 with C++11)
test.hpp
#define MAX_ROW 10
extern double posTime(const int row[MAX_ROW], int Flag, int n,double Time[]=0 );
test1.cpp
#include "test.hpp"
double posTime( const int row[MAX_ROW],
int Flag,
int n,
double* eraseTime
)
{ eraseTime[0] = 2; eraseTime[1] = 3; return eraseTime[0]; }
test.cpp
#include <iostream>
#include "test.hpp"
double eraseTime[MAX_ROW] { 1, 2, 3, 4, 5, 6 ,7, 8, 9, 10 };
int main() {
double newB = posTime (0,0,0,eraseTime);
std::cout << "result: " << newB << std::endl;
for (auto v : eraseTime) {
std::cout << v << std::endl;
}
return 0;
}
compilation command:
g++ -std=c++11 -o e:\test.exe e:\test.cpp e:\test1.cpp
or double eraseTime[MAX_ROW], if you are using MAX_ROW in int row i don't see why not in eraseTime (probably some call location not in the sample restrict this use) or double* eraseTime.
Recommended change to use std::array (constant size) or std::vector (dynamic size).

There are multiple issues here:
The signature in the header and in the implementation file are not the same: The header declares the last argument of posTime() to be of type double* (yes, pointer, not array!), while the implementation declares it to be of type double** (again, the array specification is converted to a pointer declaration because it is a function argument declaration).
The result is, that the implementation declares an overload to the function declared in the header, not an implementation for it.
When you take the address of an array, you get a pointer to an array, i. e. a value of type double (*)[MAX_ROW]. This is incompatible to a double**, which is what your compiler is complaining about. To create a variable of this type, you must use the syntax double (*myArrayPointer)[MAX_ROW];. The parentheses are important because the array subscript operator has a higher precedence than the dereference operator, with the consequence that double* myPointerArray[MAX_ROW]; declares an array of MAX_ROW pointers to doubles.
If you want to pass the array as a pointer to an array, you need to declare your function as
extern block posTime(const int row[MAX_ROW], int Flag, int n,double (*Time)[MAX_ROW]=0 );
This has the advantage that you get type checking on the length of the array, but the disadvantage that you cannot accept arrays of dynamic size. If you need this flexibility, the normal approach is to pass a pointer to the first element:
extern block posTime(const int row[MAX_ROW], int Flag, int n,double *Time=0 );
called with
block newB = posTime (0,0,0,eraseTime);
The call relies on array-pointer-decay to make a double* from your array identifier.

Related

Passing arrays to functions, what is the difference between these two approaches?

In the example below, both functions return the same result. Can someone please explain what the difference is between them?
#include <iostream>
void func1( int (&a)[4]) {
int b = a[3];
std::cout << b << std::endl;
}
void func2( int a[4]) {
int b = a[3];
std::cout << b << std::endl;
}
int main()
{
int b[4] = {3,2,3,4};
func1(b);
func2(b);
return 0;
}
In func2, int a[4] is equivalent to int *a, in other words, 4 does not matter at all. You can pass an array of any size to to this function.
However, for func1, you have to pass it an array of size 4 or you will get a compilation error.
For example, if you feed func1 an array of size 8, you will get this compliation error,
main.cpp:26:12: error: invalid initialization of reference of type ‘int (&)[4]’ from expression of type ‘int [8]’ regardless of what the array size you feed to the function is.
Also, if you print the output of sizeof(a) function in func1, it will return the size of the input array in bytes, in this case, 16=4*4 bytes. For func2, it retunrs the size of a, which is a pointer to int (in my case that size is 8 bytes).
The first one won't accept any type except a reference to an array of 4 int elements while the second will accept a pointer to int or an array of unspecified size of int because it will be passed as an array.
Note also the first approach doesn't accept temporaries arguments so you can't do something like :
func1({1, 2, 3, 4});
But if you want to use temporaries you could write :
void func1( int (&&a)[4])

Why is pointer to array of unknown bounds sometimes illegal? [duplicate]

I just found out that this is illegal in C++ (but legal in C):
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))
int accumulate(int n, const int (*array)[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += (*array)[i];
}
return sum;
}
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
return 0;
}
It compiles without problems using gcc -std=c89 -pedantic but fails to compile using g++. When I try to compile it using g++ I get these error messages:
main.cpp:5:37: error: parameter 'array' includes pointer to array of unknown bound 'int []'
int accumulate(int n, int (*array)[])
^
main.cpp: In function 'int main()':
main.cpp:18:50: error: cannot convert 'int (*)[9]' to 'int (*)[]' for argument '2' to 'int accumulate(int, int (*)[])'
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
I have been using this in my C code for a long time and I had no idea that it was illegal in C++. To me this seems like a useful way to document that a function takes an array whose size is not known before hand.
I want to know why this is legal C but invalid C++. I also wonder what it was that made the C++ committee decide to take it away (and breaking this compatibility with C).
So why is this legal C code but illegal C++ code?
Dan Saks wrote about this in 1995, during the lead up to C++ standardisation:
The committees decided that functions such as this, that accept a
pointer or reference to an array with unknown bound, complicate
declaration matching and overload resolution rules in C++. The
committees agreed that, since such functions have little utility and
are fairly uncommon, it would be simplest to just ban them. Hence, the
C++ draft now states:
If the type of a parameter includes a type of the form pointer to
array of unknown bound of T or reference to array of unknown bound of
T, the program is ill-formed.
C++ doesn't have C's notion of "compatible type". In C, this is a perfectly valid redeclaration of a variable:
extern int (*a)[];
extern int (*a)[3];
In C, this is a perfectly valid redeclaration of the same function:
extern void f();
extern void f(int);
In C, this is implementation-specific, but typically a valid redeclaration of the same variable:
enum E { A, B, C };
extern enum E a;
extern unsigned int a;
C++ doesn't have any of that. In C++, types are either the same, or are different, and if they are different, then there is very little concern in how different they are.
Similarly,
int main() {
const char array[] = "Hello";
const char (*pointer)[] = &array;
}
is valid in C, but invalid in C++: array, despite the [], is declared as an array of length 6. pointer is declared as a pointer to an array of unspecified length, which is a different type. There is no implicit conversion from const char (*)[6] to const char (*)[].
Because of that, functions taking pointers to arrays of unspecified length are pretty much useless in C++, and almost certainly a mistake on the part of the programmer. If you start from a concrete array instance, you almost always have the size already, so you cannot take its address in order to pass it to your function, because you would have a type mismatch.
And there is no need for pointers to arrays of unspecified length in your example either: the normal way to write that in C, which happens to also be valid in C++, is
int accumulate(int n, int *array)
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
to be called as accumulate(ARRAY_LENGTH(a), a).

Pass by reference works in C but does not work with C++ for this code

In my below code , It compiles and runs when I use it as a c file , but gives an error when I run it as cpp file.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
struct ploc_t {
int num;
ploc_t *right;
};
ploc_t *create_ploc(int *point , int *triangles, int n , int m){
// just for testing
ploc_t *result;
result=(ploc_t*)malloc(sizeof(ploc_t));
return result;
}
int main( )
{
int points[1][2];
int triangles[1][2];
points[0][1]=2;
points[0][2]=4;
triangles[0][1]=8;
triangles[0][2]=6;
create_ploc(points,triangles,3,4);
}
Error which I get in when using cpp file is :
Invalid arguments candidates are: plot_t(int*,int*,int,int)
Why is this error? and how can it be resolved?
The difference between C and C++ in this instance is that in C, what you're doing (passing a pointer to int[2] to a function expecting a pointer to int) is legal although discouraged, whereas in C++ you're not allowed to do it. So in C, the compiler will issue a warning. If you're not using the -Wall flag, you might not see the warning. In C++, it doesn't matter whether you used -Wall or not (although you always should) because it's an error and the compile will fail.
Arrays passed as parameters "decay" to a pointer to the array element type. (That's not the only case in which arrays decay to pointers, but it's the one relevant to this question.) Your arrays are of type int[][2], so the element type is int[2]. Consequently, when you use them as arguments, they decay to int(*)[2], which is C/C++'s idiosyncratic way of saying "a pointer to a two-element array of ints".
What's the difference between a pointer to an int and a pointer to an int[2]? One important difference is the size of the target:
int a[2];
int* p = a;
p++;
// p now points to a[2]; it was incremented by sizeof(int)
int aa[10][2];
int(*pp)[2] = aa;
pp++;
// pp now points to aa[2]; it was incremented by sizeof(int[2])
Rather than fighting with the syntax for pointer to arrays, you probably want to define you function to accept two-dimensional arrays:
ploc_t *create_ploc(int points[][2], int triangles[][2], int n , int m);
But you could, with exactly the same semantics, write out the decayed types:
ploc_t *create_ploc(int (*points)[2], int (*triangles)[2], int n , int m);
Looking at your main:
int points[1][2];
int triangles[1][2];
"points" and "triangles" are two-dimensional arrays. The first two arguments to create_ploc() are pointers to integers. Passing these two-dimensional arrays directly into the function is not passing a pointer. I'm not sure exactly what you want to do, but a couple of ways to solve this are:
1)
int points[1];
int triangles[1]; // both one-dimensional arrays of ints (int*)
2)
create_ploc(points[0],triangles[0],3,4); // passing in a one-dimensional array of ints (int*)

Pointer to array of unspecified size "(*p)[]" illegal in C++ but legal in C

I just found out that this is illegal in C++ (but legal in C):
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_LENGTH(A) (sizeof(A) / sizeof(A[0]))
int accumulate(int n, const int (*array)[])
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += (*array)[i];
}
return sum;
}
int main(void)
{
int a[] = {3, 4, 2, 4, 6, 1, -40, 23, 35};
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
return 0;
}
It compiles without problems using gcc -std=c89 -pedantic but fails to compile using g++. When I try to compile it using g++ I get these error messages:
main.cpp:5:37: error: parameter 'array' includes pointer to array of unknown bound 'int []'
int accumulate(int n, int (*array)[])
^
main.cpp: In function 'int main()':
main.cpp:18:50: error: cannot convert 'int (*)[9]' to 'int (*)[]' for argument '2' to 'int accumulate(int, int (*)[])'
printf("%d\n", accumulate(ARRAY_LENGTH(a), &a));
I have been using this in my C code for a long time and I had no idea that it was illegal in C++. To me this seems like a useful way to document that a function takes an array whose size is not known before hand.
I want to know why this is legal C but invalid C++. I also wonder what it was that made the C++ committee decide to take it away (and breaking this compatibility with C).
So why is this legal C code but illegal C++ code?
Dan Saks wrote about this in 1995, during the lead up to C++ standardisation:
The committees decided that functions such as this, that accept a
pointer or reference to an array with unknown bound, complicate
declaration matching and overload resolution rules in C++. The
committees agreed that, since such functions have little utility and
are fairly uncommon, it would be simplest to just ban them. Hence, the
C++ draft now states:
If the type of a parameter includes a type of the form pointer to
array of unknown bound of T or reference to array of unknown bound of
T, the program is ill-formed.
C++ doesn't have C's notion of "compatible type". In C, this is a perfectly valid redeclaration of a variable:
extern int (*a)[];
extern int (*a)[3];
In C, this is a perfectly valid redeclaration of the same function:
extern void f();
extern void f(int);
In C, this is implementation-specific, but typically a valid redeclaration of the same variable:
enum E { A, B, C };
extern enum E a;
extern unsigned int a;
C++ doesn't have any of that. In C++, types are either the same, or are different, and if they are different, then there is very little concern in how different they are.
Similarly,
int main() {
const char array[] = "Hello";
const char (*pointer)[] = &array;
}
is valid in C, but invalid in C++: array, despite the [], is declared as an array of length 6. pointer is declared as a pointer to an array of unspecified length, which is a different type. There is no implicit conversion from const char (*)[6] to const char (*)[].
Because of that, functions taking pointers to arrays of unspecified length are pretty much useless in C++, and almost certainly a mistake on the part of the programmer. If you start from a concrete array instance, you almost always have the size already, so you cannot take its address in order to pass it to your function, because you would have a type mismatch.
And there is no need for pointers to arrays of unspecified length in your example either: the normal way to write that in C, which happens to also be valid in C++, is
int accumulate(int n, int *array)
{
int i;
int sum = 0;
for (i = 0; i < n; ++i) {
sum += array[i];
}
return sum;
}
to be called as accumulate(ARRAY_LENGTH(a), a).

How to invoke C++ function?

I have a function with the prototype as
void test( int array [] , int b);
I know we can replce the protoype as: void test(int*, int);
In main() we declare the following arrays :
int array1[10], array2[10];
To set the body of the function to 0,
test ( array1 , b)
{
for ( int i = 0 ; i < b ; i++)
array1[i] = 0;
}
can i do the follwing and why?
int main()
{// assuming b is the size of the array
test(array1 , b);
test(array2 , b) ;
return 0;
}
i know the basic of c++ im trying to write my own include files.
I am just wondering if this is possible and is it a good choise?
Not a direct answer to your question, but the fact that you talk about C++ and yet use plain old C arrays caught my attention:
Consider not using C arrays in the first place. Instead, use a std::vector<int>. This probably avoids the need to ask this question in the first place (and it avoids a whole lot of other issues). You don't need to bother about the right size type (int? size_t? Something else?) since std::vector gives you the right type already: std::vector<int>::size_type.
Your function signature would just be
void test( std::vector<int> &a );
The implementation for filling the vector with zeros would be:
void test( std::vector<int> &a )
{
std::fill( a.begin(), a.end(), 0 );
}
You may be asking about the difference between formal parameters and actual parameters.
In your prototype
void test(int *array, size_t size);
the names 'array' and 'size' are the formal parameters. You use those names inside the body of your function.
In the code that invokes the function, you can use different names, which are the actual parameters.
so
int main()
{
const size_t b = 10;
int array1[10], array2[10];
test(array1 , b);
test(array2 , b) ;
return 0;
}
Here array1 and b are the actual parameters to the first invocation and array2 and b are the actual parameters to the second invocation.
So yes, you can use whatever names you like as actual parameters, so long as the types of the variables match your prototype.
Yes, it's possible; but declaration in the function body should be same as what you declared as prototype:
void test (int array1[], int b) // <---- see here (prefer `unsigned int` for size)
{
for ( int i = 0 ; i < b ; i++)
array1[i] = 0;
}
It's better to use library function memset() if you want to set something to 0.
(As an advise, you can a build a library on top of what is already existing. Otherwise it will be like reinventing a wheel.)
Looks like you're migrating from C. Yes, this is possible, but you need to get the declarations right, or the compiler will throw an error.
The preferred C++ prototype would be
void test(int *array, size_t size);
In C++, you must declare the return type, and the type(s) of each argument in both the prototype and the implementation.
Note:
You don't need to use size_t, but it is preferred (even on C). size_t is included in stddef.h (and by extension cstddef which is the preferred C++ include). It is architecture dependent and is usually unsigned int in 32-bit systems and unsigned long long on 64-bit systems