I stumbled on this problem while tinkering with old school arrays. An interesting one though:
a[] = {1,2,3,4,5};
a[][] = {{1,2,3,4}, {4,5,6,7}, {8,9,10,11}, {12,13,14,15}}
Consider 2 scenarios:
1.)
void func(int *a) { //passing a 1D array
a[1] = 100; //modified an element here
delete a; //This would have no effect on the array outside this function.
}
2.)
void func(int (*a)[4]) { //passing a 2D array
a[1][2] = 100; //modified an element here of 2D array
delete a; //Would have an effect on the outside. Would delete a[0][0]'s memory outside.
}
Question is why?
In 1.) pointer shall point to an array variable memory hence, the delete signature won't clear the memory a[0]?
In 2.) the signature of parameter and passed variable match exactly hence the delete would indeed delete the memory held by local variable?
Any pointers here?
You're invoking undefined behavior on multiple levels. Calling delete on an array rather than delete[]...and calling any form of delete on an object not allocated with new.
Your program can do anything it wants.
Related
Quick question. Will this leak and why/ why not?
int main()
{
int array[] = {1,2,3};
doStuff(array);
return 0;
}
when doStuff will do something like this
void doStuff(int * arr)
{
// ...
arr = new int [50];
// ...
}
EDIT for #Scott Hunter
I think it won't leak because array points to memory on stack and I've never heard of memory leaking from stack, but on the other hand i kinda lose any link to this memory.
EDIT2
My problem was I was thinking that changing arr in doStuff address will change array in main as well but it won't.
Yes it will leak, since you don't call delete [] arr; anywhere inside of doStuff().
Note that you don't even change the int array[]; declared outside of the function.
All you are doing is to change a copy of that pointer that was passed as by value parameter.
As an aside recommenation:
Don't use raw pointers and raw arrays in c++. Rather use a std::vector<int> for your case, and forget about dynamic memory management at all.
doStuff takes a copy of the array pointer. Setting arr to something else inside the body of doStuff will not modify the original array value in main.
Therefore, unlesss you call delete[] arr inside doStuff, your code will leak.
void func(int* array)
{
array=new int[5];
for (int i=5; i>0; i--)
array[5-i]=i;
}
int main()
{
int array[5]= {1,2,3,4,5};
func(array);
cout<<array[1]<<endl;
}
I presume this has something to do with arrays being constant pointers. How exactly does c++ handle this code and what happens to the dynamic memory that is assigned within the function?
When you pass an array as argument to a function by value, it decays to the pointer to the first element, which then gets passed by value. So what you recieve in the function func is a copy of the address of the first element of the array. In the function, you simply change the address, which doesn't change the array in the main() function. Whatever you do to array in func(), is local to that function only. It is like this:
void f(int x)
{
x= 100; //modifying the copy, not the variable in main()
}
int main()
{
int value = 1000;
f(x); //pass by value, means pass a copy!
}
In this case you're changing the value of x in f(). Likewise, in your case, you're changing the value of array. Since array is a pointer, you're making it pointing to a different location by allocating a new memory to it. Every change is local to the function.
Also note that since you allocate memory to the variable array, and don't deallocate it, your program leaks memory. In order to avoid that, you must write:
delete [] array;
before returning from the function. Again, this delete wouldn't change array in main().
By the way, if you want to change the element of the array in main(), then you should do this instead:
void func(int* array)
{
//array=new int[5]; //just comment this
for (int i=5; i>0; i--)
array[5-i]=i; //now array points to the same memory
//where main()'s array is in the memory.
}
Hope that helps.
Here's the problem:
array=new int[5];
This assignment means that the passed parameter will not be modified. After this assignment, array points to a newly allocated chunk of memory rather than to the array declared in main (and passed to func as an argument). What is modified is this newly allocated array -- and that's thrown away when the function returns. To make matters worse, you have a memory leak.
Suppose I have an array of objects of type Foo in C++:
Foo array[10];
In Java, I can set an object in this array to null simply by:
array[0] = null //the first one
How can I do this in C++?
Use pointers instead:
Foo *array[10];
// Dynamically allocate the memory for the element in `array[0]`
array[0] = new Foo();
array[1] = new Foo();
...
// Make sure you free the memory before setting
// the array element to point to null
delete array[1];
delete array[0];
// Set the pointer in `array[0]` to point to nullptr
array[1] = nullptr;
array[0] = nullptr;
// Note the above frees the memory allocated for the first element then
// sets its pointer to nullptr. You'll have to do this for the rest of the array
// if you want to set the entire array to nullptr.
Note that you need to consider memory management in C++ because unlike Java, it does not have a Garbage Collector that will automatically clean up memory for you when you set a reference to nullptr. Also, nullptr is the modern and proper C++ way to do it, as rather than always is a pointer type rather than just zero.
So, forget Java here, it's not helping you. Ask yourself; what does it mean for an object to be null? Can an object be null? The answer is no, an object can not be null, but a reference (pointer in C++ terms) to one can be.
In java you have reference types, which are similar to pointers under the hood. However, you cannot set objects to null even in java, only references.
In C++ you have fully fledged objects and pointers and references to objects. A pointer to an object (or primitive type) can be null, but an object itself cannot.
So, when you create an array of Foo objects you have, well, an array of Foo objects. You don't have pointers, you have objects. If your array were an array of pointers to objects then yes, you could initialize them to null (nullptr in C++0x), i.e., they don't refer to a valid object.
Other way that you have is using one dynamic array of pointers of Foo like this:
Foo** array = new Foo*[10];// Pointer of array of pointers.
Then you can initialize all this pointers to objects Foo
for(int i=0;i<10;i++)
array[i] = new Foo();// Give memory to pointers of object Foo in array
assign null to one item of array:
array[0] = 0;
I think that in C++, NULL is 0. This means it can even be assigned to an int or anywhere a 0 is acceptable. Conventionally, it's only used with pointers.
For delete this memory:
for(int i=0;i<10;i++)
delete array[i];
and finally
delete[] array;
Code Example:
#include <iostream.h>
#include <stdio.h>
class Foo
{
private:
int a;
public:
Foo()
{
a = 0;
}
void Set_V(int p){a = p;}
int Get_V(){return a;}
};
int main()
{
Foo **array = new Foo*[10];
for(int i=0;i<10;i++)
{
array[i] = new Foo();
}
//array[0] = 0;
for(int i=0;i<10;i++)
array[i]->Set_V(i);
for(int i=0;i<10;i++)
cout<<array[i]->Get_V()<<endl;
for(int i=0;i<10;i++)
delete array[i];
delete[] array;
return 0;
}
so is there away to "remove" an element in the array without creating a new one? i.e making a hole in the array of some sort?
In C++, if you have an array:
Foo array[10];
Then all 10 elements will be default-constructed. In general, there's no concept of array elements being in use vs. "removed". One way to track this idea is to make having actual values in the array elements optional, as in:
boost::optional<Foo> array[10];
You can read about the boost library's optional<> library at http://www.boost.org/doc/libs/release/libs/optional/
For the sake of documenting alternatives, I'll cover a hideous one. You could call the destructor on one of the elements: array[3].~Foo(); This is very dangerous as when the array itself goes out of scope, the destructor for each element will be called, and a precondition for that is to have a properly constructed object, so you have to be sure to have constructed a Foo in that element again beforehand (using "placement" new). There is nothing in the array itself that will help you keep track of which elements have had their destructors called by you - you'd need to track that yourself (having some record of this inside the objects would probably work in practice, but accessing the object after destruction is undefined behaviour). You'd need to be very careful that in all code paths - including those due to exceptions - you tracked the momentarily unused array elements. You really don't want to do this.
If your concern is to remove an element from the array to save memory, then use smart pointers:
shared_ptr<Foo> array[10];
You can then control specific array elements independently, with only still-populated elements being destructed when the element goes out of scope. Suitable smart pointers are available in boost or C++11, or you could use std::auto_ptr<> but should carefully read about its semantics beforehand to see if it's suitable and how to safely use it.
Separately, if there's a Foo::operator=(Some_Type*) then you could set array[3] = NULL;, and it would do whatever that assignment operator did to array[3]. Still, if Foo is not a pointer, it is probably a bad idea for it to allow someone to assign NULL to it.
I've tried to allocate a memory this way:
main:
X** a;
func(a);
func:
func(X** a){
int size = 5;
X* array = (X*)malloc(5*sizeof(X));
//some writing to the array..
a = &array;
}
If using the debugger I see that when I am in the function func everything is okay = i can write to the array and a really points to the array but the moment I am back to the main I something changes and I can't access the array through a (on the debugger it writes something like: Target request failed: Cannot access memory at address 0x909090c3 and so on).
Where is my mistake?
Note: It does compile but has a run-time problem if trying to access (print for example) the array in the main section.
Thanks.
You have to change your main like this:
X* a; // create an uninitialized pointer
func(&a); // pass the address of that pointer to the function
And inside your function, do this:
void func(X** a){
int size = 5;
X* array = (X*)malloc(5*sizeof(X));
//some writing to the array..
*a = array; // change the value of the pointer to point to the array
// you allocated
}
Note that in C++ the way to go would be to use an std::vector<X>:
std::vector<X> func() {
std::vector<X> buffer(5);
// do stuff with buffer
return buffer;
}
std::vector<X> foo = func();
This would create a new vector inside the function and return a copy of that vector to the caller. Note that the copy would be optimized away.
You are changing the local copy of your variable a, it will not propagate to the outside of function (ie. the calling scope). Easiest solution to your problem is to pass a by reference, but you can also pass it using a pointer and dereferencing the pointer inside of your function.
See the below examples.
Using a reference
void func (X*& a) {
X* array = (X*) malloc (5*sizeof(X));
a = array;
}
...
X* a;
func (a);
The ampersand on the line below states that a is being passed by reference, ie. changing it inside the function will make the change propagate to parameter the caller used.
void func (X*& a) {
Using a pointer-to-pointer
This can be hard to comprehend if you are inexperienced when it comes to pointers, but we will make func take a pointer-to-pointer as it's parameter and pass in the address of variable a from main.
Upon dereferencing the pointer-to-pointer we can safely store away the information we want.
void func (X** pointer_to_a) {
X* array = (X*) malloc (5*sizeof(X));
*pointer_to_a = array;
}
...
X * a;
func (&a); // pass in address of a
NOTE
Since you are writing C++ (stated by question title and tag) you should not be using std::malloc, instead refer to operator new.
You're setting the local pointer a to the address of the local pointer array, when you want to set the target of a to the value of array:
*a = array;
and call it as
X * a;
func(&a);
It would be less confusing to return the pointer (i.e. X * func()).
Also, you've tagged this C++ not C, so you shouldn't be using malloc; use the standard containers, or if they don't work for you, allocate using new and manage the memory with a smart pointer.
In main, a is a pointer to a pointer. That means that two things have to exist: the block of memory, and a pointer pointing to it. Then a can point to that pointer. In your attempt, that middle pointer is being allocated on the stack of func, and when func returns, it's destroyed, so that's not going to work.
You could do this:
X* pa;
X** a = &pa;
func(a);
func(X** a){
int size = 5;
X* array = (X*)malloc(5*sizeof(X));
//some writing to the array..
*a = array;
}
Think it over:
a = &array;
array is a local variable allocated on heap, &array will be junk when its scope is over (the function body).
This is really a noob quick question.
Imagine you have a struct called "No" and the following piece of code:
No *v_nos; // What does this mean?
Where I took this from they were calling "v_nos" a array? Isn't it simply a pointer to a struct "No"?
Thanks.
Arrays and pointers are NOT the same. In your case, the variable is a pointer, not an array. Even if they are not the same, the confusion is quite common and you will find in many places (including C/C++ books) that they are the same thing. This means that you should get acquainted to people calling pointers arrays.
When the C language was developed they decided that instead of passing arrays by value (possibly requiring a huge amount of copying and stack memory) they would convert silently the array into a pointer to the first element and then pass that pointer to the function.
void f( int a[3] ); // valid and misleading
// what it means:
// void f( int *a);
void test() {
int array[3];
f( array );
// what it means:
// f( & array[0] )
}
For backwards compatibility C++ keeps that feature around and you cannot pass arrays by value, nor define a function that takes an array by value (in both cases it will be converted to a pointer to the first element silently). At the same time, you can use the array access syntax on pointers to simplify pointer arithmetic, making it more confusing:
int array[3];
int *pointer = array; // simplified:
// int * pointer = & array[0]
pointer[2]; // equivalent to *(pointer+2) or array[2]
This means that with regular functions both in C and C++ arrays silently decay into pointers and most people will have the idea that they are the same thing: an array is a pointer to the first element. Well, they are not.
Both in C and C++ they are different entities, even if some usage patterns are equivalent due to that design decision. But they are in fact different:
int array[3]; sizeof(array); // 3*sizeof(int)
int *p1=array; // sizeof(int*), usually 4/8 bytes for 32/64 bit
int *p2=new int[3]; // sizeof(int*)
After passing through a function/method call, they are all pointers:
void f( int array[3] ) { sizeof(array); } // sizeof(int*) it is really a pointer! size is ignored
void g( int *p ) { sizeof(array); } // sizeof(int*)
In C++ things become even more interesting, as pass-by-value is not the only available paradigm and you can pass by reference:
void f( int (&array)[3] ); // funny syntax to pass an array of 3 integers by reference
void testf() {
int array1[3]; f(array1); // correct
int array2[2]; // f(array2); compilation error, it is not an array of 3 ints!
int *p = array1; // f(p); compilation error, it is not an array of 3 ints!
}
void g( int array[3] ); // means: void g( int *array );
void testg() {
int array1[3]; g(array1); // correct, the array decays into & array[0]
int array2[2]; g(array2); // correct, the array decays again
int *p = array1; g( p ); // correct it is a pointer
}
Note that when you define a function that takes an array by value you are actually defining a function that takes a pointer by value and that the compiler will not check that the argument to the function call actually has that size. This is a known source of errors and the reason why most functions that take arrays also take a size parameter.
Lastly, you cannot create arrays dynamically, you can only acquire memory dynamically into pointers, so when you need a heap allocated array you are actually in need of a pointer into a heap allocated contiguous block o memory:
void test() {
int *p = new int[3];
// int array[3] = new int[3]; // error!! an array is not a pointer
delete p;
}
At the end this all means that they are not the same thing, but that you can always use an array in the place of a pointer and it will be automatically converted by the compiler into a pointer to the first element of the array. More often than not, people will refer to pointers into a block of contiguously memory (whether stack or heap allocated) as array.
In terms of implementation, arrays and pointers are the same. That is, arrays are simply implemented as pointers to the first element in the array. The difference between
No *v_nos;
and
No v_nos[3];
Is that the latter sets aside memory for 3 elements for that array, while the pointer would need to have memory allocated using malloc (or new).
You could still treat the second one as the pointer that it is though, for example *v_nos would give you the first element, &v_nos would give the address of the pointer.
You are correct, but it can also be used as an array :
v_nos = new Nos[10];
v_nos[5].whatever = something;
// etc
Yes, it declares (but does not initialise) a pointer to a No.
Its a pointer to a No struct.
If they are calling it an array, that pointer could point to the first member of an array of No structs
for example
No* nos= getNosArray();//pseudocode
*nos;//first element
*(nos+1)//2nd element;
Arrays and pointers are more or less interchangeable in C++. You can dereference an offset from a pointer - *(v_nos+2) - and it's effectively the same as indexing an array v_nos[2]. In fact you can use either notation, IIRC. Under the covers both examples tell the compiler to do the same thing: increment the pointer by 2 * the size of the pointed-at object, and then return what it finds at that location.
typedef struct NO
{
int x;
}_NO;
int main()
{
_NO* v_nos;
_NO *v_nos_array;
v_nos = new _NO(); // allocate mem for 1 struct
v_nos_array = new _NO[100]; allocate mem for 100 structs
for(1=0; 1<100; i++) v_nos_array[i].x = i; //five some value to 'x' of each struct
for(1=0; 1<100; i++) cout << v_nos_array[i].x << "\n";
}
hope you can extract out the meaning. Note that an array with a single element is still an array.