I am trying to wrap my mind around arrays and pointers in C++.
I am trying to write a function that allocates memory for an int array of variable size. The array is then filled with random numbers and returned.
The problem I have is assigning values with pointers.
This is the function:
int* getArray(int length) {
int* values = new int[length];
for (int i=0; i<length; i++) {
values[i]=i;
}
return values;
}
And it works just fine.
But, if I change it to this:
int* getArray(int length) {
int* values = new int[length];
for (int i=0; i<length; i++, values ++) {
*values=i;
}
return values;
}
It doesn't work.
Can someone explain to me why I cannot do this?
This is the main method that I used to print all the values:
int main() {
int* v = getArray(100);
for(int i=0;i<100;i++, v++) {
cout << *v <<endl;
}
delete[] v;
return 0;
}
I think it is because the new operator allocates new memory in the heap and not in the stack so the pointer might actually point to the wrong direction.
But, if that is true, why is the main method working?
Side note: I do not get any kind of warning or error, but the output is just a bunch of zeros and some random numbers.
I am using the GCC compiler on Ubuntu.
values++ is modifying values, which eventually forms the function return value.
i.e. you return one past the end of the allocated array. That in itself is perfectly legal C++.
But things go very badly wrong at the function call site: you access invalid elements of the array (which very informally speaking are your "random numbers"), and calling delete[] on that is also undefined behaviour. Boom!
Related
I am having difficulties passing dynamically allocated array to the function by reference.
"The array should be transmitted to the function by reference".
My program should take n amount of integers and find out the minimum. That minimum should be added to all the arrays that the user has entered. But the BY REFERENCE part kills me. I tried (int &x[],int &n) but failed.
PLease help, thank you very much.
void add_min(int x[], int n)
{
int add[n];
int mini = x[0];
int i;
for(i = 0; i < n; i++)
{
if(x[i] < mini)
{
mini = x[i];
}
}
for(i = 0; i < n; i++)
{
add[i] = x[i] + mini;
}
for(i = 0; i< n ; i++)
{
cout<<add[i]<<endl;
}
}
int main()
{
int *x;
int n;
cout<<"Enter the amount of integers"<<endl;
cin>>n;
x = new int[n];
cout<<"Enter the integers"<<endl;
for(unsigned i = 0; i < n; i++)
{
cin>>x[i];
}
add_min(x,n);
delete x;
return 0;
}
Dynamically allocated arrays cannot be in a named variable and you cannot have a reference to one.
When you call new[] the array is allocated somewhere in the memory, and the call returns the address of the first object in that array. You store the address in a pointer variable. The pointer is not an array, it simply points to the first element.
You can pass a pointer by reference to a function like this:
void foo(int*& ptr)
If your assignment asks you to pass an array by reference, then you may not allocate the array dynamically. In that case, this is how you declare the argument to be a reference to an array:
void foo(int (&arr)[10])
Note that the size must be known at compile time. You can use a template argument to generate functions for different sizes of arrays.
If the assignment does ask you to allocate the array dynamically, then they probably intend you to pass a pointer by reference.
The problem I see here is the following to pass in via reference a:
dynamically allocated array
The only way you can have dynamic allocation to happen is via returning a pointer. The syntax for passing in an array to a function, as you have correctly guessed is:
void add_min(int x[], int n) { ... }
Certainly you can treat the array as a pointer, and then you get:
void add_min(int* x, int n) { ... }
now comes the problem with the reference
The syntax for passing in an array via reference to the application is:
void add_min(int (&x)[3]) { ... }
but in this case you need to actually know the size of it, so the array is not dynamically allocated.
To circumvent the need to know the size of the array, we can do some template magic, like:
template<int n>
void add_min(int (&x)[n]) { ... }
but again, this will need to be called with a statically allocated array (int x[124]), not a dynamic one.
But arrays are always passed in via reference, they are never copied to the stack, so your version of the code is correct.
First of all, you're using C++ so you shouldn't use pointers but std::vector. It'll be easier and you won't create memory leaks.
Second, you're passing pointer, not array. There are not the same: https://stackoverflow.com/a/1641963/1351828
So you're pssing the pointer to the first element. If you want to change elements in 'array' you can just pass pointer by value. If you want to allocate new 'array' and change it in a function, pass the pointer by reference:
void add_min(int &x[], int n)
I was trying to make a program in which the user decides the dimensions of a 2-D array.
I'm getting an error on the function definition while compiling. Why is this wrong and what would be the correct way to do it?
I'm using the Dev-C++ 5.7.1 compiler (if that's relevant).
#include<iostream>
using namespace std;
int R=0,C=0;
void func(int);
int main() {
cin>>R>>C;
int array[C][R];
// DO STUFF HERE
func(array);
// DO SOME MORE STUFF
return 0;
}
void func(int arr[][R]) {
// DO STUFF HERE
}
ISO-C++ forbids VLAs. To dynamically allocate an array you'll either need to do some raw pointer tricks or use a vector of vectors.
vector of vectors approach:
std::cin >> R >> C;
std::vector<std::vector<int>> array(R, std::vector<int>(C));
The signature for func then becomes (const correctness may be different)
void func(const std::vector<std::vector<int>>& v);
The above is the easier, more maintainable, safer, shorter solution.
With pointers and pointers to pointers you can do it but it becomes more complicated, and you need to delete everything that you new
int R, C;
std::cin >> R >> C;
int **array = new int*[R]; // allocates space for R row pointers
for (int i = 0; i < R; ++i) {
array[i] = new int[C]; // for each row, allocate C columns
}
func(R, C, array);
//then delete everything
for (int i = 0; i < R; ++i) {
delete [] array[i]; // delete all of the ints themselves
}
delete [] array; // delete the row pointers.
with the signature for func being
void func(int r, int c, int **arr);
again, vector of vectors will be a lot easier on you.
An array can be located in two different memory regions - on the stack, or on the heap.
Array like you specified, is located on the stack.
int array[SIZE];
when an array is located on the stack, the compiler needs to know in advance what is its size, therefor SIZE must be a constant expression (known at compile time), and sometimes a defined value (set using #define SIZE 10).
if you want to create an array of unknown size (will be determined in runtime), you need to create the array on the heap, like this:
int **array = new int*[C];
for(int i = 0;i<C; i++)
array[i] = new int[R];
later on, you must remember to delete everything you dynamically allocated (everything you used new on)
for(int i = 0;i<C; i++)
delete[] array[i];
delete[] array;
note the use of delete[], because we are deleting an array (array is an array of arrays of ints, array[i] is an array of ints)
I would recommend passing in a pointer to the array, and two variables for R and C. Then it's up to you to make sure you use pointer math correctly to stay within the bounds of the array.
Otherwise set this up as a template, but you'll still probably need to know the sizes of R & C.
int** function()
{
int M[2][2] = {{1,2},{3,4}};
return (int **)M; //is this valid?
}
void anotherFn()
{
int **p = new int*[2];
for(int i = 0; i<2; i++) {
p[i] = new int[2];
}
p = function();
cout << p[0][0];
}
The above code compiled but gave runtime error. So, can I return a 2D array only if it was declared as double pointer or is there some way I can return an array as a 2D pointer?
You are representing a 2D array as a pointer to pointer to int. That is a bad idea. A better idea is to use a std::vector<std::vector<int>>. Better yet would be to use a dedicated class. But the point is that once you get rid of pointers you can return the value without any problem:
matrix_2d function() {
matrix_2d M = {{1, 2}, {3, 4}};
return M;
}
This works quite well for an appropriate definition of matrix_2d (see above).
Your code makes this whole process much more complicated by using pointers, and accesses invalid memory. In particular, you are allocating memory in your main function, but then you are discarding the pointer to that memory by reassigning it with the result of function(): inside function you aren’t using the previously-allocated memory, you are using stack-allocated memory and returning a pointer to that. Once the function exits, that stack-allocated memory is gone.
To return a 2D array, make sure you dynamically allocate it, then return the pointer. The problem with your code is that you are returning a pointer to a local variable, which will cause problems.
Basically, you'll want to do something like this (skeleton):
int** function()
{
int** M;
// Allocate M here
return M;
}
struct LeafDataEntry
{
void *key;
int a;
};
int main(){
//I want to declare a vector of structure
vector<LeafDataEntry> leaves;
for(int i=0; i<100; i++){
leaves[i].key = (void *)malloc(sizeof(unsigned));
//assign some value to leaves[i].key using memcpy
}
}
I am getting SEG FAULT error for this code while doing the malloc in for loop above....Any suggestions for any alternative to assign memory to the pointer in the vector of structs.
It is because you are trying to assign to a vector which does not have the elements yet. Do this instead:
for(int i=0; i<100; i++){
LeafDataEntry temp;
leaves.push_back(temp);
leaves[i].key = (void *)malloc(sizeof(unsigned));
//assign some value to leaves[i].key using memcpy
}
That way you will be accessing actual memory.
In the comments the OP mentioned that the number of elements in the array will be decided at runtime. You can set i < someVar which will allow you to decide someVar and the size of the list at runtime.
The other answer
leaves.resize(someVar) //before the loop
Is probably a better way to go though because it is likely that it will be more efficient.
You're indexing an empty vector. Try using
leaves.resize(100);
Before the loop.
Here we are once again good people of the internet.
This is the code I'm using:
//This is what is in the header file
int *myArr[]; // A two-dimensional array representing holding the matrix data
//This is what is in the definition file
Matrix::Matrix(int n, int m)
{
myRows = n;
myColumns = m;
initialize();
}
void Matrix::initialize()
{
*myArr = new int[myRows];
for (int i=0; i < 3; i++)//Only set to 3 since myRows is acting crazy
{
myArr[i] = new int[myColumns];
}
}
For some reason when I use myRows variable to create the myArr array it just seems to stop referencing the value it was pointing towards before.
For instance I give it the value 3 and after the *myArr = new int[myRows] has been executed it changes the value of myRows to 9834496, which I don't understand.
Does the "new" de-reference the variable or something?
Or am I doing something wrong?
Oh and since this is a school practice project (so I won't blame you if you don't answer) I would prefer an answer over working code, so that I could know what I did wrong for future projects.
int *myArr[];
This is wrong! You've to tell the compiler the size also, of your array of pointer. How about if you declare int a[]. You're telling the compiler to create an array of int, of unknown size, which is not allowed in C++. That is why you cannot do that.
I would suggest you to do this:
int **myArr;
void Matrix::initialize()
{
myArr = new int*[myRows]; //note int* here!
for (int i=0; i < myRows; i++)
{
myArr[i] = new int[myColumns];
}
}
This should work now.
Try replacing:
*myArr = new int[myRows];
by
myArr = new int*[myRows];
You should use std::vector<>. It deals with all the problems of memory allocation and deallocation.
And it does so without any bugs.
And then you focus yourself on the real goals of your algorithm. Not on memory management :-)
typedef std::vector<int> Ints;
typedef std::vector<Ints> Matrix;
Matrix myArray;
I'm not sure if you're project requires you to use multi-level pointers, if it doesn't another way you can approach this problem is to just treat the multi-dimensional array as one big flat array.
That means when you reach the end of a row, the index after that would be the first element of the next row. Here's how the code might look:
// In this approach the double pointer int**
// is replaced with just a simple int*
int *myArr;
// Here's your Matrix ctor. Note the use of the initializer list
Matrix::Matrix(int n, int m) : myRows(n), myColumns(m)
{
initialize();
}
void Matrix::initialize()
{
myArr = new int[myRows * myColumns];
/* This loop is no longer needed since we're allocating
one big chunk at once.
for (int i=0; i < 3; i++)//Only set to 3 since myRows is acting crazy
{
myArr[i] = new int[myColumns];
}
*/
}
// To retrieve stuff from your array
// you would do something like this:
int Matrix::operator() (const int x, const int y)
{
return myArr[x * myRows + y];
}