Array passing to a method in C++ [duplicate] - c++

This question already has answers here:
How do I use arrays in C++?
(5 answers)
What is array to pointer decay?
(11 answers)
Closed 8 years ago.
As far as I know, in C++ when you pass a non-pointer object to a method, it makes a copy of it to work with in the method. However in my program below, I pass a copy and yet my method actually edits the original character array. Why is this working? :/
#include <iostream>
#include <string>
void Reverse(char s[], int sizeOfArray)
{
for (int i = 0 ; i < sizeOfArray; i++)
{
s[i] = 'f';
}
}
int main()
{
char c[3] = {'g','t','r'};
Reverse(c,3);
for (int t = 0 ; t < 3; t++)
{
std::cout << c[t];
}
return 0;
}
NOTE:
The output is fff

You cannot copy arrays by passing them to functions. The array "decays" into a pointer. Check for yourself by printing the variables' typeid:
#include <iostream>
#include <string>
void Reverse(char s[], int sizeOfArray)
{
std::cout << typeid(s).name() << "\n";
for (int i = 0 ; i < sizeOfArray; i++)
{
s[i] = 'f';
}
}
int main()
{
char c[3] = {'g','t','r'};
std::cout << typeid(c).name() << "\n";
Reverse(c,3);
for (int t = 0 ; t < 3; t++)
{
std::cout << c[t];
}
return 0;
}
Result:
char [3]
char *
Moral of the story:
Use std::vector.
Edit: I should mention that the exact result of the typeid name is implementation-defined. "char [3]" and "char *" is what I get with VC 2013. But the underlying issue is the same on every compiler, of course.

void Reverse(char s[], int sizeOfArray)
Reverse(c,3);
>call by value
>call by reference
here you are doing call by reference operation that means you are passing address of c to int s[]
you are passing a reference of c to reverse function. this is called call by reference not call by value. thats why reverse function overriding your original input

Because char s[] is actually char * pointing to the first element of array.
It means your function Reverse gets the first arg pointer but not copy of array.
If you want to get copy you should use memcpy first and pass new (copy) array to function.

C-array cannot be passed by copy.
It may be passed by reference as void Reverse(char (&a)[3])
or by its decayed pointer as you do void Reverse(char a[], int size)
(which is the same as void Reverse(char* a, int size)).
You may use std::array (C++11) to have a more intuitive behaviour.

if you declare an array then the variable holds the base address of that array, so here char c[3] means c holds the base address of the array c[3].
so, when you are passing Reverse(c,3); actually you are passing the base address.

Related

Is it possible to pass a 2D array using a void pointer in C++?

I want to pass a 2D array of characters to another function using a parameter of type "void*" and then have that function have access to the elements inside that array.
This code spits out a "Segmentation Fault:11" at the point where voidPointer tries to std::cout elements inside array2.
#include <iostream>
void voidPointer(void* userdata) {
char** array2 = static_cast<char**>(userdata);
for (int i=0; i<3; ++i) {
for (int j=0; j<3; ++j) {
std::cout << array2[i][j] << ' ';
}
std::cout << std::endl;
}
return;
}
int main() {
char array[3][3];
for (int i=0; i<3; ++i) {
for (int j=0; j<3; ++j) {
array[i][j] = 'a';
}
}
voidPointer(array);
return 0;
}
I've tried lots of different things and can't figure this out at all. I was able to get the above code to work when it's dealing with a 1D array. For example, this code
#include <iostream>
void voidPointer(void* userdata) {
char* array2 = static_cast<char*>(userdata);
for (int i=0; i<3; ++i) {
std::cout << array2[i] << ' ';
}
std::cout << std::endl;
return;
}
int main() {
char array[3];
for (int i=0; i<3; ++i) {
array[i] = 'a';
}
voidPointer(array);
return 0;
}
works as expected with the output "a a a".
Backstory: I'm working on my first project in which I'm trying to use a Mouse Callback function that accepts a parameter in the form "void* userdata". I am attempting to pass a 2D character array to this Callback function so I can then pass it on to other functions that will require access to the elements inside this array. I don't really know if this is good coding practice or not so feel free to let me know some alternatives.
To anyone that responds, thank you!
Firstly, I'll explain why your second example succeeds but your first example fails. Then I'll suggest some options for consideration to make your code work.
In short - your first example has undefined behaviour because the notional equivalence of pointers and arrays only works in one dimension.
The second example relies on the facts that;
The name of a one-dimensional array can be implicitly converted to a pointer to that array's first element. So, in main() of your second example, voidPointer(array) is equivalent to voidPointer(&array[0]). &array[0] has type char *.
A pointer can survive a round trip via a void * conversion - where "round trip" means retrieving the pointer of the original type. i.e. a char * can be converted to a void * AND that void * can be converted back to a char *. So the explicit conversion char* array2 = static_cast<char*>(userdata) done in voidPointer() successfully retrieves the pointer - so array2 in voidPointer() is equal to &array[0] passed by main();
Since the pointer passed by main() is the address of the first element of the array passed, voidPointer() can safely treat that pointer AS IF it is an array (as long as code doesn't try to access elements out of range of the original array).
The logic above is only applicable for pointers and one-dimensional arrays, so breaks down in the first example;
The name of a one-dimensional array can be implicitly converted to a pointer to that array's first element. So, in main() of your second example, voidPointer(array) is equivalent to voidPointer(&array[0]). However, the difference is that - the expression &array[0] has type char (*)[3] (a pointer to an array of three char) and that is NOT equivalent to a char **.
in voidPointer() your code converts the received pointer to a char ** via char** array2 = static_cast<char**>(userdata). This means that the pointer array2 has a different type that the pointer (&array[0]) passed by main();
Since array2 has a different type than the pointer passed by main() the code in voidPointer() which dereferences array2 (treats it as if it is an array of arrays) has undefined behaviour.
Generally speaking, there are two ways you can make the code work. The first is to do the right type of conversion.
void voidPointer(void* userdata)
{
char (*array2)[3] = static_cast<(char (*)[3]>(userdata);
// rest of your function can be used as is
}
As in your code, the array dimensions (which are both 3 in your example) must be known and fixed at compile time. There is no way that userPointer() can obtain any array dimensions from userdata, because a void * does not carry any of that sort of information from the caller.
A second option is to wrap the array in a data structure, for example
#include <iostream>
struct Carrier {char data[3][3];};
void voidPointer(void* userdata)
{
Carrier *package2 = static_cast<Carrier *>(userdata);
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
std::cout << package2->data[i][j] << ' ';
}
std::cout << std::endl;
}
}
int main()
{
Carrier package;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
package.data[i][j] = 'a';
}
}
voidPointer(&package);
return 0;
}
This works because a Carrier * can survive a round trip via a void pointer (i.e. the value of package2 in voidPointer() has the the same type AND the same value as &package in main()) .
A second option is to use the std::array class. Although this is syntactically different, it is actually a modified version of the first option (since std::array is technically a templated data structure that contains an array of fixed dimension).
#include <iostream>
#include <array>
void voidPointer(void* userdata)
{
std::array<std::array<char, 3>, 3> *package2 = static_cast<std::array<std::array<char, 3>, 3> *>(userdata);
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
std::cout << (*package2)[i][j] << ' ';
}
std::cout << std::endl;
}
}
int main()
{
std::array<std::array<char, 3>, 3> package;
for (int i=0; i<3; ++i)
{
for (int j=0; j<3; ++j)
{
package[i][j] = 'a';
}
}
voidPointer(&package);
return 0;
}
Since your examples both had array dimensions fixed at compile time (3 in each dimension), my examples do the same. I'll leave extending the above to have dimensions fixed at run time (e.g. as user inputs) as a learning example.
It looks like the question is how to make this scenario work instead of why the attempt failed. For those interested in why the attempt failed, see casting void** to 2D array of int.
Note: It would be better to avoid using void*, but sometimes one has to interface with someone else's C-style API where void* is the traditional way to pass data to a callback.
There is a reasonably common trick for simulating a multi-dimensional array with a one-dimensional array. Using the trick reduces your scenario to the case that works. The trick involves how you access the elements. Instead of declaring char array[DIM1][DIM2] and accessing elements via array[i][j], declare the array to be char array[DIM1 * DIM2] and access elements via array[i*DIM2 + j].
However, remembering this formula is intellectual overhead, consuming brainpower that would be better used elsewhere. Not to mention that I get the dimensions reversed half the time. You could relieve the coder of this overhead by wrapping this array in a class, and hiding the formula in a method for accessing elements. This might look like the following.
class Array2D {
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
char data[DIM1 * DIM2];
public:
char& at(unsigned i, unsigned j) { return data[i*DIM2 + j]; }
// And perhaps other methods
};
You could then create an object of this class, then pass the address of that object to your C-style mouse handler. I.e. if your variable is Array2D array then call voidPointer(&array). This version can be adapted to the situation where the dimensions are not known at compile time.
Then again, if you are going to create a class anyway, why not try to preserve the syntax you are used to (using operator[] twice)? This does assume that the dimensions are compile-time constants.
class Array2D {
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
char data [DIM1][DIM2];
public:
auto& operator[] (unsigned i) { return data[i]; }
// And perhaps other methods
};
Of course, this approach locks you into a single size. It would probably be a good idea to make this a template. It would be even better if someone else did all that work for me.
#include <array>
static constexpr unsigned DIM1 = 3;
static constexpr unsigned DIM2 = 3;
using Array2D = std::array< std::array<char,DIM2>, DIM1 >;
// Note the order: ^^^^ ^^^^
Remember: if your variable is Array2D array then call voidPointer(&array).
Why not to use a structure instead of array. You can define everything in a structure, than pass its address to your function.

What is the difference between allocating a specific sized array vs declaring a specific sized array in function in cpp? [duplicate]

This question already has answers here:
What is a dangling pointer?
(7 answers)
Closed 5 years ago.
Normally a scope of an array in a function ends with it. But if I allocate beforehand then it perfectly returns the array. So what's the difference between allocating array or declaring array?
I am writing the code and the place where I am confused. Is it because of dynamic memory allocation of the first declaration or something else. Can someone elaborate please?
#include <bits/stdc++.h>
#define N 10
using namespace std;
int * get_array() {
int * p = new int[N];
//|--- by declaring like this, the array was perfectly returned.
int p[N];
//|--- but is case of this declaration the array returned showed garbage value in the main function.
for(int i = 0; i < N; ++i) p[i] = i;
return p;
}
int main(int argc, char const *argv[])
{
int * M = get_array();
for (int i = 0; i < N; ++i) {
cout << M[i] << endl;
}
return 0;
}
In the second case the array is created in the heap of the function, so when you exit the function, that array doesn't exists anymore.
In the first case, you're reserving memory space to put your array, so isn't local to the function per se, and you must handle its destruction

c++ size of array is changing using sizeof [duplicate]

This question already has answers here:
When a function has a specific-size array parameter, why is it replaced with a pointer?
(3 answers)
Closed 8 years ago.
i have simple main that called simple methods with array as parameter
the size in the array is right , but then when i try to print the array im getting different
sizeof array :
int bubbleSort(int arr[]) // yeah i know this sort is not complete
{
int arrSize = sizeof(arr); // HERE IS SIZE IS 4
bool bSorted = true;
while(bSorted)
{
for(int i=0;i<arrSize;i++)
{
if(arr[i]>arr[i+1])
{
int tmp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = tmp;
}
}
bSorted = false;
}
return 1;
}
int main(int argc, char* argv[])
{
int arr[] = {4,3,7,8,9};
bubbleSort(arr);
int sOf = sizeof(arr); // HERE THE SIZE IS 20 ????
for(int j=0;j < sOf ;j++)
{
printf("%d",arr[j]);
}
return 0;
}
You cannot pass arrays* by value as function parameters (nor return them in such fashion). The syntax void f(int a[]) is merely syntactic sugar that is in every aspect identical to void f(int * a), and the function parameter is a pointer, not an array. So you end up measuring the size of the pointer.
The alternative syntax may serve as a loose kind of documentation of intent, signalling that you plan to call this function with the address of an array element, but there is no actual difference to the pointer syntax.
*) Array types and function types are both constrained thus, which is why people often say that they are not first-class citizens of the type system.
Due to the language being stupid, this:
int bubbleSort(int arr[])
actually means this:
int bubbleSort(int* arr)
So sizeof(arr) is the size of a pointer.

Arrays as address constants in functions

I'm teaching myself C++ and had some questions about arrays and pointers. My understanding is that arrays are really just pointers, however, arrays are address constants which cannot be changed.
If this is the case, I was wondering why in my function show2() I was able to change the address of the pointer list. Unlike variables, I thought arrays are passed by reference so I was expecting a compiler error when calling function show2() since I incremented the address of list. But the code works just fine. Can someone please explain?
Thank you!
#include<iostream>
#include<iomanip>
using namespace std;
void show1(double *list, int SIZE)
{
for(int i=0; i < SIZE; i++)
{
cout << setw(5) << *(list+i);
}
cout << endl;
return;
}
void show2(double *list, int SIZE)
{
double *ptr = list;
for(int i=0; i < SIZE; i++)
cout << setw(5) << *list++;
cout << endl;
return;
}
int main()
{
double rates[] = {6.5, 7.2, 7.5, 8.3, 8.6,
9.4, 9.6, 9.8, 10.0};
const int SIZE = sizeof(rates) / sizeof(double);
show1(rates, SIZE);
show2(rates, SIZE);
return 0;
}
My understanding is that arrays are really just pointers
Let's get that out of the way. No, arrays are not pointers. Arrays are a series of objects, all of the same type, contiguous in memory.
Arrays can be passed by reference, but that is not what is usually done. What is usually done, which is what you are doing, is passing a pointer to the first element of the array. Arrays can and will "decay" to a pointer to their first element upon demand. And that's what is happening when you pass rates to show1 and show2.
Inside show1 and show2, list starts out as a pointer to rates[0]. You're free to modify this pointer to point at any other double.
If you wanted to pass an array by reference, it would look like this:
void show3(double (&list)[9]) { ... }
Or the more versatile:
template<size_t SIZE>
void show3(double (&list)[SIZE]) { ... }
Note that what you can't do is pass an array by value (unless it is contained within another object). If you write a function which looks like it is taking an array by value, e.g.
void show4(double list[9]) { ... }
It is actually a pointer, and that number 9 is meaningless. Native arrays suck.
First, arrays are converted to a pointer to the first element when passed as the function argument. BTW, arrays are not pointers, as one example, sizeof(rates) in your code isn't the size of a pointer.
Second, arrays are passed by value since you are not using references.
So in the function show2, you are modifying a pointer, which is fine.
Arrays are not pointers. C++ has inherited "Array-Pointer Equivalence" from C which means that a well-known array variable can decay to a pointer, primarily for the purpose of offset math and for avoiding passing arrays by value:
int array[64];
int* a = array; // equivalent to a = &array[0];
Array's aren't pointers. If you use an array variable name in a pointer context, it will "decay" to a pointer - that is, lose the extended attributes available from an array object.
int array[64];
int* a = array;
std::cout << "array size = " << sizeof(array) << "\n";
std::cout << "a size = " << sizeof(a) << "\n";
std::cout << "(int*)(array) size = " << sizeof((int*)array)) << "\n";
"Array size" will be 256 (int is 4 bytes, 64 of them = 256 bytes), "a size" will be 4 or 8 bytes depending on 32/64 bits, and "(int*)(array)" size will be the same size as the pointer.
People often think that arrays are passed by value. This is not true: http://ideone.com/hAeH18
#include <iostream>
void bump(int arr[3]) {
for (size_t i = 0; i < 3; ++i)
arr[i]++;
}
int main() {
int array[] = { 1, 2, 3 };
bump(array);
for (size_t i = 0; i < 3; ++i)
std::cout << array[i] << "\n";
return 0;
}
This outputs "2, 3, 4" not "1, 2, 3".
This occurs because arrays decay to pointers when passed as function arguments. But to support the syntax for receiving arrays as arrays, C has to be able to treat pointers like arrays in some contexts:
void f1(int* a) { a[0]++; }
void f2(int* a) { (*a)++; }
void f3(int a[]) { a[0]++; }
void f4(int a[]) { (*a)++; }
void f5(int a[1]) { a[0]++; }
void f6(int a[1]) { (*a)++; }
All of these functions produce the same code.
In C, this originated from the fact that array information is lost at compile time. So this function:
void f(int array[])
has no way to tell how large the array it is receiving is. They wanted programmers to be conscious of this and be careful about how/if they passed size information - e.g. in the case of char arrays, instead of size, we have the nul terminator byte.
Unfortunately they didn't choose to make it obvious by diasllowing the representation that makes it look like you are receiving an array with size information intact :(

Passing an array of ints as an argument in C++? [duplicate]

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Passing Arrays to Function in C++
(5 answers)
What is array to pointer decay?
(11 answers)
Closed 9 years ago.
I made a function in C++ to find the length of an array. I find the sizeof the array passed in the argument and divide it by the sizeof the variable type. This should work but it always returns 1! Am I missing something obvious? Or does this have to do with pointers and memory? This is my code:
#include <iostream>
using namespace std;
int lengthOf(int arr[]);
int main() {
int x[] = {1,2,3,0,9,8};
int lenX = lengthOf(x);
cout << lenX;
return 0;
}
int lengthOf(int arr[]) {
int totalSize = sizeof arr;
cout << totalSize << endl;
int elementSize = sizeof(int);
return totalSize/elementSize;
}
Output (should be 6 instead of 1):
4
1
I am fairly new so excuse me if this is a bad question.
When passing an array as parameter, it always decays into a pointer. If you want to see the size of the array, you need to pass the array by reference, e.g.:
template <int Size>
int lengthOf(int (&array)[Size]) {
return Size;
}
You should use the pointer.
(sizeof(arr)/sizeof(*arr))
Even though int arr[] looks like you are passing an array, you are actually passing a pointer. int arr[] is equivalent to int* arr when used as a function parameter, this comes from C.
In C++, if you want to pass an array, the proper way is to do it by reference:
template <int N>
int lengthOf(int (&arr)[N]) {
int totalSize = sizeof arr;
cout << totalSize << endl;
int elementSize = sizeof(int);
return totalSize/elementSize;
}