C++ returning array and display it - c++

i would like to ask, why this code doesnt work...
int* funkce(){
int array[] = {1,2,3,4,5};
return(array);
}
int main(){
int* pp = funkce();
int* ppk = pp+5;
for (int *i = pp; i!=ppk; i++){
cout << (*i) << endl;
}
system("PAUSE");
return(0);
}
This code display:
1
16989655
4651388
- // -
253936048
So the poniter is out of array...
But how is possible, that this code with array in Main is ok?
int main(){
int a[] = {1,2,3,4,5};
int* pp = a;
int* ppk = pp+5;
for (int *i = pp; i!=ppk; i++){
cout << (*i) << endl;
}
system("PAUSE");
return(0);
}
this code displayed:
1
2
3
4
5
Could you explain to me, why the first one doesnt work?
Thank you!

You're returning a pointer to a temporary which goes out of scope when the function ends. If you want to have a function return an array, you need to do one of:
std::array<int, 5> func() {
// stack-allocated
std::array<int, 5> a = {1, 2, 3, 4, 5};
return a;
}
std::vector<int> func() {
// heap-allocated
std::vector<int> a = {1, 2, 3, 4, 5};
return a;
}
int* func() {
// heap-allocated, you have to remember to delete it
int* a = new int[5]{1, 2, 3, 4, 5};
return a;
}
etc. There's more options, but this should give you a good start.

Never return a local a pointer/reference to a variable, that memory is freed/re-used on return.
Using that dangling reference is Undefined Behavior and has unpredictable consequences.
Return an object, a pointer to heap-allocated memory, or save into a caller-supplied buffer.

Related

The increment of a pointer does not work. It's quite hard for me to understand what's what

I have recently learned some basics of pointers in C++. So I understand that an array's name is just simply a pointer set to the first position of the array by default. And I do not really comprehend why the first code works just fine whereas the second code shows an error on the line: tab = tab+1;
Could you explain to me why it's so ambiguous?
#include <iostream>
int main()
{
int *tab;
tab = new int[5] {0, 1, 2, 3, 4};
for(int i=0; i<5; i++)
{
std::cout << *tab << std::endl;
tab++;
}
delete []tab;
}
#include <iostream>
int main()
{
int tab[5] = {0, 1, 2, 3, 4};
for(int i=0; i<5; i++)
{
std::cout << *tab << std::endl;
tab = tab+1; // ERROR
}
}
The first code "works" because tab is declared as an actual pointer, and you can assign another pointer to it. But the code also fails, because it has undefined behavior due to tab no longer pointing at the original memory returned by new[] when delete[] is called.
The second code does not work because tab is declared as an array, not a pointer. It decays into a pointer when needed, but you can't assign a pointer to an array.
So I understand that an array's name is just simply a pointer set to the first position of it by default.
No. That is wrong. Arrays are not pointers and pointers are not arrays.
Because arrays can decay to the address of its first elements you can write int* tab_ptr = tab; to get a pointer to the first element:
#include <iostream>
int main()
{
int tab[5] = {0, 1, 2, 3, 4};
int* tab_ptr = tab;
for(int i=0; i<5; i++)
{
std::cout << *tab_ptr << std::endl;
tab_ptr = tab_ptr+1;
}
}
And because arrays do decay to the address of its first element when passed to functions you can also do this:
#include <iostream>
void foo(int t[]){
for(int i=0; i<5; i++)
{
std::cout << *t << std::endl;
t = t+1;
}
}
int main()
{
int tab[5] = {0, 1, 2, 3, 4};
foo(tab);
}
When you write tab = tab+1 you get the error:
<source>:23:13: error: incompatible types in assignment of 'int*' to 'int [5]'
23 | tab = tab+1;
| ~~~~^~~~~~~
because the array does decay to an address in tab+1, and tab+1 is a pointer, but you cannot assign the resulting pointer to the array tab.
The first version does not have this problem, because there tab is indeed a pointer to a dynamic array.

How to reassign an array to another array?

Is it possible to reassign an array to another array? Like this:
This is the function e02:
void e02(){
int a[] = {15, 9, 8, 4, 3};
int n = 5;
int x = 5;
fn02(a, n, x);
cout << endl;
for(int i = 0; i < n; i++){
cout << a[i] << " ";
}
}
And this is the function fn02:
void fn02(int* a, int &n, int x){
n += 1;
int* b = new int[n];
int j = 0;
bool put = false;
for(int i = 0; i < n; i++){
if(x > a[i] && put == false){
b[j] = x;
j++;
a--;
put = true;
} else{
b[j] = a[i];
j++;
} //else
} //i loop
a = b;
}
This is supposed to put the variable n into the array but the array still needs to be descending. If I just assign a = b like this then I get the output 15, 9, 8, 4, 3, 5 with 5 being a garbage value. So my question is: Is there a way to reassign an array to a different array like here?
If I use a pointer like
int* &p1;
and then put it in the function I get what I want but the function has to have those parameters and has to be void
I will provide some concepts that will potentially help you derive a solution to your problem. Then provide a quick solution that can help you with your final solution.
...If I just assign a = b like this then I get the output 15, 9, 8, 4, 3, 5 with 5 being a garbage value.
The output of the number 5 has nothing to do with your assignment of a=b in fcn02. The value 5 is actually the value of x in the calling function. You are accessing the array outside the bounds of it's original allocation thus accessing the value of next address of the size of int. In this case it's the value of x. if you spit out the address of x and the address of a[6] you will see that they are equal.
Your assignment in fcn02 of a=b does not work as you intended due to the fundamental concept of passing values to a function. When you call the function fcn02(a) the value "a" (the address of the beginning of the array) is copied to the value of "a" in fcn02. Changing "a" in fcn02 does not change "a" in the calling function.
Example for clarification NOTE( Using the same value "a" can be confusing so I changed it a bit).:
int func02( int* b ) // address of a is copied to b
{
... // some code...c is dynamically allocated and has an address of 0x80004d30
b = c; // b is set to address of c; thus, b address is now 0x80004d30
// a is unchanged and you now have a memory leak since you didn't delete b.
}
int main()
{
int a[5] = {1,2,3,4}; // address is 0x28cc58
func02(a); // complier will make a copy of the value of a to b
// address (i.e. value) of a is still 0x28cc58
}
Memory layout of why you see 5:
int a[5] = {1,2,3,4,5}; // 0x28cc64
int x = 7; // 0x28cc5c
{ array a }{ x }
---- ---- ---- ---- ---- ----
| 1 | 2 | 3 | 4 | 5 | 7 |
---- ---- ---- ---- ---- ----
However to answer you question you can NOT assign one array to another.
int a[5] = {1,2,3,4,5};
int b[5];
b = a;
for ( int i = 0; i<5; ++i )
{
cout << b[i] << endl;
}
The compiler will not allow this.
Here is quick and dirty solution keeping your function parameters the same for guidance:
void e02(){
int a[6] = {15, 9, 8, 4, 3, 0};
int sizeofA = 5;
int numToAdd = 5;
fn02(a, sizeofA, numToAdd);
cout << endl;
for(int i = 0; i < n; i++){
cout << a[i] << " ";
}
}
void fn02(int* a, int &n, int x){
n += 1;
int i = 0;
while( i < n )
{
if ( a[i] > x )
++i;
else {
int tmp = a[i];
a[i] = x;
x = tmp;
}
}
}
In order to insert an element in a sorted vector (decreasing order), you could try this:
#include <iostream>
#include <vector>
using namespace std;
void InsertItemInSortedArray(std::vector<int>& vec, int item)
{
auto high_pos=std::lower_bound (vec.rbegin(), vec.rend(), item);
vec.insert(high_pos.base(), item);
}
int main() {
std::vector<int> vec = {15, 9, 8, 4, 3};
int item = 5;
InsertItemInSortedArray(vec, item);
for (const auto& elem : vec)
{
std::cout << elem << std::endl;
}
return 0;
}
It is so simple you need just to do *arraya=*arrab;

How do I stop my array from printing address?

I have a header, cpp and main class.
//Arr.h
class Arr
{
public:
void setArr();
void printArr();
private:
int x[5];
};
//Arr.cpp
#include "Arr.h"
#include <iostream>
using namespace std;
void Arr::setArr()
{
int x[5] = { 2, 3, 5, 7, 11 };
}
void Arr::printArr()
{
for (int i = 0; i < 5; i++)
{
cout << x[i] << "\n";
}
}
//main.cpp
int main()
{
Arr a;
a.setArr();
a.printArr();
}
However, when I run the code, a.printArr() prints out array address and not the values contained in the array. Is there a way to fix this?
Your code will print not address but some indeterminate value generated via default-initializing. Initialize the member array instead of the local array to throw away.
void Arr::setArr()
{
x[0] = 2;
x[1] = 3;
x[2] = 5;
x[3] = 7;
x[4] = 11;
}
Your problem is here:
void Arr::setArr()
{
int x[5] = { 2, 3, 5, 7, 11 };
}
the declaration int x[5] defines a new array of 5 elements which will be destroyed on exiting that function; and the name x hides the data member Arr::x.
One way you can do it is this:
void Arr::setArr()
{
/*static*/ auto arr = { 2, 3, 5, 7, 11 };
std::copy(arr.begin(), arr.end(), x);
}
Full code:
#include <iostream>
#include <algorithm>
class Arr
{
public:
void setArr();
void printArr();
private:
int x[5];
};
using namespace std;
void Arr::setArr()
{
/*static*/ auto arr = { 2, 3, 5, 7, 11 };
std::copy(arr.begin(), arr.end(), x);
}
void Arr::printArr()
{
for (int i = 0; i < 5; i++)
{
cout << x[i] << "\n";
}
}
//main.cpp
int main()
{
Arr a;
a.setArr();
a.printArr();
}
Your code is not printing array address. Maybe you saw some unexpected numbers and assumed it was an address, but in fact it is undefined behaviour caused by outputting uninitialized variables.
Your code int x[5] = .... failed because this declares a new local variable x, it doesn't modify the class member x.
Perhaps you tried:
x = { 2, 3, 5, 7, 11 };
and got compilation errors. This is because C-style arrays may not be assigned. This annoying rule is a hangover from C++'s past. To avoid this problem and many others, you can try to avoid using C-style arrays. In this case use a C++ array:
private:
std::array<int, 5> x;
Then the suggested assignment will work.
As WhiZTiM has already pointed out, your problem is at the setArr function in your class. The reason for this is because in C++ you cannot assign values to the array in the "normal fashion" i.e. using x = {blah, blah, blah}; (unless you use std::array<int, ARRAYSIZE>). In setArr you are creating another array named x and then this array is deleted once it is out of scope, and in printArr you are printing an array with no values in it yet.
Each value in the array must be set individually in C styled arrays (as shown in MikeCAT's answer).
One solution to this is to create a temporary array with the values you want and assigning the values to your class array through a for loop, i.e.:
void Arr::setArr() {
const int ARRAYSIZE = 5;
int tmp[ARRAYSIZE] = {2, 3, 5, 7, 11};
for (int i = 0; i < ARRAYSIZE; ++i) {
x[i] = tmp[i];
}
}
As M.M also pointed out, can simply change int x[5] in your private variables in Arr to std::array<int, 5> x and then in setArr simply have the statement: x = {2, 3, 5, 7, 11}; which is the better option in my opinion and easier to read, but it's also good to know how to use C arrays 😊

C++: Change value of variable using its pointer

Let's say I have the following funciton:
void part(T* arr){
//some function
int x[5] = {1,2,3,4,5};
arr = x;
}
where original:
int arr[5] = {0,0,0,0,0}
I would like to know, how can I change the value of original arr inside the function to be some other value (lets say x)?
Thanks
To achieve this, you would need to copy elements from the array x to arr:
std::copy(x, x + sizeof(x) / sizeof(x[0]), arr);
However, as a general advice, don't use raw pointers to represent an array of objects. You could use std::array instead and then you can use it's operator= to copy all elements.
#include <iostream>
#include <array>
void part(std::array<int, 5>& arr)
{
std::array<int, 5> x {{1, 2, 3, 4, 5}};
arr = x;
}
int main()
{
std::array<int, 5> arr;
part(arr);
for (const auto& val : arr) {
std::cout << val << " ";
}
}
LIVE
You were close.
void part(T* arr){
//some function
int x = 5;
*arr = x;
}
You just need to add a * in front of arr which means the value pointed to by that pointer. If you just say arr that means the actual address which you do not want to be changing.
Looks like you changed the question while I was writing my answer.
In this case you need a loop.
void part(T* arr){
//some function
int x[5] = {1,2,3,4,5};
for(int i = 0; i < 5; i++)
{
arr[i] = x[i];
}
}

Passing a reference to an offset position in an STL vector

I'm trying to convert some old C functions to C++. My original programme stores a matrix in a single array, and I just pass a pointer to the first element to a function so that I am working on the correct row, e.g.
double f1(int *a){
return a[0] + a[1];
}
int main(void){
int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for(i = 0; i < 5; i++){
printf("%d\n", f1(&x[2 * i]));
}
I would like to be able to do something similar using the STL without copying. So my programme would look something like this
double f1(vector<int>& a){
return a[0] + a[1];
}
int main(void){
int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> y(x, x + 10);
for(i = 0; i < 5; i++){
cout << f1(y) << endl; // This is clearly wrong
}
How would I do this? I could change my function to receive a reference to a vector::iterator I guess, but is there another way?
You could simply pass an iterator to the function. Random access iterators are very similar to pointers (in fact, pointers qualify as random access iterators.) For example,
#include <vector>
double f1(std::vector<int>::const_iterator a)
{
return a[0] + a[1];
}
#include <iostream>
int main()
{
vector<int> y{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto it = y.cbegin();
for(int i = 0; i < y.size()/2; ++i)
std::cout << f1(it + 2*i) <<std::endl;
}
Write array view. An array view is a pair of pointers with begin end size empty, operator[], front and back methods, and constructors from C arrays, std::array<T,N>&, std::vector<T,A>&, std::vector<non_const_T,A>const&, std::array<non_const_T,N>const&, std::initializer_list<non_const_T>, etc.
Oh, and T*,size_t and T*,T* ctors, which are great for slicing (use forwarding ctors: T*,size_t->T*,T*, and everything else to those 2).
It does not own its data, so all of its methods are const except operator=. (non-const methods would be methods that change the view range -- changing the elements is a const operation on a view).
Then
double f1(array_view<const int> a){
return a[0] + a[1];
}
You don't need to make so many changes:
double f1(int *a)
{
return a[0] + a[1];
}
int main(void)
{
vector<int> y = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i = 0; i < 5; i++) {
cout << f1(&y[2 * i]) << endl;
}
}