I am trying to write a function that swap two arrays in O(1) time complexity. However, when i try to write the function parameters, I get the error:
error: cannot convert ‘int (*)[4]’ to ‘int**’
Here is my code:
#include <iostream>
using namespace std;
void swap_array_by_ptr(int* a[], int* b[]) {
int* temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int fr[] = {1,2,3,4};
int rv[] = {4,3,2,1};
swap_array_by_ptr(&fr, &rv);
for (int i = 0; i < 4 ; i++) {
cout << fr[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << rv[i] << " ";
}
}
However, when i tried to define the arrays with 'new' command, this works as expected as below:
#include <iostream>
using namespace std;
void swap_array_by_ptr(int** a, int** b) {
int* temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int fr = new int[4]{1,2,3,4};
int rv = new int[4]{4,3,2,1};
swap_array_by_ptr(&fr, &rv);
for (int i = 0; i < 4 ; i++) {
cout << fr[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << rv[i] << " ";
}
}
Is there any way that i can define the arrays with [] method and swap the arrays by sending these arrays with '&array' method ?
As I believe, there must be a way to do that, I only achieve this when I'm trying to do with 'new' method. However, is there any way to swap two arrays in O(1) complexity with sending parameters as
swap_array_by_ptr(&fr, &rv);
?
Thanks for help.
You can not swap two arrays with O( 1 ). You need to swap each pairs of corresponding elements of two arrays.
In the first program
int fr[] = {1,2,3,4};
int rv[] = {4,3,2,1};
swap_array_by_ptr(&fr, &rv);
the expressions &fr and &rv have type int( * )[4] while the corresponding function parameters in fact has the type int **
void swap_array_by_ptr(int* a[], int* b[]) {
after adjusting the parameters having array types to pointers to the array element types by the compiler.
So the compiler issues an error.
You could use standard function std::swap declared in the header <utility> the following way
std::swap( fr, rv );
But in any case its complexity is O( n ).
In the second program there are at least typos. Instead of
int fr = new int[4]{1,2,3,4};
int rv = new int[4]{4,3,2,1};
you have to write
int *fr = new int[4]{1,2,3,4};
int *rv = new int[4]{4,3,2,1};
In this case you are not swapping arrays themselves. That is the arrays will still store their initial values. You are swapping pointers that point to the dynamically allocated arrays.
To be sure that arrays are not swapped consider the following demonstration program.
#include <iostream>
using namespace std;
void swap_array_by_ptr(int** a, int** b) {
int* temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int fr[] = { 1,2,3,4};
int rv[] = {4,3,2,1};
int *p1 = fr;
int *p2 = rv;
swap_array_by_ptr( &p1, &p2 );
for (int i = 0; i < 4 ; i++) {
cout << p1[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << p2[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << fr[i] << " ";
}
cout << endl;
for (int i = 0; i < 4 ; i++) {
cout << rv[i] << " ";
}
cout << endl;
}
It is a syntactic quirk inherited from C that a declaration of a function parameter as an array is automatically converted to a declaration as a corresponding pointer. This is not as odd as it might first seem, however, because it dovetails with the automatic conversion of function arguments of array type to corresponding pointers, also inherited from C.*
Thus, this declaration ...
void swap_array_by_ptr(int* a[], int* b[]) {
... is equivalent to this one:
void swap_array_by_ptr(int **a, int **b) {
. But the arguments you are passing do not match. This, for example,
int fr[] = {1,2,3,4};
declares fr as an array of 4 int. If it were passed as a function argument, it would be automatically converted to a pointer to the first element, thus of type int *. Types int * and int ** are not compatible.
On the other hand, what you actually try to pass, &fr is the address of an array 4 int, of type int(*)[4]. This also is incompatible with int **, because arrays are not pointers.
You could write your function like this:
void swap_array_by_ptr(int (*a)[4], int (*b)[4]) {
int temp[4];
memcpy(temp, a, sizeof(a));
memcpy(a, b, sizeof(b));
memcpy(b, temp, sizeof(temp));
}
That would be compatible with the call in your code. Do note, however, that that is specific to array size 4, and you're not really gaining anything useful from that. You could, however, convert it to a template:
template<class T, std::size_t n>
void swap_array(T (*a)[n], T (*b)[n]) {
T temp[n];
memcpy(temp, a, sizeof(a));
memcpy(a, b, sizeof(b));
memcpy(b, temp, sizeof(temp));
}
That handles arrays of any element type and size,** as long as the sizes match. Of course, it scales as O(N) with array size, in both time and auxiliary space.
Such time scaling is unavoidable. To swap two objects you need to read each at least once and write each at least once, and that requires time proportional to the size of the objects. But you could reduce the space overhead to O(1) by swapping the arrays element by element in a loop. That would very likely be slower, but the time complexity would still be O(N).
Of course, you can also use std::swap() on arrays. It is quite similar to the template above, but uses references to the arrays instead of pointers to them.
*This is a specific case of a much more general behavior.
**So long as the temporary array does not turn out to be too large for the stack.
Change the swap_array_by_ptr function from 'swap_array_by_ptr(int** a, int** b)'
to 'swap_array_by_ptr(int* a, int* b)'.
void swap_array_by_ptr(int* a, int* b) {
int* temp = *a;
*a = *b;
*b = temp;
}
here's a link to a similar question: Swapping 2 arrays in C
Related
Write a function, reverseArray, that when passed an int array of length greater than 0 will return a dynamically allocated array of the same length but with the elements in the reverse order. For example, if passed the array, {1,2,3,4,5,6,7,8,9,0} the function would return the array {0,9,8,7,6,5,4,3,2,1}.
Below is my code, but there is a bug in it.
This is my output.
1
2
3
4
5
6
4113
6
5
4
3
2
1
0x7fffe697ceb0
The 4113 and address are provided by the compiler.
#include <iostream>
using namespace std;
int * readNumbers() {
int * a = new int[6];
for (int i = 0; i < 6; i++) {
int x;
cin >> x;
a[i] = x;
}
// a++;
return a;
delete[] a;
}
int *reverseArray(int *numbers1,int length) {
for (int i = length; i >=0; i--) {
cout << numbers1[i] << endl;
}
return numbers1;
delete [] numbers1;
}
int main() {
int *arr1 = readNumbers();
cout << reverseArray(arr1,6) << endl;
return 0;
}
I think there may have been an issue with your wording. Assuming you want your function just to print the reverse of a passed array, you're off to a good start.
One issue is what was said in the comments: your for loop is indexing past your array. When you type int * a = new int[6]; you are creating a pointer 'a' which points to a location in memory. Since you chose size 6, the appropriate amount of memory is allocated. If you happen to index outside of that range, you will end up pointing to a random spot in memory, not allocated for your array. Hence why you are getting a weird number '4113'.
A fix for this could be:
int i = length changed to int i = length-1
Another issue is that your function returns an integer pointer, and you are trying to cout this pointer. As another commenter said, you have to think about what this does. If you try this code:
#include <iostream>
using namespace std;
int main() {
int arr[] = {1, 2, 3};
cout << arr << endl;
return 0;
}
your output would be something like 0xff09ba. This represents the location of the start of the array in memory. If you change arr to (arr + 1) you will get the location of the second index of the array.
So when you type cout << reverseArray(arr1,6) << endl; you are really just printing out the location of numbers1 in memory. This is why you are getting '0x7fffe697ceb0' in your output. To fix this, simply make your function
void reverseArray(int *numbers1,int length) {
for (int i = length; i >=0; i--) {
cout << numbers1[i] << endl;
}
}
and change your main to:
int main() {
int *arr1 = readNumbers();
reverseArray(arr1,6);
return 0;
}
Now, if you actually want to return this array, you would need to create a new array which holds the reverse numbers and then return that. An example of a function that does that is:
int* reverseArray(int *numbers1,int length) {
int j = 0;
int *numbers2 = new int[length];
for (int i = length-1; i >=0; i--) {
numbers2[j] = numbers1[i];
j++;
}
return numbers2;
}
There are probably better ways to do this, but this is just one solution. Regardless, you should always be careful when allocating memory yourself.
i have a little problem with my college assignment. I don't really understand what's going on with pointers and reference. Could someone point me where I am making a mistake??
using namespace std;
int i, n, maax, *position;
void tablica()
{
int tab[n];
cout<<"enter data:"<<endl;
for (i=0; i<n; i++)
{
cin>>tab[i];
}
maax = tab[0];
for (i=0; i<n; i++)
{
if (maax<tab[i])
{
maax=tab[i];
*position=i+1;
}
}
}
int main()
{
cout<<"array size:"<<endl;
cin>>n;
tablica();
cout<<"max el. position is: "<<&position<<endl;
return 0;
}
Sure we can help you a little bit. But the whole topic of pointers and references cannot be covered in a short answer here on SO. You need to read a book.
The following will be very simplified and there is much more in reality. But let's start with this simple explanantion.
Let me give you a typical example that is often used in C or very early C++ books. Look at the function swap that should exchange the values of 2 variables.
#include <iostream>
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 2;
swap(a, b);
std::cout << "a: " << a << "\tb: " << b << '\n';
}
We hope that after the call to the function swap, "a" will contain 2 and "b" will be 1. But it is not. Because in this case (and per default) the variables that are given to the function swap, are passed by value. So, the compiler will generate some code and copies the value of variables "a" and "b" into some local internal storage, also accessible with the name "a" and "b". So, the original "a" and "b" will never be touched or modified. By passing a variable by value, a copy will be mdae. This is often intended, but will not work in this example.
The next development stage was the pointer. The pointer is also a variable that contains a value. But this time it is the address of another variable somehwere in memory. If you have a variable like int a=3; then the 3 is somewhere stored in memory (decided by the compiler of the linker) and you can access the memory region with the name "a".
A pointer can store the memory address of this variable. So not the value 3 of the variable "a", but the address of the variable "a" in memory. The pointer points to that memory region, where the 3 ist stored. If you want to access this value, then you need to dereference the pointer with the * operator. And to get the address of variable 'a', you can write &a. But how does this help?
It helps you indirectly to get modified or result values out of a function. Example:
#include <iostream>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int a = 1, b = 2;
swap(&a, &b);
std::cout << "a: " << a << "\tb: " << b << '\n';
}
In main we take the address of variable "a" and "b" and give this to the function. The address of the function (the pointer) will be given to the function as value now. A copy of the pointer will be made (not in reality) but this does not harm, because we can now modify the original values of the variable, by derefencing the pointer. Then the function ends and we will find the correct values in the original variables "a" and "b".
But, pointers are notoriously difficult to understand and very error prone. Therefore the "reference" has been invented. It is kind of an alias for a normal variable. And the good point is that if you pass a reference to the function, then you can modify immediately the original value. That makes things very convenient.
The function swap could then be written as
#include <iostream>
void swap(int &a, int &b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 1, b = 2;
swap(a, b);
std::cout << "a: " << a << "\tb: " << b << '\n';
}
And this gives the intented result. And is by far simpler.
Now to your code. First, VLAs (variable length arrays), namely the int tab[n]; where 'n' is no compile time constant, are a not a ppart of the C++ language. You canot use them. You could and should use a std::vector instead, but you did not yet learn about it. So we will use new, to allocate some memory dynamically. Please note: In reality, new, raw pointers for owned memory and C-Style arrays should not be used. But anyway.
Then let us look at your requirements
function returns the max element. pass the array by the pointer and the pos. by the reference
So, we need a function to calculate the max element in an array, then return this value, and additionally copy the position of the max element in a variable, given to the function as reference. We will add an additional parameter for the size of the array, because we will not use VLAs here. The array will be given by pointer.
So the prototype of your function will be:
int getMaxElement(int *array, int sizeOfArray, int& positionOfMaxValue)
To implement such a function, we create an internal variable to hold the max value, which we will later return. Then, we compare all values in a loop against this max value and, if we find a bigger one, then we store this new result. As the initial value, we can simply take the first value of the array.
Example:
#include <iostream>
int getMaxElement(int* array, int sizeOfArray, int& positionOfMaxValue) {
int resultingMaxValue = 0;
if (sizeOfArray > 0) {
resultingMaxValue = array[0];
for (int i = 0; i < sizeOfArray; ++i) {
if (array[i] > resultingMaxValue) {
resultingMaxValue = array[i];
positionOfMaxValue = i;
}
}
}
return resultingMaxValue;
}
int main() {
// Get array size from user
std::cout << "\nPlease enter the array size: ";
int arraySize = 0;
std::cin >> arraySize;
// Create an array
int* array = new int[arraySize];
// Read all values into the array
for (int i = 0; i < arraySize; ++i)
std::cin >> array[i];
// Now calculate the max value and position of the max value
int position = 0;
int maxValue = getMaxElement(array, arraySize, position);
// Show result
std::cout << "\n\nResult:\nThe maximum value '" << maxValue << "' is at position " << position << '\n';
delete[] array;
}
Please remember: This is a very simplified explanation
You shouldn't use global variables (see Are global variables bad?). int tab[n]; is not standard C++, its a variable length array that is only available as extension on some compilers (see Why aren't variable-length arrays part of the C++ standard?). The segfault is because you never allocate memory for the position, it is initialized because its a global, but it doesnt point to an int (see Is dereferencing a pointer that's equal to nullptr undefined behavior by the standard?).
You do not need any array to get the max value and position. And there is no need to use a pointer in your code. Determine the maximum value and position in the same loop that is reading the input and return the result from the function instead of using the global variable:
#include <iostream>
int tablica(int n) {
std::cout<<"enter data:\n";
int max = 0;
int max_pos = 0;
std::cin >> max;
for (int i=1; i<n; i++) {
int number = 0;
std::cin>>number;
if (max<number) {
max=number;
max_pos = i;
}
}
return max_pos;
}
int main()
{
std::cout<<"input size:\n";
int n;
std::cin>>n;
int position = tablica(n);
std::cout<<"max el. position is: "<< position << "\n";
return 0;
}
Look at what the function should do:
"function returns the max element. pass the array by the pointer and the pos. by the reference"
It should not read any array elements.
It should not receive or return values in global variables.
It should not use a pointer to the position.
It should be passed an array (as a pointer) and somewhere to store the maximum position (as a reference), and return the maximum value.
That is, its prototype should look like
int tablica(const int* input, int size, int& max_position)
and main should look something like this:
int main()
{
int n = 0;
cout << "Array size: " << endl;
cin >> n;
int* data = new int[n];
for (int i = 0; i < n; i++)
{
cin >> data[i];
}
int position = -1;
int max_element = tablica(data, n, position);
cout << "The maximum element is " << max_element << ", at index " << position << endl;
delete [] data;
}
Implementing tablica left as an exercise.
i'm new to programming , this code gives me syntax error in line => int *result = apply_all(array1,5,array2,3) this is the error: expected primary-expression before '}' token|
i'm trying to write function called apply_all expects 2 arrays of integers and their sizes and dynamically allocates a new array of integers whose size is the product of 2 array sizes.
the function should loop through the 2nd array and multiple each element accross each element of array 1 and store the product in newly created array. the function is returning a pointer of to the newly allocated array.
also i wrote a function which is print to display the 1st & 2nd & newly array.
#include <iostream>
using namespace std;
//function prototype
int *apply_all(int *array1 ,int size1,int *array2,int size2);
void print(int *array,int size);
int main()
{
int array1[] {1,2,3,4,5};
int array2[] {10,20,30};
cout << "Array 1:";
print(array1,5);
cout << "Array 2:";
print(array2,3);
int *result = apply_all(array1,5,array2,3);
cout << "Result : ";
print(result,15);
delete [] result;
return 0;
}
int *apply_all(int *array1 ,int size1,int *array2,int size2)
{
int *result {nullptr};
result = new int[size1 * size2];
for (int i{0};i<size2;i++)
for(int j{0};j<size1;j++)
*(result[i*5+j]) = *(array1[i])**(array2[j]);
return result;
}
void print(int *array,int size)
{
for(auto num:array)
cout << num << endl;
}
On this line:
*(result[i*5+j]) = *(array1[i])**(array2[j]);
since result[i*5+j] gives you an int, you are trying to dereference an int, which is not possible.
You just need to do:
result[i*5+j] = array1[i] * array2[j];
Also, in print, your range-for loop won't work with a pointer. You need to do:
for(int i = 0; i < size; ++i)
cout << array[i] << endl;
Also, in apply_all, your loop bounds are incorrect. i needs to go till size1, and j needs to go to size2.
Here's a demo.
Since you are new, a simple work around would be creating an array with buffer space to store your results in and passing the pointer for this into apply_all. You could then write to this array which (being declared in main) should be very easy to access and cause few errors and use a c-string like ending to know when your results are over and to stop printing from the array (c-strings end with a value of 0 so that programs don't read unrelated memory). eg:
int buf[99];
apply_all(array_1, size1, array_2, size2, buf, size3);
for (int x = 0; buf[x] != end of buf var; x++;)
{
print(buf[x])
}
and
apply_all()
{
buf[start-end] = whatever you want;
buf[end + 1] = some variable that won't appear in buffer; //max int size?
}
struct zone {
int a;
double b;
};
zone *abc() {
static zone r[10];
for (int i = 0; i < 10; i++) {
r[i].a = 2 * i;
[r[i].b=0.5*i;
cout << r[i].a << " " << r[i].b << endl;
}
return r;
}
int main() {
zone *PP;
zone P[10];
PP = abc();
for (int i = 0; i < 10; i++) {
P[i] = (PP + i);
cout << "work" << P[i].a << endl;
}
getch();
}
I need to return an array of structs that is formed in a function called by main. I managed to retrieve an array with a pointer, but with struct it doesn't work.
How do I return a struct array?
You are assigning a value of variable with a pointer:
P[i] = (PP + i);
To get a copy of internal value, you need access struct:
P[i] = PP[i];
Would be like this:
#include <iostream>
using namespace std;
struct zone {
int a;
double b;
};
zone *abc() {
static zone r[10];
for (int i = 0; i < 10; i++) {
r[i].a = 2 * i;
r[i].b=0.5*i;
cout << r[i].a << " " << r[i].b << endl;
}
return r;
}
int main() {
zone *PP;
zone P[10];
PP = abc();
for (int i = 0; i < 10; i++) {
P[i] = PP[i];
cout << "work" << P[i].a << endl;
}
}
Your struct contains just digits, however, if it contains strings or pointer, you will need make a deep copy.
Well fairly simple - by using another struct to encapsulate the returned array in order to get over 'C' language limitations.
struct zone {
int a;
double b;
};
struct zone_array_of_10 {
zone arr[10];
};
zone_array_of_10 abc() {
zone_array_of_10 r;
for (int i = 0; i < 10; i++) {
r.arr[i].a = 2 * i;
r.arr[i].b=0.5*i;
cout << r.arr[i].a << " " << r.arr[i].b << endl;
}
return r;
}
int main() {
zone_array_of_10 PP;
PP = abc();
for (int i = 0; i < 10; i++) {
cout << "work" << PP.arr[i].a << endl;
}
getch();
}
It's fact that in 'C' language arrays can't be passed by value. However structures can. So whenever you want to pass the actual content of some array without much hassle - just encapsulate it in a structure.
A cool feature of C++ is the use of references. The best part of references is that they allow you to pass data in an out of a function without copying the data (you are using the same data inside and pass back out). So if you make a function.
Another method is to use a pointer to a pointer. You can pass a pointer pointer or address of a pointer and malloc within the function.
structure* a;
funct(&a);
printf("%s\n", a[0].printfunction());
printf("%s\n", a[1].printfunction());
...
void funct(structure** a, int size){
*a = (structure*)malloc(sizeof(structure) * size);
(*a)[0] = ...
(*a)[1] = ..
(*a)[ size-1] = ...
}
You can access the array outside of the function. Just be sure to free/delete anything you call with malloc/new. The above code can use new I'm just better with c. You can easily pull the malloc outside of the function and just pass in a pointer to the array.
In C, a function can't take or return an array. This is annoying, and I've never heard a good reason given for it. Anyway, C++ fixed this a long time ago, but it never really caught on, for reasons that will become plain in a moment.
Obligatory "for anything larger than a toy application you should strongly reconsider using naked pointers and/or raw arrays!"
C++ introduced references. They are really just syntactic sugar around pointers, but aren't all variables just syntactic sugar around pointers? In C++, a function can take and/or return a reference to an array. Like so:
int takes (char (&arr)[10])
{
std::cout << sizeof(arr); // 10
}
int (&returns())[10]
{
return some_array; // Not a pointer!
}
int (&takes_and_returns (int (&arr)[10])) [10]
{
return arr;
}
Of course, I don't have to tell you that this is extremely ugly and difficult to read. Modern C++ to the rescue!
template <size_t n, typename T>
using array<n,t> = T[n];
int takes (array<10,int>& arr);
array<10,int>& returns();
array<10,int>& takes_and_returns (array<10,int>& arr);
Note, however, that due to the way new works, it is an ordeal to properly construct and then return a reference to a dynamic array. This is how I did it, but I'm not even sure if this is correct; there might lurk some UB:
int (&returns())[10]
{
int* x = new int[10];
return *(int(*)[10]) x;
}
Of course, we can tidy this up a bit:
using arr10 = int[10];
arr10& returns()
{
int* x = new int[10];
return *(arr10*) x;
}
And then, at the call site, you'd assign it to a reference like so:
int (&my_array)[10] = returns();
// doing stuff ...
delete[] &my_array;
As you can see, at the end of the day, getting all this to work correctly and to interoperate with existing features is a bit of an ordeal. If you need a function to take or return an array, this is how you do it. But for most purposes, it is better (easier, safer) to use standard library containers.
#include <iostream>
using namespace std;
int getDegree()
{
int degree;
cout << "Enter degree of polynomial" << endl;
cin >> degree;
return degree;
}
int* getPoly(int degree)
{
cout << "Enter coefficients in order of power of x. e.g. for 2 + x + 3x^2, enter 2 then 1 then 3" << endl;
int coeff [degree +1];
for (int i = 0; i <= degree; i++)
{
cin >> coeff[i];
}
return coeff;
}
int* polyder(int p[], int degree)
{
int dp[degree];
for(int i = 0; i < degree; i++)
{
dp[i] = p[i+1] * (i+1);
}
return dp;
}
int main(int argc, const char * argv[])
{
int degree = getDegree();
int p = *getPoly(degree);
int dp = *polyder(&p, degree);
for(int i = 0; i < degree +1; i++)
cout << " " << p[i] << " x^" << i;
cout << endl;
for(int i = 0; i < degree +1; i++)
cout << " " << dp[i] << " x^" << i;
cout << endl;
return 0;
}
I am getting an error during the print statements.
I am not worried about the math involved, just how to pass the arrays between functions/methods.
Can anyone find why this is not working?
I am new to C++, used to Java.
Can anyone find why this is not working?
In C++ variables are destroyed when the scope in which they were declared ends. You return an address of a variable that doesn't exist when the function ends:
int* getPoly(int degree)
{
int coeff [degree +1];
// ...
return coeff;
}
If you wish the variable still exists after the function ends, you have to allocate it using new:
int* getPoly(int degree)
{
int *coeff = new int[degree +1];
// ...
return coeff;
}
And, at the end of your main function (or wherever you don't need the array anymore), call delete[] to deallocate the memory:
int *p = getPoly(degree);
delete[] p;
The Array name is essentially a pointer to the first element of the array (as you can see in the code above, I've declared p as a pointer to int), so you pass them to other functions just by providing their name:
int* polyder(int p[], int degree){/*do something here*/}
// <-- some other code
int *p = getPoly(degree);
int* returnedArray = polyder(p,degree);
First of all, the line
int coeff [degree +1];
is not a valid C++ statement unless 'degree' is a constant, even through some compilers may allow it.
Even if some compiler allowed it, the space for coeff is allocated from the stack and will be invalid after the function returns. Hence, the line
return coeff;
returns an memory location that will be invalid at its usage.
In order to return valid memory function, replace the line
int coeff [degree +1];
by
int* coeff = new int[degree];
You don't need degree+1 items in the array.
Similar changes are needed in the function polyder.
The thing to remember about arrays in C++ is that unlike Java, they are not objects (at least in the way they are in Java). They're simply pointers to a block of allocated memory, and the [] operator simply automatically does the math to move the pointer to the correct location.
When passing arrays between functions, you're basically just passing a pointer. Unless you want to get into some highly complicated and likely too much for your use case code, you should always pass the size of the array along with it to ensure that your indexes always stay in bounds.
And as the other answer points out, you need to ensure that the life cycle of the array lasts as long as you need it to. Simply returning a pointer to an object doesn't keep it alive like returning a reference does in Java.