passing array from one function to the other [duplicate] - c++

This question already has answers here:
Returning a reference to a local variable in C++
(3 answers)
Closed 7 years ago.
I think I've got my self confused by following codes. Suppose I have two simple functions:
int* makeiniele()
{
int res[55] = { 0 };
return res;
}
and
void printele(int* wxyz)
{
for (int k = 0; k < 55; k++)
{
cout << wxyz[k] << "\n";
}
}
The problem is when I run the following line:
printele(makeiniele());
I get 55 big negative numbers instead of 55 zeros!
Thank you for your time

Two issues:
1) The array is not initialized to contain 55 zeros, but only 1, remaining 54 elements are going to be some older memory content:
int res[55] = { 0 };
you need to use the memset() function in order to do that efficiently:
int res[55];
memset(res, 0, sizeof(res));
2) The array you declare in the makeiniele() function will be deallocated after returning from the function and (since it was living on the stack) its content is going to be overwritten by the call of next function printele(). Therefore, initializing it correctly won't fix your problems.
A solution would be to consider using malloc() to allocate the array instead. Your makeiniele() function should look like this:
int* makeiniele(){
int *res = malloc(sizeof(int)*55));
memset(res, 0, sizeof(int)*55);
return res;
}
And remember to call free() after you have finished with the array in order to avoid memory leaks.

int* makeiniele()
{
int res[55] = { 0 };
return res;
}
The problem here lies with scope - once a function ends, any variables declared within the function are deleted from memory. Once the function makeiniele terminates, the array res is also deleted from memory. The memory that array took up has been replaced with something else - this 'something else' is what's being printed to your screen. You can verify this with the following code:
int * myvar = new int[55]{ 0 };
int* var = myvar;
printele(var);
delete myvar;
printele(var);
The fist 55 numbers will be zeroes (the variable hasn't been deleted yet). Once the variable is manually deleted with delete the address of it is now pointing to unused memory, so it spits out random numbers. To fix this, replace your makeiniele funciton with this:
int* makeiniele()
{
int * myvar = new int[55]{ 0 };
return myvar;
}
And everything should work fine!
EDIT: As Zereges said, you MUST ensure to end your program with
delete myvar;
to prevent a memory leak.

A little modern C++ answer.
Either using clever array (std::vector)
std::vector<int> makeiniele()
{
std::vector<int> res(55, 0);
return std::move(res);
}
void printele(const std::vector<int>& wxyz)
{
for (int k = 0; k < 55; k++)
{
cout << wxyz[k] << "\n";
}
}
Or using clever pointers (std::shared_ptr)
std::shared_ptr<int> makeiniele()
{
std::shared_ptr<int> res(new int[55]);
std::memset(res.get(), 0, 55 * sizeof(int));
return std::move(res);
}
void printele(std::shared_ptr<int> wxyz)
{
for (int k = 0; k < 55; k++)
{
std::cout << wxyz.get()[k] << "\n";
}
}

Related

Using pointer variables to print specific array variables

I am a C++ beginner and my task is as follows:
Define and initialise a single-dimensional integer array. Next, define a pointer that points to the first element in the array and passes the pointer to a function.
Using only pointer variables (and looping constructs), print only the array values that are exact multiples of 7 from start to finish to standard output. The only program output should be the numbers, one per line with no white space.
I have tried:
void print_sevens(int* nums, int length)
{
int array[5] = { 5,8,21,43,70 };
int* ptr = array;
int* num = array;
for (int i = 0; i < length; i++)
{
*num++;
if (num[i] % 7 == 0) {
cout << num[i] << endl;
}
}
}
int main()
{
int array[5] = { 5,8,21,43,70 };
int* ptr = array;
print_sevens(ptr, 5);
}
It compiles but does not output anything.
I am also confused about passing the pointer to a function. Should this be done in the main file or in the function file?
You are creating an additional array in the print_sevens function, which is unnecessary as you already passed the pointer to the first element of the array created in the main()(i.e. array).
Removing that unnecessary array and related codes from the function will make the program run perfectly. (See online)
void print_sevens(int* nums, int length)
{
for (int i = 0; i < length; i++)
{
if (nums[i] % 7 == 0)
std::cout << nums[i] << std::endl;
}
}
and in the main you only need to do the follows, as arrays decay to the pointer pointing to its first element.
int main()
{
int array[5]{ 5,8,21,43,70 };
print_sevens(array, 5);
}
Note that,
num++ increments the pointer, not the underline element it is
pointing to (due to the higher operator precedence of operator++ than operator*). If you meant to increment the element(pointee) you
should have (*num)++.
Secondly, do not practice with using namespace std;. Read more:
Why is "using namespace std;" considered bad practice?
You are modifying the contents of your array when you do *num++.

Deleting template pointer in array of undetermined size causes SIGABRT

template <class T>
class Vector {
int pos = 0;
int chunkSize;
T** p = new T*;
public:
Vector(int chunkSize = 1000) {
this->chunkSize = chunkSize;
p[0] = new T[chunkSize];
std::cout << &p[0] << std::endl;
}
~Vector() {
for (int i = 0; i < pos / chunkSize; i++) {
std::cout << &p[i] << std::endl;
delete [] p[i];
}
}
void pushBack(T val);
void display();
};
template<class T>
void Vector<T>::pushBack(T val) {
p[pos / chunkSize][pos % chunkSize] = val;
if (++pos % chunkSize == 0)
p[pos / chunkSize] = new T[chunkSize];
}
template<class T>
void Vector<T>::display() {
for (int i = 0; i < pos; i++)
std::cout << p[i / chunkSize][i % chunkSize] << " ";
std::cout << std::endl;
}
I was tinkering with some code today, and came up with the above. What I am trying to do is create something resembling a vector, by using fixed sized arrays, and just creating more as I need.
I usually program in Java, so memory management isn't my forte, and I am not sure that what I am doing is entirely okay. The vector is created fine, and I can add any number of values to it just fine. I can also display them, without issue, using the display function above. However, the destructor throws a SIGABRT when trying to delete any element, and that is why I am here, I don't know why I can't free memory I have allocated and have access to, although I guess one possibility is that I am writing and reading from memory I should not have access to. Those two cout statements print the same address for the 0th element, which I used to check that I was consistently looking at the same memory address.
Could someone explain to me either how to delete the elements properly, or why what I am doing is a huge mistake?
EDIT: The main class calls this code as follows.
int main() {
Vector<int> vec;
for (int i = 0; i < 1000000; i++)
vec.pushBack(i);
vec.display();
return 0;
}
The problem is that you only allocate space for one T* and store that in your p pointer. Once you push back chunksize elements, you write to p[1], which (since it past the end of the memory allocated for it) results in Undefined Behavior. Which includes running on apparently working for quite some time before it blows up.
You'll need to allocate additional space in the p array whenever you need to access additional elements there.

How do I set an array to a new array?

I need to implement a function that modifies an array. The new array may be a different size. cout prints 1. I understand what's wrong with this code but I just cannot figure out what the syntax is.
//tried this..
int reduce(int *array[])
{
*array = new int[1];
(*array)[0] = 6;
return 0;
}
//also tried this..
int reduce(int array[])
{
array = new int [1];
array[0] = 6;
return 0;
}
int main()
{
int a[1] = {1};
int *p = a;
reduce(&p);
cout << a[0];
return 0;
}
Don't understand your question correctly, but this is what you may do:
void reduce(int *a, int size)
{
for (int i =0; i < size; ++i) {
*(a+i) = 6; // or whatever value to want to
}
}
Call it this way:
int main(){
int a[5] = {1, 1, 1, 1, 1};
int *p = a;
reduce(p, 5);
for (int i =0; i < 5; ++i) { cout << a[i]<<endl; }
return 0;
}
EDIT
What you are trying to do can be vaguely done this way:
int * reduce (int **b, int size) {
*b = new int[size];
for (int i =0; i < size; ++i) {
*(*b + i) = 6;
}
return *b;
}
int main(){
int a[5] = {1, 1, 1, 1, 1};
int *p = a;
p = reduce(&p, 5);
cout << p[0];
cout << p[1];
cout << p[2];
cout << p[3];
cout << p[4];
delete [] p;
return 0;
}
But it still wont change where a is pointing to.
What you are trying to do is not possible with statically defined arrays.
When you use an array like
int a[1] = {1};
you cannot change the size of the array at run time, you cannot make it point to dynamically allocated memory. You may only access and modify the elements the array. That's it.
The function reduce changes where p points to but it does not change the elements of a.
If you want to modify the contents of a, you can simply use a as an argument, and set the values.
MODIFIED:
You want to modify array a, try this :
int reduce(int **array)
{
*array = new int[1];
(*array)[0] = 6;
return 0;
}
int main()
{
int *a = new int[1];
reduce(&a);
cout << a[0];
return 0;
}
First of all, the formal parameter int* array[] actually is the same as int** array (you can think of it as a two-dimensional array). This is probably not what you want.
The answer of #everettjf will only work if you do not change the size of the array. A possible solution (that completely replaces the array) would be
#include <iostream>
void print_array(int[],int);
int* reduce(int array[]) {
// get rid of the old array
delete[] array;
// create a new one
array = new int[7]{8,4,6,19,3,56,23};
// need to return the new address, so that
// the main function is informed on the new
// address
return array;
}
int main() {
// initialize array
int *a = new int[1]{4};
print_array(a,1);
// "change" array by completely replacing it
a=reduce(a);
print_array(a,7);
return 0;
}
// simply prints out the array; no error checking!
void print_array(int array[], int length) {
std::cout << "[";
for (int i = 0; i < length ; ++i) {
std::cout << array[i] << " ";
}
std::cout << "]" << std::endl;
}
In the reduce function, the initial array is completely deleted. Afterwards, you can create a new one (I chose to just use 7 random numbers). It is important to return that pointer back to the caller (the main method). Otherwise the a pointer in the main method would point to invalid
If you are not forced (by some kind of excercise, for example) to use arrays, you should look into http://en.cppreference.com/w/cpp/container/vector
The premise of your question is invalid. It is not possible to resize an array of automatic storage duration (aka a in main()) after its definition by ANY means in standard C++.
Dynamic memory allocations in either of your reduce() functions will not cause a in main() to be resized.
reduce(&p) will calls the first version of reduce() , which will then change p (so it points at the dynamically allocated memory) but not affect a.
If main() calls reduce(a) or reduce(p) (the two are equivalent, given the initialisation int *p = a) will change neither a nor p, but instead cause a memory leak.
The underlying problem, I suspect, is that you believe - incorrectly - that pointers and arrays are the same thing. They are actually different things, but can be used in the same way in various contexts. And your code is one of the contexts in which they cannot be used interchangeably.
If you want a resizeable array, use a static container (like std::vector<int>) and - if you want a function to resize it, pass it by reference. It manages its own memory dynamically, so is able to dynamically resize itself.

C++: The value that the pointer is pointing to changes

I am trying to code a class that represents a set of integers. It's a homework assignment but for the life of me I cannot figure out this issue.
In the class "IntSet", I have two private variables; one is a pointer to an array the other is the size of the array. I can create objects of this class and they work as intended. But I have this function named "join" that returns an object of the IntSet class. It essentially concatenates the arrays together then uses that array to create the returning object.
Here is my code:
#include <iostream>
using namespace std;
class IntSet {
int * arrPtr;
int arrSize;
public:
//Default Constructor
IntSet() {
int arr[0];
arrPtr = arr;
arrSize = 0;
}
//Overloaded Constructor
IntSet(int arr[], int size) {
arrPtr = arr;
arrSize = size;
}
//Copy Constructor
IntSet(const IntSet &i) {
arrPtr = i.arrPtr;
arrSize = i.arrSize;
}
/*
* Returns a pointer to the first
* element in the array
*/
int* getArr() {
return arrPtr;
}
int getSize() {
return arrSize;
}
IntSet join(IntSet &setAdd) {
//Make a new array
int temp[arrSize + setAdd.getSize()];
//Add the the values from the current instance's array pointer
//to the beginning of the temp array
for (int i = 0; i < arrSize; i++) {
temp[i] = *(arrPtr + i);
}
//Add the values from the passed in object's array pointer
//to the temp array but after the previously added values
for (int i = 0; i < setAdd.getSize(); i++) {
temp[i + arrSize] = *(setAdd.getArr() + i);
}
//Create a new instance that takes the temp array pointer and the
//size of the temp array
IntSet i(temp, arrSize + setAdd.getSize());
//Showing that the instance before it passes works as expected
cout << "In join function:" << endl;
for (int j = 0; j < i.getSize(); j++) {
cout << *(i.getArr() + j) << endl;
}
//Return the object
return i;
}
};
int main() {
//Make two arrays
int arr1[2] = {2 ,4};
int arr2[3] = {5, 2, 7};
//Make two objects normally
IntSet i(arr1, 2);
IntSet j(arr2, 3);
//This object has an "array" that has arr1 and arr2 concatenated, essentially
//I use the copy constructor here but the issue still occurs if I instead use
//Inset k = i.join(j);
IntSet k(i.join(j));
//Shows the error. It is not the same values as it was before it was returned
cout << "In main function:" << endl;
for (int l = 0; l < k.getSize(); l++) {
cout << *(k.getArr() + l) << endl;
}
return 0;
}
The program compiles and the output as of now is:
In join function:
2
4
5
2
7
In main function:
10
0
-2020743083
32737
-2017308032
I don't know why but the 10 and 0 are always the same every time I recompile and run. Also, if I print out the address of the pointer rather than the value(in both the join function and the main function), I get the same memory address.
Sorry if I misuse terms, I come from a java background, so pointers and such are a little new to me. If any clarification is needed, please ask.
Thanks in advance.
int temp[arrSize + setAdd.getSize()];
This is a local array, its lifetime ends once the function returned.
IntSet i(temp, arrSize + setAdd.getSize());
Here you are constructing an IntSet with this array. In fact the constructor simply changes a member pointer to the value of temp:
IntSet(int arr[], int size) {
arrPtr = arr;
arrSize = size;
}
As a result, since the lifetime of the object that temp and consequently also i.arrPtr is pointing to ends after leaving join, you will have a wild pointer. Dereferencing this pointer later in main invokes undefined behavior.
You need to allocate the array dynamically with new[] and delete it later with delete[]. The same goes for your constructors. Also note that if you use new[] in join and delete[] in the destructor, then you also have to make sure that the copy constructor actually copies the array (create new array with new[] and copy contents). If you simply assign the pointer then both the source and destination object will point to the same array and they will also both try to delete it at deconstruction, again invoking undefined behaviour.
But since this C++, you might as well use a std::vector which does all of this for you. (or std::set if you actually want a integer set)
The quickest fix with your code is to change
int temp[arrSize + setAdd.getSize()];
into this
int * temp = new int[arrSize + setAdd.getSize()];
The thing is that you allocated temp on the stack, so when join() returns that memory is releases. By allocating memory on the heap (as per the fix) the memory is not released when join() returns.
There are other things wrong with your code -- depending on the point of the assignment. I think most of these will be fixed when you consider the implications of having memory on the heap.

How to store pointers to statically allocated objects in a vector?

Lets say I wanted to make a vector of objects and another vector of pointers to those objects (I cannot use dynamic memory). The way I would do it is in the following example.
#include <iostream>
#include <vector>
using namespace std;
class Foo {
public:
int bar;
Foo(int x) : bar(x) {
}
};
int main () {
vector<Foo> foos;
vector<Foo*> pFoos;
for (int i = 0; i < 10; i++) {
Foo foo(i);
foos.push_back(foo);
pFoos.push_back(&foos.back());
}
for (int i = 0; i < 10; i++) {
cout << foos[i].bar << endl;
cout << pFoos[i]->bar << endl;
}
}
I think this should work because foos stores a copy of the object, and then I store the reference to the copy (because the original foo will be undefined, so I shouldn't store a reference to that). But this is what I get:
0
36741184
1
0
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
The first to numbers from pFoos are wrong. Furthermore, the large number changes every time. I don't see anything that would cause this undefined behavior. Could someone tell me what I'm doing wrong?
Adding items to a vector invalidates all previous iterators. Calling push_back on the vector may make the pointers you got from it previously invalid if the vector needs to reallocate its internal storage.
If you knew that you were never going to grow the vector again then this would work:
for (int i = 0; i < 10; i++) {
foos.push_back(Foo(i));
}
for (int i = 0; i < 10; i++) {
pFoos.push_back(&foos[i]);
}
or as commented by rodrigo:
foos.reserve(10)
for (int i = 0; i < 10; i++) {
Foo foo(i);
foos.push_back(foo);
pFoos.push_back(&foos.back());
}
for (int i = 0; i < 10; i++) {
cout << foos[i].bar << endl;
cout << pFoos[i]->bar << endl;
}
I guess this is not a good programming approach. The vector is responsible for storing objects and it may REALLOC memory to get bigger memory blobs ... So, your pointer is not valid anymore ...
vector::push_back can move elements, which is why the addresses aren't valid. You can pre-load the memory for the vector to its final size by calling reserve before you start pushing things into the vector, or you can wait until you've finished pushing things before you take their addresses.
But you say that you "cannot use dynamic memory". vector uses dynamic memory.