I'm having trouble understanding how to pass a dynamic array by reference in C++.
I've recreated the problem in this small isolated code sample:
#include <iostream>
using namespace std;
void defineArray(int*);
int main()
{
int * myArray;
defineArray(myArray);
/** CAUSES SEG FAULT*/
//cout<<(*(myArray)); //desired output is 0
return 0;
}
void defineArray(int*myArray)
{
int sizeOfArray;
cout<<"How big do you want your array:";
cin>>sizeOfArray;
/** Dynamically allocate array with user-specified size*/
myArray=new int [sizeOfArray];
/** Define Values for our array*/
for(int i = 0; i < sizeOfArray; i++)
{
(*(myArray+i))=i;
cout<<(*(myArray+i));
}
}
myArray is passed by value itself, any modification on myArray (such as myArray=new int [sizeOfArray];) has nothing to do with the original variable, myArray in main() is still dangled.
To make it passed by reference, change
void defineArray(int*myArray)
to
void defineArray(int*& myArray)
This solution is hopelessly complicated. You don't need new[], pointers or even a reference parameter. In C++, the concept of "dynamic arrays" is best represented by std::vector, which you can just just use as a return value:
#include <iostream>
#include <vector>
std::vector<int> defineArray();
int main()
{
auto myArray = defineArray();
if (!myArray.empty())
{
std::cout << myArray[0] << "\n";;
}
}
std::vector<int> defineArray()
{
int sizeOfArray;
std::cout << "How big do you want your array:";
std::cin >> sizeOfArray;
std::vector<int> myArray;
for (int i = 0; i < sizeOfArray; i++)
{
myArray.push_back(i);
std::cout<< myArray[i] << "\n";
}
return myArray;
}
push_back will work intelligently enough and not allocate new memory all the time. If this still concerns you, then you can call reserve before adding the elements.
Related
I'm learning C++ and I'm wondering if anyone can explain some strange behaviour I'm seeing.
I'm currently learning memory management and have been playing around with the following code:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
// pass back by pointer (old C++)
const int array_size = 1e6; // determines size of the random number array
vector<int> *RandomNumbers1()
{
vector<int> *random_numbers = new vector<int>[array_size]; // allocate memory on the heap...
for (int i = 0; i < array_size; i++)
{
int b = rand();
(*random_numbers).push_back(b); // ...and fill it with random numbers
}
return random_numbers; // return pointer to heap memory
}
int main (){
vector<int> *random_numbers = RandomNumbers1();
for (int i = 0; i < (*random_numbers).size(); i++){
cout << (*random_numbers)[i] + "\n";
}
delete random_numbers;
}
What I'm trying to do is get a pointer to a vector containing random integers by calling the RandomNumbers1() function, and then print each random number on a new line.
However, when I run the above code, instead of printing out a random number, I get all sorts of random information. It seems as though the code is accessing random places in memory and printing out the contents.
Now I know that I'm doing something stupid here - I have an int and I am adding the string "\n" to it. If I change the code in main() to the following, it works fine:
int main (){
vector<int> *random_numbers = RandomNumbers1();
for (int i = 0; i < (*random_numbers).size(); i++){
cout << to_string((*random_numbers)[i]) + "\n";
}
}
However I just can't understand the behaviour I'm getting with the "wrong" code - i.e. how adding the string "\n" to (*random_numbers)[i]
causes the program to access random areas of memory, instead of where my pointer is pointing to. Surely I have de-referenced the pointer and accessed the element at position i before "adding" "\n" to it? So how is the program instead accessing a totally different memory address?
"\n" is a string literal. It is an array and it is converted to a pointer pointing at its first element in your expression.
(*random_numbers)[i] is an integer.
Adding a pointer to an integer means that advance the pointer by the integer.
This will drive the pointer to out-of-range because "\n" has only 2 elements ('\n' and '\0') but the numbers returnd from the rand() function are likely to be larger than 2.
There are several issues with your code.
you are using delete instead of delete[] to free the array allocated with new[].
you are creating an array of 1000000 vectors, but populating only the 1st vector with 1000000 integers. You probably meant to create just 1 vector instead.
you can and should use the -> operator when accessing an object's members via a pointer. Using the * and . operators will also work, but is more verbose and harder to read/code for.
you are trying to print a "\n" after each number, but you are using the + operator when you should be using the << operator instead. You can't append a string literal to an integer (well, you can, but it will invoke pointer arithmetic and thus the result will not be what you want, as you have seen).
With that said, try something more like this:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int array_size = 1e6; // determines size of the random number array
vector<int>* RandomNumbers1()
{
vector<int> *random_numbers = new vector<int>;
random_numbers->reserve(array_size);
for (int i = 0; i < array_size; ++i)
{
int b = rand();
random_numbers->push_back(b);
}
return random_numbers;
}
int main (){
vector<int> *random_numbers = RandomNumbers1();
for (size_t i = 0; i < random_numbers->size(); ++i){
cout << (*random_numbers)[i] << "\n";
}
/* alternatively:
for (int number : *random_numbers){
cout << number << "\n";
}
*/
delete[] random_numbers;
}
However, if you are going to return a pointer to dynamic memory, you really should wrap it inside a smart pointer like std::unique_ptr or std::shared_ptr, and let it deal with the delete for you:
#include <iostream>
#include <vector>
#include <cmath>
#include <memory>
using namespace std;
const int array_size = 1e6; // determines size of the random number array
unique_ptr<vector<int>> RandomNumbers1()
{
auto random_numbers = make_unique<vector<int>>();
// or: unique_ptr<vector<int>> random_numbers(new vector<int>);
random_numbers->reserve(array_size);
for (int i = 0; i < array_size; ++i)
{
int b = rand();
random_numbers->push_back(b);
}
return random_numbers;
}
int main (){
auto random_numbers = RandomNumbers1();
for (size_t i = 0; i < random_numbers->size(); ++i){
cout << (*random_numbers)[i] << "\n";
}
/* alternatively:
for (int number : *random_numbers){
cout << number << "\n";
}
*/
}
Though, in this case, there is really no good reason to create the vector dynamically at all. 99% of the time, it is unnecessary and unwanted to use standard containers like that. Since the vector manages dynamic memory internally, there is no reason for the vector itself to also be created in dynamic memory. Return the vector by value instead, and let the compiler optimize the return for you.
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int array_size = 1e6; // determines size of the random number array
vector<int> RandomNumbers1()
{
vector<int> random_numbers;
random_numbers.reserve(array_size);
for (int i = 0; i < array_size; ++i)
{
int b = rand();
random_numbers.push_back(b);
}
return random_numbers;
}
int main (){
vector<int> random_numbers = RandomNumbers1();
for (size_t i = 0; i < random_numbers.size(); ++i){
cout << random_numbers[i] << "\n";
}
/* alternatively:
for (int number : random_numbers){
cout << number << "\n";
}
*/
}
I'm trying to read an unknown number of elements into the array, when my size reaches the current capacity, I call a function to double the size and copy the contents of the old array into a new array. I got my '&' but it seems it's still passing the array by value.
#include <iostream>
#include <fstream>
using namespace std;
void resize(int*&, int&);
int main() {
ifstream in("numbers.input");
int cap = 10;
double avg;
int total = 0;
int size = 0;
int *arr = new int [cap];
int temp;
for(int i =0; i <cap; i++){
in >> temp;
if(size >= cap) {
resize(arr,cap);
}
arr[i]=temp;
total += arr[i];
size++;
}
avg = (double) total/cap;
cout << cap <<endl;
cout << size <<endl;
cout << total <<endl;
cout << avg;
return 0;
}
void resize(int *&arr,int &cap) {
cap*=2;
int* newArr = new int[cap];
for(int i = 0; i < cap; i++){
newArr[i] = arr[i];
}
delete [] arr;
arr = newArr;
}
Everything you try to implement 'by hand' is already in
the standard library. Use std::vector<> which implements
a doubling/reallocation strategy very similar to what you're
proposing.
#include <fstream>
#include <vector>
int main() {
std::ifstream in("numbers.input");
std::vector<int> arr;
int temp;
while (in >> temp) { arr.push_back(temp); }
// process your data ...
}
See http://www.cplusplus.com/reference/vector/vector/
To answer the question more literally: Arrays are always passed
by reference, typically by passing a pointer to the first element.
Your resize function is taking the pointer by reference and will modify the value of the variable it is called with. However you have a number of bugs:
You copy cap items out of the old array, but you have already doubled cap, leading to an out of bound access and a possible crash.
Your resize function never gets called, due to a bug in your input loop. You should step through in a debugger (or at least add some trace cout calls) to work out what is going on. Try to figure this one out, if you can't let me know.
Your average is using cap as the divisor, that is not correct.
Note: You should add in your question that you can't use vector, because that would be the normal way to do this.
Note 2: In your question, you should also say exactly what is going wrong with your program - "seems to be passing the array by value" is a bit vague - why do you think it isn't passing by value?
I am trying to switch the elements of a class array using pointers. It is not outputting what I want. I tried using pointers in the function, but it's not allowed. It's also not allowed to call the function onto the class object without using a pointer, since I declared the class object using a double pointer. I am not using this method simply to solve a small problem, but just to practice using this method for more difficult problems.
Here is my code:
#include <iostream>
#include <algorithm>
using namespace std;
class thing{
public:
int index;
int value;
thing();
private: int number;
};
thing::thing()
{
number = 0;
}
void arrange(thing array[]){
for(int i=0; i<19; ++i){
if(array[i].value<array[i+1].value){
swap(array[i], array[i+1]);
arrange(array);
}
}
}
int main(){
thing** things = new thing*[20];
for (int i=0; i < 20; ++i)
{
things[i] = new thing(); // default constructor
things[i]->index = i;
things[i]->value=rand() % 100;
}
cout << "The random array is: " << endl;
for(int i=0;i<20;++i){
cout << things[i]->value << endl;
}
arrange(*things);
cout << "The arranged array is: " << endl;
for (int i=0; i < 20; ++i)
{
cout << things[i]->value << endl;
}
return 0;
}
When you call arrange(*things), you're just passing the first element of things to the function, not the array. It should be array(things). Then the arrange function should be written to use pointers:
void arrange(thing* array[]){
for(int i=0; i<19; ++i){
if(array[i]->value<array[i+1]->value){
swap(array[i], array[i+1]);
arrange(array);
}
}
}
Here you create an array of pointers to thing:
thing** things = new thing*[20];
Here you dereference it and get a pointer to thing which is stored at thing[0]:
arrange(*things);
But this function declaration
void arrange(thing array[])
treats this pointer as an array of thing, so that *things points to it first element, which is absolutely not what it really is.
You should change your arrange() function to use correct type:
void arrange(thing* array[]){
for(int i=0; i<19; ++i){
if(array[i]->value<array[i+1]->value){
swap(array[i], array[i+1]);
arrange(array);
}
}
}
And call it as:
arrange(things);
Regarding using vectors, you don't need to use any pointers at all.
std::vector<thing> things(20);
for (int i=0; i < things.size(); ++i)
{
things[i].index = i;
things[i].value=rand() % 100;
}
arrange(things);
void arrange(std::vector<thing>& array){
for(int i=0; i + 1 < things.size(); ++i){
if(array[i].value<array[i+1].value){
swap(array[i], array[i+1]);
arrange(array);
}
}
}
I have a class that needs to store an array with a variable size. Ideally, this size would be defined as a parameter given to the constructor of the class.
I can define a constant and then work with that, as seen below:
#include <iostream>
#define ARRSIZE 5
class Classy{
private:
int myarray[ARRSIZE];
public:
Classy();
void printarray();
};
Classy::Classy(){
for(int i = 0; i < ARRSIZE; i++){
myarray[i] = i * i * 2;
}
}
void Classy::printarray(){
for(int i = 0; i < ARRSIZE; i++){
std::cout << myarray[i] << std::endl;
}
}
However, I'd like to do it like this:
#include <iostream>
class Classy{
private:
int arraysize;
int myarray[arraysize];
public:
Classy(int parraysize);
void printarray();
};
Classy::Classy(int parraysize){
arraysize = parraysize;
for(int i = 0; i < arraysize; i++){
myarray[i] = i * i * 2;
}
}
void Classy::printarray(){
for(int i = 0; i < arraysize; i++){
std::cout << myarray[i] << std::endl;
}
}
The compiler really doesn't like my approach though, so I am looking for an alternative way of doing things.
I did some googling on the subject, but my searches did not come up fruitful. I found this approach which does it using dynamic memory allocation. This is something I'd like to avoid, so I am looking for a solution that does not rely on that. It might well be (and I'm starting to think) that it is the only elegant solution to my problem (and if this is the case, the question should of course be closed as duplicate).
It is required to use dynamic allocation, because sizeof (Classy) must be a compile-time constant. There's no way for your object's internal size to grow. But dynamic allocation doesn't have to be as complicated as that link suggests.
You can do it like this:
#include <memory>
class Classy
{
private:
int arraysize;
std::unique_ptr<int[]> myarray;
public:
Classy(int parraysize);
void printarray();
};
Classy::Classy(int parraysize)
: arraysize{parraysize}
, myarray{new int[arraysize]}
{
for(int i = 0; i < arraysize; i++){
myarray[i] = i * i * 2;
}
}
#include <iostream>
void Classy::printarray()
{
for(int i = 0; i < arraysize; i++){
std::cout << myarray[i] << std::endl;
}
}
This will allow the size to vary at the moment of creation, and be fixed thereafter. std::unique_ptr will take care of automatically destroying the array contents when your object is dying.
You want to use templates to solve this problem:
#include <array>
template<std::size_t ArraySize>
class Classy final
{
public:
static const std::size_t size = ArraySize;
/* The rest of your public interface here */
private:
std::array<int, ArraySize> m_array;
};
Then you can use your class like this:
int main()
{
Classy<5> hasArrayOfFiveElements;
return 0;
}
You could very well opt to not use std::array, in preference for a c-style array. But we're writing C++, so let's use the better language facilities we have available to us :)
Well, I think you can't do it without using dynamic memory allocation while using a classic array, but you can use std::vector. You can do it like this:
#include <iostream>
class Classy{
private:
int arraysize;
std::vector<int> myArrayOfInts;
public:
Classy(int parraysize);
void printarray();
};
Classy::Classy(int parraysize){
arraysize = parraysize;
for(int i = 0; i < arraysize; i++){
myArrayOfInts.push_back(i * i * 2);
}
}
void Classy::printarray(){
for(int i = 0; i < myArrayOfInts.size(); i++){ //you could also use arraysize, but then you
std::cout << myArrayOfInts[i] << std::endl;//must update it when you add or remove any
} // element from vector
}
You need to dynamically allocate your array using new[] and then delete[] it in your destructor. Alternatively, use a std::vector<int> and reserve the amount passed to the constructor. Yet one more method is to make your class templated, taking a size_t argument for the amount of elements you want it to have, but that completely removes the dynamic aspect of it (and you might as well be using std::array at that point.
I know you'd like to avoid dynamic allocation, but it's the most efficient way to do what you want (because vector might take up more space than you expect).
A bit late. However, this may be another approach.
#include <iostream>
#include <cstddef>
class Classy
{
public:
Classy();
template <size_t ARRSIZE>
Classy(int (&arr)[ARRSIZE], size_t size = 0);
void printarray();
private:
int* myarray;
size_t max_size;
size_t arraysize;
};
template <size_t ARRSIZE>
Classy::Classy(int (&arr)[ARRSIZE], size_t size)
{
myarray = arr;
max_size = ARRSIZE;
arraysize = size;
}
void Classy::printarray(){
for(int i = 0; i < max_size; i++){
std::cout << i << " " << myarray[i] << std::endl;
}
}
int main()
{
int arr[10];
Classy c(arr);
c.printarray();
return 0;
}
In my code I input the sizes of both dimensions and then declare a two-dimensional array. My question is, how do I use that array as a function parameter? I know that I need to write the number of columns in the function specification but how do I pass the number of columns?
void gameDisplay(gameCell p[][int &col],int a,int b) {
for(int i=0;i<a;i++) {
for(int j=0;j<b;j++) {
if(p[i][j].getStat()==closed)cout<<"C ";
if(p[i][j].getStat()==secure)cout<<"S ";
if(p[i][j].getBomb()==true&&p[i][j].getStat()==open)cout<<"% ";
if(p[i][j].getBomb()==false&&p[i][j].getStat()==open) {
if(p[i][j].getNum()==0)cout<<"0 ";
else cout<<p[i][j].getNum()<<" ";
}
cout<<endl;
}
}
}
int main() {
int row,col,m;
cout<<"Rows: ";cin>>row;cout<<"Columns: ";cin>>col;
m=row*col;
gameCell p[row][col];
gameConstruct(p[][col],m);
gameDisplay(p[][col],row,col);
}
I tried this way but it doesn't work.
Thank you.
In C++, you cannot have variable length arrays. That is, you can't take an input integer and use it as the size of an array, like so:
std::cin >> x;
int array[x];
(This will work in gcc but it is a non-portable extension)
But of course, it is possible to do something similar. The language feature that allows you to have dynamically sized arrays is dynamic allocation with new[]. You can do this:
std::cin >> x;
int* array = new int[x];
But note, array here is not an array type. It is a pointer type. If you want to dynamically allocate a two dimensional array, you have to do something like so:
std::cin >> x >> y;
int** array = new int*[x]; // First allocate an array of pointers
for (int i = 0; i < x; i++) {
array[i] = new int[y]; // Allocate each row of the 2D array
}
But again, this is still not an array type. It is now an int**, or a "pointer to pointer to int". If you want to pass this to a function, you will need the argument of the function to be int**. For example:
void func(int**);
func(array);
That will be fine. However, you almost always need to know the dimensions of the array inside the function. How can you do that? Just pass them as extra arguments!
void func(int**, int, int);
func(array, x, y);
This is of course one way to do it, but it's certainly not the idiomatic C++ way to do it. It has problems with safety, because its very easy to forget to delete everything. You have to manually manage the memory allocation. You will have to do this to avoid a memory leak:
for (int i = 0; i < x; i++) {
delete[] array[i];
}
delete[] array;
So forget everything I just told you. Make use of the standard library containers. You can easily use std::vector and have no concern for passing the dimensions:
void func(std::vector<std::vector<int>>);
std::cin >> x >> y;
std::vector<std::vector<int>> vec(x, std::vector<int>(y));
func(vec);
If you do end up dealing with array types instead of dynamically allocating your arrays, then you can get the dimensions of your array by defining a template function that takes a reference to an array:
template <int N, int M>
void func(int (&array)[N][M]);
The function will be instantiated for all different sizes of array that are passed to it. The template parameters (dimensions of the array) must be known at compile time.
I made a little program:
#include <iostream>
using namespace std;
void fun(int tab[][6], int first)
{}
int main(int argc, char *argv[])
{
int tab[5][6];
fun(tab, 5);
return 0;
}
In function definition you must put size of second index. Number of column is passed as argument.
I'm guessing from Problems with 'int' that you have followed the advices of the validated question and that you are using std::vector
Here is a function that returns the number of columns of an "array" (and 0 if there is a problem).
int num_column(const std::vector<std::vector<int> > & data){
if(data.size() == 0){
std::cout << "There is no row" << std::endl;
return 0;
}
int first_col_size = data[0].size();
for(auto row : data) {
if(row.size() != first_col_size){
std::cout << "All the columns don't have the same size" << std::endl;
return 0;
}
}
return first_col_size;
}
If you're using C-style arrays, you might want to make a reference in the parameter:
int (&array)[2][2]; // reference to 2-dimensional array
is this what you're looking for?
int* generate2DArray(int rowSize, int colSize)
{
int* array2D = new int[rowSize, colSize];
return array2D;
}
example . . .
#include <iostream>
#include <stdio.h>
int* generate2DArray(int rowSize, int colSize);
int random(int min, int max);
int main()
{
using namespace std;
int row, col;
cout << "Enter row, then colums:";
cin >> row >> col;
//fill array and display
int *ptr = generate2DArray(row, col);
for(int i=0; i<row; ++i)
for(int j=0; j<col; ++j)
{
ptr[i,j] = random(-50,50);
printf("[%i][%i]: %i\n", i, j, ptr[i,j]);
}
return 0;
}
int* generate2DArray(int rowSize, int colSize)
{
int* array2D = new int[rowSize, colSize];
return array2D;
}
int random(int min, int max)
{
return (rand() % (max+1)) + min;
}
instead of accessing p[i][j] you should access p[i*b + j] - this is actually what the compiler do for you since int[a][b] is flattened in the memory to an array in size of a*b
Also, you can change the prototype of the function to "void gameDisplay(gameCell p[],int a,int b)"
The fixed code:
void gameDisplay(gameCell p[],int a, int b) {
for(int i=0;i<a;i++) {
for(int j=0;j<b;j++) {
if(p[i*a +j].getStat()==closed)cout<<"C ";
if(p[i*a +j].getStat()==secure)cout<<"S ";
if(p[i*a +j].getBomb()==true&&p[i][j].getStat()==open)cout<<"% ";
if(p[i*a +j].getBomb()==false&&p[i][j].getStat()==open) {
if(p[i*a +j].getNum()==0)cout<<"0 ";
else cout<<p[i*a +j].getNum()<<" ";
}
cout<<endl;
}
}
}
int main() {
int row,col,m;
cout<<"Rows: ";cin>>row;cout<<"Columns: ";cin>>col;
m=row*col;
gameCell p[row][col];
gameConstruct(p[][col],m);
gameDisplay(p[],row,col);
}