I am trying to return an array from a function:
#include <iostream>
using namespace std;
int* uni(int *a,int *b)
{
int c[10];
int i=0;
while(a[i]!=-1)
{
c[i]=a[i];
i++;
}
for(;i<10;i++)
c[i]=b[i-5];
return c;
}
int main()
{
int a[10]={1,3,3,8,4,-1,-1,-1,-1,-1};
int b[5]={1,3,4,3,0};
int *c=uni(a,b);
for(int i=0;i<10;i++)
cout<<c[i]<<" ";
cout<<"\n";
return 0;
}
I pass two arrays from my main() into my uni() function. There I create a new array c[10] which I return to my main().
In my uni() function I try to merge the non-negative numbers in the two arrays a and b.
But I get something like this as my output.
1 -1078199700 134514080 -1078199656 -1216637148 134519488 134519297 134519488 8 -1078199700
Whereas when I try to print the values of c[10] in the uni() function it prints the correct values. Why does this happen??
Is this something related to the stack?? Because I have tried searching about this error of mine, and I found a few places on stackoverflow, where it says that do not allocate on stack but I couldn't understand it.
Further it would become very easy if I allocate my array globally, but if this is the case then everything shall be declared globally?? Why are we even worried about passing pointers from functions?? (I have a chapter in my book for passing pointers)
Admittedly, the std::vector or std::array approach would be the way to go.
However, just to round things out (and if this is a school project, where the teacher gives you the obligatory "you can't use STL"), the other alternative that will avoid pointer usage is to wrap the array inside a struct and return the instance of the struct.
#include <iostream>
using namespace std;
struct myArray
{
int array[10];
};
myArray uni(int *a,int *b)
{
myArray c;
int i=0;
while(a[i]!=-1)
{
c.array[i]=a[i];
i++;
}
for(;i<10;i++)
c.array[i]=b[i-5];
return c;
}
int main()
{
int a[10]={1,3,3,8,4,-1,-1,-1,-1,-1};
int b[5]={1,3,4,3,0};
myArray c = uni(a,b);
for(int i=0;i<10;i++)
cout << c.array[i] << " ";
cout << "\n";
return 0;
}
Note that the struct is returned by value, and this return value is assigned in main.
You have the value semantics of returning an instance, plus the struct will get copied, including the array that is internal within it.
Live Example
You're returning a pointer to a local object. In the uni function, the variable c is allocated on the stack. At the end of that function, all of that memory is released and in your for loop you are getting undefined results.
As suggested in the comments, std::array or std::vector will give you copy constructors that will allow you to return the object by value as you're trying to do. Otherwise you'll have to resort to something like passing your output array in as an argument.
You are returning a pointer to an array that is being deallocated at the return statement. It's a dangling pointer. It's UB.
Use an std::vector or std::array and return by value. There are compiler optimizations that will avoid inefficiencies.
Related
Say I have the following code:
#include <iostream>
using namespace std;
int defaultvalue[] = {1,2};
int fun(int * arg = defaultvalue)
{
arg[0] += 1;
return arg[0];
}
int main()
{
cout << fun() << endl;
cout << fun() << endl;
return 0;
}
and the result is:
2
3
which make sense because the pointer *arg manipulated the array defaultvalue. However, if I changed the code into:
#include <iostream>
using namespace std;
int defaultvalue[] = {1,2};
int fun(int arg[] = defaultvalue)
{
arg[0] += 1;
return arg[0];
}
int main()
{
cout << fun() << endl;
cout << fun() << endl;
return 0;
}
but the result is still:
2
3
Moreover, when I print out the defaultvalue:
cout << defaultvalue[0] <<endl;
It turn out to be 3.
My question is, in the second example, should the function parameter be passed by value, so that change of arg will have no effect on defaultvalue?
My question is, in the second example, should the function parameter be passed by value, so that change of arg will have no effect on defaultvalue?
No.
It is impossible to pass an array by value (thanks a lot, C!) so, as a "compromise" (read: design failure), int[] in a function parameter list actually means int*. So your two programs are identical. Even writing int[5] or int[24] or int[999] would actually mean int*. Ridiculous, isn't it?!
In C++ we prefer to use std::array for arrays: it's an array wrapper class, which has proper object semantics, including being copyable. You can pass those into a function by value just fine.
Indeed, std::array was primarily introduced for the very purpose of making these silly and surprising native array semantics obsolete.
When we declare a function like this
int func(int* arg);
or this
int (func(int arg[])
They're technically the same. It's a matter of expressiveness. In the first case, it's suggested by the API author that the function should receive a pointer to a single value; whereas in the second case, it suggests that it wants an array (of some unspecified length, possibly ending in nullptr, for instance).
You could've also written
int (func(int arg[3])
which would again be technically identical, only it would hint to the API user that they're supposed to pass in an int array of at least 3 elements. The compiler doesn't enforce any of these added modifiers in these cases.
If you wanted to copy the array into the function (in a non-hacked way), you would first create a copy of it in the calling code, and then pass that one onwards. Or, as a better alternative, use std::array (as suggested by #LightnessRacesinOrbit).
As others have explained, when you put
int arg[] as a function parameter, whatever is inside those brackets doesn't really matter (you could even do int arg[5234234] and it would still work] since it won't change the fact that it's still just a plain int * pointer.
If you really want to make sure a function takes an array[] , its best to pass it like
template<size_t size>
void func (const int (&in_arr)[size])
{
int modifyme_arr[100];
memcpy(modifyme_arr, in_arr, size);
//now you can work on your local copied array
}
int arr[100];
func(arr);
or if you want 100 elements exactly
void func (const int (&arr)[100])
{
}
func(arr);
These are the proper ways to pass a simple array, because it will give you the guaranty that what you are getting is an array, and not just a random int * pointer, which the function doesn't know the size of. Of course you can pass a "count" value, but what if you make a mistake and it's not the right one? then you get buffer overflow.
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 7 years ago.
#include<iostream>
using namespace std;
int *Arr(int y,int size){
int arg[size];
for(int i=size-1;i>=0;i--){
arg[i]=y%10;
y=y/10;
}
return arg;
}
int main(){
int *p=Arr(2587,4);
for(int j=0;j<4;j++){
cout<<p[j]<<" ";
}
return 0;
}
> Blockquote
I dont why this isn't working ...I'm trying to back an array but the problem is in the second digits.Can somebody help ;) thanks
The problem is you are putting your result into a local array that is destroyed when the function ends. You need to dynamicaly allocate the array so that its life-span is not limited to the function it was created in:
#include<iostream>
using namespace std;
int *Arr(int y, int size)
{
// This local array will be destroyed when the function ends
// int arg[size];
// Do this instead: allocate non-local memory
int* arg = new int[size];
for(int i = size - 1; i >= 0; i--)
{
arg[i] = y % 10;
y = y / 10;
}
return arg;
}
int main()
{
int *p = Arr(2587, 4);
for(int j = 0; j < 4; j++)
{
cout << p[j] << " ";
}
// You need to manually free the non-local memory
delete[] p; // free memory
return 0;
}
NOTE:
Allocating dynamic memory using new is to be avoided if possible. You may want to study up on smart pointers for managing it.
Also, in real C++ code, you would use a container like std::vector<int> rather than a builtin array
Of course it is not working.
At best, the behaviour is undefined, since Arg() is returning the address of a local variable (arg) that no longer exists for main(). main() uses that returned address when it is not the address of anything that exists as far as your program is concerned.
There is also the incidental problem that int arg[size], where size is not fixed at compile time, is not valid C++. Depending on how exacting your compiler is (some C++ compilers reject constructs that are not valid C++, but others accept extensions like this) your code will not even compile successfully.
To fix the problem, have your function return a std::vector<int> (vector is templated container defined in the standard header <vector>). Then all your function needs to do is add the values to a local vector, which CAN be returned safely by value to the caller.
If you do it right, you won't even need to use a pointer anywhere in your code.
I can't understand one weird thing. Here is my program :
#include <iostream>
using namespace std;
void Swap(int *a , int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int a=0;
int b=0;
cout<<"Please enter integer A: ";
cin>>a;
cout<<"Please enter integer B: ";
cin>>b;
cout<<endl;
cout<<"************Before Swap************\n";
cout<<"Value of A ="<<a<<endl;
cout<<"Value of B ="<<b<<endl;
Swap (&a , &b);
cout<<endl;
cout<<"************After Swap*************\n";
cout<<"Value of A ="<<a<<endl;
cout<<"Value of B ="<<b<<endl;
return 0;
}
Now if you look at the function "Swap", I have used "void Swap". Therefore it must not return any value to main function (only "int" returns a value (at least that's what my teacher has taught me)). But if you execute it, the values are swaped in main function! How come ? Can anyone tell me how its possible ?
Swap function in your example just swaps two integers, but does NOT return anything.
In order to check what function has retuned, you have to assign it to some variable, like this
int a = swap(&a, &b);
but this piece of code has an error because swap function doesn't return anything.
Another example:
int func() {
return 18;
}
int main() {
int a = func();
cout << a;
}
Is fine, cause variable a is int and function func returns an int.
Swap may not return any values, but it can still modify them. You're passing in pointers to two variables into the function. If you change the value the pointer maps to in the Swap function, that change persists throughout the program.
Actually, the function is NOT returning the value. It is just accessing the values through the variables' addresses and swapping them from their reference. Your code is right and now I have cleared your concept without any long explanation. That's all.
This is correct.
Your Swap method does work with pointers, not real values.
In your main your are calling this method and tell it to swap the values in the variables. They are in the sme context at this point.
Your code looks very similar to this:
http://www.tutorialspoint.com/cplusplus/cpp_function_call_by_pointer.htm
What it does it uses pointers addresses. You use them as parameters and then you use them to access the information stored at that location, which is the values of a and b, and then change them.
I think you are misunderstand what your teacher said.
What he/she said might be Swap() will not return value, but change value by passing address is still valid.
like this:
int Swap();
int GetReturnValue = Swap(); // Get return value from Swap()
Let's look the second one:
void Swap();
int GetReturnValue = Swap();
Though the second one might really get value, but this value is meaningless.
Sometimes, you will get a compiler warning if you do like the second one, GCC Compiler will report warnings about casting
Swap procedure can only modify your variables because you've passed them by reference.
Remember procedures, unlike functions, cannot return a value.
I am a bit confused. There are two ways to return an array from a method. The first suggests the following:
typedef int arrT[10];
arrT *func(int i);
However, how do I capture the return which is an int (*)[]?
Another way is through a reference or pointer:
int (*func(int i)[10];
or
int (&func(int i)[10];
The return types are either int (*)[] or int (&)[].
The trouble I am having is how I can assign a variable to accept the point and I continue to get errors such as:
can't convert int* to int (*)[]
Any idea what I am doing wrong or what is lacking in my knowledge?
If you want to return an array by value, put it in a structure.
The Standard committee already did that, and thus you can use std::array<int,10>.
std::array<int,10> func(int i);
std::array<int,10> x = func(77);
This makes it very straightforward to return by reference also:
std::array<int,10>& func2(int i);
std::array<int,10>& y = func2(5);
First, the information you give is incorrect.
You write,
“There are two ways to return an array from a method”
and then you give as examples of the ways
typedef int arrT[10];
arrT *func(int i);
and
int (*func(int i))[10];
(I’ve added the missing right parenthesis), where you say that this latter way, in contrast to the first, is an example of
“through a reference or pointer”
Well, these two declarations mean exactly the same, to wit:
typedef int A[10];
A* fp1( int i ) { return 0; }
int (*fp2( int i ))[10] { return 0; }
int main()
{
int (*p1)[10] = fp1( 100 );
int (*p2)[10] = fp2( 200 );
}
In both cases a pointer to the array is returned, and this pointer is typed as "pointer to array". Dereferencing that pointer yields the array itself, which decays to a pointer to itself again, but now typed as "pointer to item". It’s a pointer to the first item of the array. At the machine code level these two pointers are, in practice, exactly the same. Coming from a Pascal background that confused me for a long time, but the upshot is, since it’s generally impractical to carry the array size along in the type (which precludes dealing with arrays of different runtime sizes), most array handling code deals with the pointer-to-first-item instead of the pointer-to-the-whole-array.
I.e., normally such a low level C language like function would be declared as just
int* func()
return a pointer to the first item of an array of size established at run time.
Now, if you want to return an array by value then you have two choices:
Returning a fixed size array by value: put it in a struct.
The standard already provides a templated class that does this, std::array.
Returning a variable size array by value: use a class that deals with copying.
The standard already provides a templated class that does this, std::vector.
For example,
#include <vector>
using namespace std;
vector<int> foo() { return vector<int>( 10 ); }
int main()
{
vector<int> const v = foo();
// ...
}
This is the most general. Using std::array is more of an optimization for special cases. As a beginner, keep in mind Donald Knuth’s advice: “Premature optimization is the root of all evil.” I.e., just use std::vector unless there is a really really good reason to use std::array.
using arrT10 = int[10]; // Or you can use typedef if you want
arrT10 * func(int i)
{
arrT10 a10;
return &a10;
// int a[10];
// return a; // ERROR: can't convert int* to int (*)[]
}
This will give you a warning because func returns an address of a local variable so we should NEVER code like this but I'm sure this code can help you.
I am trying to make a c++ program with a class which holds integers on the "heap" and has only one method, pop() which returns the first item in the class and removes it. This is my code so far:
#include <iostream>
using namespace std;
class LinkList {
int *values; //pointer to integers stored in linklist
int number; // number of values stored in linklist
public:
LinkList(const int*, int); // Constructor (method declaration)
int pop(); // typically remove item from data structure (method declaration)
};
LinkList::LinkList(const int *v, int n){
number = n;
*values = *v;
int mypointer = 1;
while (mypointer<n) {
*(values+mypointer) = *(v+mypointer);
mypointer++;
}
}
int LinkList::pop() {
if (number>0) {
int returnme = *values; //get the first integer in the linklist
number--;
values++; //move values to next address
return returnme;
}
else {return -1;}
}
int main() {
int test[] = {1,2,3,4,5};
LinkList l1(test,5);
cout << l1.pop() << endl;
LinkList l2(test,5);
cout << l2.pop() << endl;
return 0;
}
The issue is that its failing at the line *values = *v, if i remove the 4th and 5th lines from the main method, I no longer get this issue, so its go to be a memory management thing.
What I want to do is to get values to point to a continuous bit of memory with integers in. I have tried to use arrays for this but keep just getting random memory addresses returned by pop()
Background: normal I programming in java, I've only be using C/C++ for 2 months, I'm using eclipse IDE in ubuntu, I can make very basic use of the debugger but currently I dont have functioning scroll bars in eclipse so I can't do somethings if they dont fit on my screen.
You are dereferencing an uninitialized pointer (values) at the line *values = *v; which is undefined behavior (UB). What this line says is "get the integer that values points to and assign to it the value pointed by v". The problem with this logic is that values doesn't yet point to anything. The result of this UB is the crash that you receive.
There are many other problems with this code, such as passing a const int* to the constructor with the intent of modifying those values. The biggest problem is that this is not an actual linked list.
*values = *v;
You dereference the values pointer in this line before initializing it. This is the source of the later errors, and the non-errors in the first three lines of main are simply due to luck. You have to allocate space via values = new int[n] and deallocate it in the destructor via delete[] values. std::vector does this work in a clean and exception-safe way for you.
Perhaps the problem is that you're incrementing an integer - mypointer, rather than a a pointer. If the integer requires more than one byte of space, then this might lead to errors. Could you try declaring a pointer and incrementing that instead?
The values member variable is a pointer to uninitialized memory. Before you start copying numbers into it you have to point it to valid memory. For example:
LinkList::LinkList(const int *v, int n){
number = n;
values = new int[n]; // allocate memory
int mypointer = 0;
while (mypointer<n) {
*(values+mypointer) = *(v+mypointer);
mypointer++;
}
}
LinkList::~LinkList() {
delete values; // release memory
}
Also, why do you call this a linked list while in fact you are using a memory array to store your numbers?