What is the difference between A and A[] in function parameter? - c++

//function prototype at the top
void fillRandArray(int A[], int number, int maxNum);
//function declaration
void fillRandArray(int* A, int number, int maxNum) {
for(int i = 0; i < number; i++) {
A[i] = rand() % maxNum + 1;
}
}
int A[MAX_STUDENTS];
fillRandArray(A, number, 44);
I dont understand the code, so the prototype set int A[]
then the declaration set int* A
when we pass the argument, shouldn't we pass like this...
fillRandArray(A[MAX_STUDENTS], number, 44); <---- ???

The code below is passing the name of an array, which is an address.
void fillRandArray(int A[], int number, int maxNum);
The code below this is passing just the name of an address, which happens to be A in this case. They are basically doing the same thing.
void fillRandArray(int* A, int number, int maxNum)
You would not pass the argument like the following:
fillRandArray(A[MAX_STUDENTS],..., ...);
because you told the compiler to expect an address, not an element of the array. So you would just pass it A (i.e. the name of array, which is also the starting address). So it would look like this:
fillRandArray(A, number, 44);
Ask more questions, if I didn't explain it well enough.

The problem is that C-style arrays can't be passed as arguments
to a function. When you write int a[] as a parameter in
a function, the compiler translates it to int* a. In
addition, if you provide a dimension (e.g. int a[10]), it is
simply ignored.
Also, an array can convert to a pointer, and will do so in a lot
of contexts. This is what happens in fillRandArray(A, number,
44); the array A is implicitly converting to a pointer.
As for fillRandArray(a[MAX_STUDENTS], number, 44), this
indexes into the array for the first element; with your
declaration, it passes an int (not an array or a pointer),
except that it accesses one beyond the end of the array, so it's
undefined behavior.
In general, you want to avoid this (although with main, you
can't): the function should either take an std::vector<int>&
a, or in a few special cases, an int (&a)[N] (in which case,
the function should be a template, and N be a template
parameter). So you might write:
template <size_t N>
void fillRandArray( int (&a)[N], int maxNumber )
{
for ( int i = 0; i != N; ++ i ) {
a[i] = rand() % maxNum + 1;
}
}
(But for this sort of thing, std::vector is far preferrable.)

Related

Is there a way to fix this error : no match for 'operator[]' (operand types are 'empl' and 'int')

Im getting homework done but i faced this problem i tried everything changing variables name, changing function ....
I looked into this problem on google still no idea how to fix this error.
#include<stdio.h>
#include<iostream>
struct empl {
char nom;
char pre;
float salaire;
double cin;
}empl;
struct empl t[50];
struct empl E;
int taille(int n)
{
printf("saisie la taille de tableaux\n");
scanf("%d\n", &n);
return 0;
}
int remplire(int n, struct empl t, int i)
{
for (i = 1; i <= n; i++)
{
printf("t[%d].nom= ", i);
scanf("%s\n", &t[i].nom);
printf("t[%d].prenom= ", i);
scanf("%s\n", &t[i].pre);
printf("t[%d].salaire= ", i);
scanf("%f\n", &t[i].salaire);
printf("t[%d].CIN= ", i);
scanf("%lf\n", &t[i].cin);
}
}
int main()
{
int i, n;
int taille(int n),
taille(n);
int remplire(int n, struct empl t, int i);
remplire(n, t, i);
}
Although your code is written mostly in C style, you seem to be compiling it with a C++ compiler, as it accepts #include <iostream> (though you do not appear to use anything from it), and it has a notion of operator overloading. C and C++ are distinct languages, and the distinction is somewhat relevant here.
In either language, however, the code you have presented is flawed. The problem is with the several expressions in function remplire that follow this pattern: &t[i].nom. Absent any operator overloading (which is not available in C anyway), the [] operator in those expressions requires one of its operands to designate either a pointer or an array, and the other to designate an integer. Although there is a file-scope variable t that is an array, inside remplire() that is shadowed by a function parameter with the same name. Inside that function, then, t refers the the parameter, which is a struct empl, not an array or pointer (or integer).
Your compiler ought to be giving you another clue, too, where you call that function ...
remplire(n,t,i);
..., passing the global t as an argument. The compiler very much should complain about a type mismatch between the second argument (t) and the corresponding function parameter.
Perhaps what you wanted to do is simply to declare remplire() to accept a structure pointer as its second parameter:
int remplire(int n, struct empl *t, int i)
While you're at it, do remove the redundant local declaration of that function inside main(). You don't need that as long as remplire() is defined before main(), and if you want to have a separate declaration of that function then it would best be placed at file scope, and probably in a header file.
First of all iostream is C++ header coming from standard library and will not work for C program. And now issues:
int taille (int n)
{
printf("saisie la taille de tableaux\n");
scanf("%d\n",&n);
return 0;
}
This function is called with an input parameter - that means you can pass a value into a function, but not access the parameter and hope it will be used in other places. To correct this you should declare the function should look like this:
int taille (int * n)
{
printf("saisie la taille de tableaux\n");
scanf("%d\n", n);
return 0;
}
Next function - similar problem, it should look like this:
int remplire (int n , struct empl * t ,int i)
{
for (i=1;i<=n;i++)
{
printf("t[%d].nom= ",i);
scanf("%s\n",&t[i].nom);
printf("t[%d].prenom= ",i);
scanf("%s\n",&t[i].pre);
printf("t[%d].salaire= ",i);
scanf("%f\n",&t[i].salaire);
printf("t[%d].CIN= ",i);
scanf("%lf\n",&t[i].cin);
}
}
Or even like this:
int remplire (int n , int i)
as t is global variable. Also this function should return some value as it is declared to return int.
And now the main function:
int main()
{
int i,n;
int taille(int n),
taille(n);
int remplire(int n,struct empl t,int i);
remplire(n,t,i);
}
Don't redeclare functions inside another function, even if it is permissible it does not mean you should do it. Also main function should return 0 if everything works fine. To correct the function write it like this:
int main()
{
int i,n;
taille(& n);
remplire(n,& t,i);
}
Some good advice, please read some books to learn how to program in C if you want to go that way.
There are many issues in your code.
Starting reading a good C textbook is advised.
You probably want this:
#include <stdio.h>
#include <iostream>
struct empl {
char nom[30];
char pre[30];
float salaire;
double cin;
}empl;
struct empl t[50];
struct empl E;
int taille(int & n)
{
printf("saisie la taille de tableaux\n");
scanf("%d", &n);
return 0;
}
void remplire(int n, struct empl *t)
{
for (int i = 0; i < n; i++)
{
printf("t[%d].nom= ", i);
scanf("%s", &t[i].nom);
printf("t[%d].prenom= ", i);
scanf("%s", &t[i].pre);
printf("t[%d].salaire= ", i);
scanf("%f", &t[i].salaire);
printf("t[%d].CIN= ", i);
scanf("%lf", &t[i].cin);
}
}
int main()
{
int n;
taille(n);
remplire(n, t);
}
It's still poor code and it's written mostly in C style, but it compiles and works as intended.
In C++ you'd do this totally differently.
You've declared this global array variable t
struct empl t[50];
and also declared a parameter t in this function
int remplire (int n , struct empl t ,int i)
Inside the function it's going to treat any instance of t as to be the parameter as that is nearer in scope than the global variable. So when you have code like this...
scanf("%s\n",&t[i].nom);
...it's going to throw up errors because t isn't an array.
The solution is to use variable names that have meaning like "employee_array" rather than single letters.
Also that call to scanf is wrong as for strings you don't need to pass in a pointer to the variable, so it should look like
scanf("%s\n",t[i].nom);
But you'd also need to make nom be a string too - currently it's only a char.

Checking size of an array through function

When I want to know the size of an array I do the following :
int array[30];
for(int i = 0; i < 30; i++)
array[i] = i+1; //Fill list
const int size = sizeof(array) / sizeof(array[0]);
But when I pass the array as argument in a function I will have a pointer in the function.
int size( int array[] )
{
return sizeof(array) / sizeof(array[0]); //Doesn't work anymore
}
This obviously doesn't work. But how do I get the size of that array in a function without taking another parameter for the size?
how do I get the size of that array in a function without taking
another parameter for the size?
You don't. The size of the array has to be somewhere visible to the compiler. Otherwise all you'll be able to pass is a pointer to the first element in the array.
However, you can use a template for the size, and make this a little more magical and seamless:
template <size_t N> int size (const int (&ary)[N])
{
assert (N == (sizeof(ary) / sizeof (ary[0])));
return N;
}
And further templatizing the type of elements, so this works with arrays of anything:
template <typename T, size_t N> int size (const T (&ary)[N])
{
assert (N == (sizeof(ary) / sizeof (ary[0])));
return N;
}
This is the way to get the size of the array using function templates:
template <typename T, size_t N>
constexpr size_t size(const T (&)[N] ) // omit constexpr if no C++11 support
{
return N
}
then
for(int i = 0; i < size(array); i++) { .... }
but you could simplify things by using an std::array (or std::tr1::array or boost::array if you don't have C++11) and using it's size() method.
In C, arrays in function parameters behave very strangely. Frankly, I think the language was very badly designed here.
void foo(int data[10]) {
int *p;
int a[10];
}
sizeof(p) will probably be 4 (or maybe 8). And sizeof(a) will be 40 (or 80).
So what do you think sizeof(data) will be? If you guessed 40 (or 80), you're wrong. Instead, its size is the same as sizeof(p).
If a C compiler see a [ immediately after the name of a parameter, it removes it and replaces it with a pointer, and data[10] becomes *data. (This is different from the decaying behaviour we get with arrays elsewhere, when a parameter, arrays are dealt with more drastically).
In fact, the following will compile despite the different sized arrays:
int foo(int data[10]);
int main() {
int hugearray[1000];
foo(hugearray); // this compiles!
}
The C compiler doesn't respect, in any way, the size of array parameters. I believe that compilers should issue a warning on any array parameters, and encourage us to use the * directly. I might allow [], but certainly not [10] given that it's ignored by the compiler.
If you want your C compiler to respect the size of arrays, you should pass the address of the array.
int foo(int (*data)[10]);
int main() {
int smallarray[10];
foo(&smallarray); // OK
int hugearray[1000];
foo(&hugearray); // error, as desired
}
Returning to the original question, parameter arrays know nothing about their size.
Use Macro
int findSize(int array[])
{
//This will not return size off array,it will just get starting address array and no information about boundaries
return sizeof(array) / sizeof(array[0]);
}
//But we can define a Macro for this
#define FIND_ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
int main()
{
int SampleArray[30];
printf("\nSize =%d ",sizeof(SampleArray) / sizeof(SampleArray[0]));
printf("\nSize from Function =%d ",findSize(SampleArray));
printf("\nSize from Macro =%d ",FIND_ARRAY_SIZE(SampleArray));
printf("\n");
return 0;
}
In C you can't find the size of array by passing array beginning address to function.
For example You have made function call
size(array); // You are calling function by passing address of array beginning element
int size( int array[] ) // this is same as int size(int *array)
{
return sizeof(array) / sizeof(array[0]); //Doesn't work anymore
}
Here sizeof(array) will give you the size of pointer. that is architecture dependent.
And if you pass character array instead of int array and that too if the character array was nulterminated then You can use strlen().This is the only way we can find the size of array.
strlen() counts till nul occurrence, You can use this trick However allocate memory for one more element to your array or declare your array with MAX_SIZE+1 .When ever if you store array elements of size n then store a known value inside array[n] and while finding size check against that value like strlen() Checks for Nul character.

swapping 2 items in an array, but not passing it by reference

void swap(int a[], int size){
...............
}
int main(){
int x[4] = {4,5,3,12} ;
swap(x,4) ;
// print array here - some elements are swapped
}
So I'm not sure how it is possible for the swap-function to change the order of elements
since it is passed by value in void swap?
If I do something like this: void swap( int (&a)[], int size)
then the original array in my main function would get changed, but how does swap function swap elements, if it just copies the array, and hence should not make any effect on the array in main?
Arrays are not copied when passed as a function arguments. They are "decayed" (automatically converted) to pointers to appropriate first elements. So this code
void swap(int a[], int size) { ... }
is equivalent to
void swap(int* a, int size) { ... }
which should now explain the behavior observed.
(And if indeed you want to prevent that conversion, pass the array by reference).
In C and C++, when you pass an array to a function, you are actually only passing its address (yes, by value, but of course that doesn't change anything since an address passed by value or not always points to the same location).
In the function, whatever element of the array you access or change would be the original one.
So basically, your answer is that you got everything right and no need to do anything.
Example:
void swap(int a[], int size){
for (int i = 0; i < size/2; ++i)
{
a[i] ^= a[size-1-i]; // If you are interested
a[size-1-i] ^= a[i]; // try to understand
a[i] ^= a[size-1-i]; // how this works
}
}
int main(){
int x[4] = {4,5,3,12} ;
swap(x,4) ;
// print array here - some elements are swapped
}
The array is not passed by value, it decays into an int*. Check this code:
void swap(int a[], int size){
}
void swap(int* a, int size){
}
int main()
{
}
Now see what the compiler says:
$ g++ -Wall test.cpp
test.cpp: In function ‘void swap(int*, int)’:
test.cpp:4:6: error: redefinition of ‘void swap(int*, int)’
test.cpp:1:6: error: ‘void swap(int*, int)’ previously defined here
It works because you are not passing the array by value. Passing an array to a function is the same as passing a pointer to the first element in the array. Thus, you are not actually passing by value.
For this reason, I recommend using the more obvious notation:
void swap(int* a, int size)
You would use the double pointer:
void swap(int** a, int size)
or
void swap(int & a[], int size)
only if you want the function to change the memory address of the original array.
i.e. You reallocate the memory and want the caller to receive the new array. Of course, in this case you would probably cause a nasty leak.
If you want to enforce call by value behavior then make the argument const.
void swap(const int* a, int size)
This will prevent the method from being allowed to alter the array in any way. This is useful when you are passing a video buffer or something to a user but you do not want them to corrupt the data.

Determining the quantity of elements in a C array

When print_array is called, the size of the int array[] parameter (count) isn't what was expected. It seems sizeof is not returning the size of the entire array which would be 5*sizeof(int) = 20.
namespace Util
{
void print_array(int array[])
{
size_t count = (sizeof array)/(sizeof array[0]);
cout << count;
// int count = sizeof(array)/sizeof(array[0]);
// for (int i = 0; i <= count; i++) cout << array[i];
}
}
int array_test[5]={2,1,5,4,3};
Util::print_array(array_test);
int array[] here becomes int* array, and sizeof(array) returns the same thing sizeof(int*). You need to pass an array by reference to avoid that.
template <size_t N>
void print_array(int (&array)[N]) {
std::cout << N;
}
int array[] = { 2, 1, 5, 4, 3 };
print_array(array);
Read this: it says the way to fix this, but for a quick description:
When a function has a specific-size array parameter, why is it replaced with a pointer?
Using sizeof(array) will work in the scope that the array is statically defined in. When you pass it into a function though the type gets converted into a pointer to the array element type. In your case, when you're in print_array it is an int*. So, your sizeof in in the function will be the size of a pointer on your system (likely 32 or 64 bits).
You can get around this with some fancy syntax like so (from the link above):
If you want that the array type is preserved, you should pass in a
reference to the array:
void foo ( int(&array)[5] );
but I'd say just pass the size in as well as another parameter, its more readable.
As this array is implemented as a thin overlay on pointers, the variable you have is just a pointer, so sizeof will return the size of your pointer.
The only way to know the length of an array is to place a terminating object, as the null character in C strings.
There is no other way to determine the size of an array if you only have a pointer to it.
Here's a trick: you can take a reference to an array of fixed size. You can use this to template-deduce the size.
#include <iostream>
char a [22];
char b [33];
void foo (char *, size_t size)
{
std :: cout << size << "\n";
}
template <size_t N>
void foo (char (&x) [N])
{
foo (x, N);
}
int main () {
foo (a);
foo (b);
}
This prints 22\n33\n
void print_array( int array[] ) is synonymous with void print_array( int *array ). No size information is passed when the function call is made, so sizeof doesn't work here.
For an algorithm like this, I like to use iterators, then you can do what you want... e.g.
template <typename Iterator>
void print(Interator begin, Iterator end)
{
std::cout << "size: " << std::distance(begin, end) << std::endl;
std::copy(begin, end, std::ostream_iterator<std::iterator_traits<Iterator>::value_type>(std::cout, ", "));
}
to call
print(a, a + 5); // can calculate end using the sizeof() stuff...
just an addition to all the answers already posted:
if you want to use an array which is more comfortable (like an ArrayList in java for instance) then just use the stl-vector container which is also able to return its size
All the following declarations are exactly same:
void print_array(int array[]);
void print_array(int array[10]);
void print_array(int array[200]);
void print_array(int array[1000]);
void print_array(int *array);
That means, sizeof(array) would return the value of sizeof(int*), in all above cases, even in those where you use integers (they're ignored by the compiler, in fact).
However, all the following are different from each other, and co-exist in a program, at the same time:
void print_array(int (&array)[10]);
void print_array(int (&array)[200]);
void print_array(int (&array)[1000]);
int a[10], b[200], c[1000], d[999];
print_array(a); //ok - calls the first function
print_array(b); //ok - calls the second function
print_array(c); //ok - calls the third function
print_array(d); //error - no function accepts int array of size 999

How are arrays passed?

Are arrays passed by default by ref or value?
Thanks.
They are passed as pointers. This means that all information about the array size is lost. You would be much better advised to use std::vectors, which can be passed by value or by reference, as you choose, and which therefore retain all their information.
Here's an example of passing an array to a function. Note we have to specify the number of elements specifically, as sizeof(p) would give the size of the pointer.
int add( int * p, int n ) {
int total = 0;
for ( int i = 0; i < n; i++ ) {
total += p[i];
}
return total;
}
int main() {
int a[] = { 1, 7, 42 };
int n = add( a, 3 );
}
First, you cannot pass an array by value in the sense that a copy of the array is made. If you need that functionality, use std::vector or boost::array.
Normally, a pointer to the first element is passed by value. The size of the array is lost in this process and must be passed separately. The following signatures are all equivalent:
void by_pointer(int *p, int size);
void by_pointer(int p[], int size);
void by_pointer(int p[7], int size); // the 7 is ignored in this context!
If you want to pass by reference, the size is part of the type:
void by_reference(int (&a)[7]); // only arrays of size 7 can be passed here!
Often you combine pass by reference with templates, so you can use the function with different statically known sizes:
template<size_t size>
void by_reference(int (&a)[size]);
Hope this helps.
Arrays are special: they are always passed as a pointer to the first element of the array.