I'm a student writing a method that removes zeros from the end of an array of ints, in C++. The array is in a struct, and the struct also has an int that keeps track of the length of the array.
The method examines each element starting from the last, until it encounters the first non-zero element, and marks that one as the "last element" by changing the value of length. Then the method walks back up to the original "last element", deleting those elements that are not out of bounds (the zeros).
The part that deletes the ith element in the array if i is greater than the updated length of the array, looks like this:
if (i > p->length - 1) {
delete (p->elems + i); // free ith elem
That line is wrong, though. Delete takes a pointer, yes? So my feeling is that I need to recover the pointer to the array, and then add i to it so that I will have the memory location of the integer I want to delete.
Is my intuition wrong? Is the error subtle? Or, have I got the entirely wrong idea? I've begun to wonder: do I really need to free these primitives? If they were not primitives I would need to, and in that case, how would I?
have I got the entirely wrong idea?
I'm afraid so.
If you make one new[] call to allocate an array, then you must make one delete[] call to free it:
int *p = new int[10];
...
delete[] p;
If your array is in a struct, and you make one call to allocate the struct, then you must make one call to free it:
struct Foo {
int data[10];
};
Foo *foo = new Foo;
...
delete foo;
There is no way to free part of an array.
An int[10] array actually is 10 integers, in a row (that is, 40 bytes of memory on a 32 bit system, perhaps plus overhead). The integer values which are stored in the array occupy that memory - they are not themselves memory allocations, and they do not need to be freed.
All that said, if you want a variable length array:
that's what std::vector is for
#include <vector>
#include <iostream>
struct Foo {
std::vector<int> vec;
};
int main() {
Foo foo;
// no need for a separate length: the current length of the vector is
std::cout << foo.vec.size() << "\n";
// change the size of the vector to 10 (fills with 0)
foo.vec.resize(10);
// change the size of the vector to 7, discarding the last 3 elements
foo.vec.resize(7);
}
If p->elems is a pointer, then so is p->elems + i (assuming the operation is defined, i.e. i is of integral type) - and p->elems + i == &p->elems[i]
Anyhow, you most likely don't want to (and cannot) delete ints from an array of int (be it dynamically or automatically allocated). That is
int* ptr = new int[10];
delete &ptr[5]; // WRONG!
That is simply something you cannot do. However, if the struct contains the length of the array, you could consider the array "resized" after you change the length information contained by the struct - after all, there is no way to tell the size of the array a pointer points to.
If, however your array is an array of pointers to integers (int*[]) and these pointers point to dynamically allocated memory, then yes, you could delete single items and you'd do it along the lines of your code (you are showing so little code it's difficult to be exact).
Related
I am currently working on a program that requires a function to figure out array values and then stores those values in arr1[], which has an unknown size and is calculated within the function. It then passes back the entire array along with the size of the array back to the main function. Using a struct, I returned the size, but I cannot return the array for some reason. Can someone please direct me in the right direction with what I'm doing wrong?
Here is my struct:
struct Arr
{
int size_1;
int arr_1[];
};
And here is part of my function that returns the array, where arr1[] is the array in which I need to return:
Arr smallElement(int arr[], int size)
{
Arr tempArr;
for (int count = 0; count < newSize; count++)
{
tempArr.arr_1[count] = arr1[count];
}
return tempArr;
}
This is what I use in my main function to call the function to print the array, but it just prints 3 random numbers every time:
Arr a;
a = smallElement(array, n);
cout << "The array is: ";
for (int count = 0; count < a.size_1; count++)
{
cout << a.arr_1[count] << " ";
}
Inside a struct, int arr_1[] does not define an actual array. It is actually just a placeholder called a flexible array member. In C, this is used by allocating memory for the fully defined part of the struct plus additional space for the array—you have to manually add space when using malloc or other memory allocation. In standard C++, you should not use this. (It is not part of standard C++. It is an extension adopted by some compilers from C, where it is standard.)
When you declared tempArr, it created just the fully defined portion of the struct. When you assigned values to tempArr.arr_1[count], there was no allocated array there, so the behavior is undefined. When you return tempArr, a copy of the struct is returned, but, again, only a copy of the defined portion.
If the caller knows the size the array will be, you may want to have them pass the array to the function, perhaps by allocating it with new or by using std::vector and passing the vector by reference. If the size is not known by the caller, then you may want to have the function allocate the array and return a pointer to it (in which case the caller is responsible for deleting it later), or you may want to pass an empty (or otherwise available for re-use) std::vector to the function, preferably by reference. Inside the function, it can add more elements to the vector, and the std::vector will manage memory allocation for you.
I have a double pointer Array of a structure:
typedef struct Position{
int x;
int y;
} Position;
Position** array = (Position**)malloc(sizeof(Position*)*10); //10 elements
array[0] = (Position*)malloc(sizeof(Position*));
array[0]->x = 10;
array[0]->y = 5;
Can I calculate the length of set array and if so, how?
The normal way for arrays does not work :
int length = sizeof(<array>)/sizeof(<array>[0]);
Once you have dynamically allocated an array, there is no way of finding out the number of elements in it.
I once heard of some hacky way to obtain the size of a memory block, (msize) which would allegedly allow you to infer the size of the data within the block, but I would advice against any such weird tricks, because they are not covered by the standard, they represent compiler-vendor-specific extensions.
So, the only way to know the size of your array is to keep the size of the array around. Declare a struct, put the array and its length in the struct, and use that instead of the naked array.
As you marked the question as C++, I would suggest that you use std::vector, then, after you "allocated some memory" (or requested some memory to allocated by std::vector constructor or by using push_back, or resize), you can simply get the size back using by using std::vector::size.
typedef struct Position{
int x;
int y;
} Position;
std::vector<Position> array(10);
array[0].x = 10;
array[0].y = 5;
size_t size = array.size(); // will be 10
Having only a pointer to some memory block, you cannot defer the size of this memory block. So you cannot defer the number of elements in it.
For arrays of pointers, however, you could infer the number of elements in it under the following conditions:
make sure that every pointer (except the last one) points to a valid object.
for the last pointer in the array, make sure that it is always NULL.
Then you can derive the length by counting until you reach NULL.
Maybe there are some other similar strategies.
Solely from the pointer itself, however, you cannot derive the number of elements in it.
Old question, but in case someone needs it:
#include <stdio.h>
...
int main()
{
char **double_pointer_char;
...
int length_counter = 0;
while(double_pointer_char[length_counter])
length_counter++;
...
return 0;
}
This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 6 years ago.
I have an array of integers that I pass into function. Then I want to make a dynamic array in that function as a copy of the first array, but whenever I change the value of an element in second array (copy), the value in the first array also changes. What am I doing wrong?
example:
int *array1 = new int[N]
int *array2 = new int[N]
array2 = array1;
array2[1]=2; //element of the first array at index 1 also becomes 2
Thank you.
The Explanation:
Since we are dealing with C++, there is pretty much no reason to use new int[N] instead of std::vecotr<int> of a size N.
To explain what is happening in your code: You create a pointer named array1 and allocate memory enough to contain N integers. You do the same with second pointer, called array2. Since the names array1 and array2 are just pointers to memory, what they point to can be changed. In the line array2 = array1 you change to what is pointing array2 to memory allocated and pointed to by array1 pointer.
So what happens now? Really bad stuff. You are encountering a memory leak. The memory that was pointed to by array2 is still there, still allocated, but you are unable to access it, since your only access to it (array2 pointer) now points to entirely different part of memory. You now also have 2 pointers that point to the same memory (originally the memory that was allocated in the line int *array1 = new int[N]).
How to improve your code?
Use std::vector<int>. Vector class comes with well written and safe assignment operator that will work for you here:
std::vector<int> array1(N);
std::vector<int> array2(N);
array2 = array1;
Now you have 2 identical vectors, memory is managed well (array1 and array2 are separate entities. They do not share the same memory and can be freely changed without affecting the other one) and your code looks pretty.
What if you cannot change everything to std::vector?
You mentioned having an array that you pass into a function. Let's call it an original_array of a size N. Consider this code, which uses similar signature, but uses safe memory management by converting array to vector:
void copy_and_do_stuff(int original_array[], int N)
{
std::vector<int> array2;
std::copy(original_array, original_array + N, array2.begin());
// here, the vector "array2" is a copy of your `original_array`. Changes
// to it will not affect your argument.
// ... do whatever you need to do in this function ...
}
Remember to add #include <vector> and #include <algorithm> to use vectors and std::copy function.
To give a full answer, although the comments say everything important so far:
The line array2 = array1; does the following: take the address that is stored in array1 and store it also in array2. They are both pointing at the same location now (and the old, reserved storage is still reserved but not pointed at, aka a memory loss)
In any case, pointers are somewhat dangerous things, easily leading to unexpected behaviour, especially if you are a beginner. Therefore, you want to use std::vector:
//at the head of the file
#include <vector>
using std::vector;
//in the program
vector<int> array_1(n);
//do something with array_1:
array_1[0] = 1;
array_1[1] = ...
vector<int> array_2 = array_1; //actually copies the content
or:
vector<int> array_2(array_1); //copy constructor
At some point you will want to investigate how vector works internally (it wraps an array, actually), but for now, simply use vector. Read it's documentation. You can do all sorts of things on it with the STD library, like for example having it sorted by std::sort.
As mentioned in the comments you probably shouldn't be doing this in c++; std::vector is THE optimized; safe and reliable way to handle data of this sort.
But it is clear from your question that you don't really understand pointers.
This is what you code does:
int *array1 = new int[N]; //allocate memory for the first array
int *array2 = new int[N]; //allocate memory for the second array
array2 = array1; //OVERWRITE the location of the second array
//with that of the first (thus destroying your
//only pointer to the second array and creating a
//memory leak)
To achieve what you want in array2=array1 you need to write a loop and copy every integer ELEMENT of the array across to the new array - this creates a 'deep' copy.
array1 and 2 are pointers in your case.
When you do:
array2 = array1;
array2 points to the same memory location as array1, and the old array2 is lost in memory (and so it creates a memory leak, as Elemental said)
You need to copy the array elements by hand or use std::vector
I have an array of a structure (with the parameters of name and number), and the initial array takes in elements from a document that I've made. The initial list size starts at 1000. When the list fills up, I call another method that I'm struggling with. I would like for it to copy the data into a new array that doubled the size, and then delete the old array.
If I name it: array1 and array2, I have my program use array1 throughout. I need help with the pointers that would get array2 to work as array1.
Is there a way to copy the array to a temp array of the same or new size, and then remake the initial array reassigning back to that? For this exercise, I can't use vectors. While I know how to use them, and that they solve this issue while being better, I'm trying to do it with only arrays.
using namespace std;
struct Information {
char functionality;
int SSN;
string name;
};
int numPeople = 1000;
//Gets called if the initial array (whatever size) is filled
void doubleArray(Information *array){
numPeople = numPeople * 2;
//Will now be the doubled array size
Information temp[numPeople]
for(int i = 0; i < numArray; i++){
temp[i].SSN = array[i].SSN;
temp[i].name = array[i].name;
}
//Normally makes it crash
delete[] array;
}
edit: This is what I currently have
void doubleArray(Information *person){
numPeople = numPeople * 2;
Information* temp = new Information[numPeople];
memcpy(temp, person, numPeople);
delete[] person;
person = temp;
}
It gets to numPeople = 1000 (the initial list size) but then crashes shortly after. Is the doubling array correct?
Arrays are fixed size. You cannot change the capacity of the original array.
{Use std::vector}
You can have a pointer to an array. And use the same pointer. When the array is full, you can allocate another array, copy old array items to new array, delete the old array and assign your array pointer to the new array.
{Did I mention std::vector?}
By the way, there is a data structure that performs resizing as necessary. If I recall correctly, it is std::vector. Try it out. :-)
Assuming you are using std::array (which you should be), then copying the array is very easy.
std::array<myStruct, 1000> array1{};
std::array<myStruct, 2000> array2{};
// codes...
std::copy(array1.begin(), array1.end(), array2.begin())
However, this is a specific scenario in which you only use these two arrays. It will not dynamically double the size of the array as you simply cannot do this dynamically with stack-based arrays, just like c arrays[].
What you can, and should, be using is std::vector<myStruct>. This will dynamically grow as you need it. Until you provide us with code and a more specific issue, this is the best advice that I can offer with the information provided.
If you aren't allowed to use std::vector, as one of your comments stated, then you'll want to look at dynamic allocation.
size_t sz = [whatever];
// Dynamically allocate an array of size sz.
T* T_array = new T[sz];
// Do whatever...
delete[] T_array; // new[] needs to be paired with delete[].
T_array = nullptr; // Not strictly necessary, but a good idea if you have more code after.
As the size doesn't need to be constant for a dynamic array, this will allow you to allocate memory as necessary. You can then use std::copy() to copy data from one array to the other, as Goodies mentioned.
[For more information on dynamic allocation, see here.]
Lets say, i have
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
Now I want to add a 6th element to the array. How do I do it?
You have to reallocate the array and copy the data:
int *p;
p = new int[5];
for(int i=0;i<5;i++)
*(p+i)=i;
// realloc
int* temp = new int[6];
std::copy(p, p + 5, temp); // Suggested by comments from Nick and Bojan
delete [] p;
p = temp;
You cannot. You must use a dynamic container, such as an STL vector, for this. Or else you can make another array that is larger, and then copy the data from your first array into it.
The reason is that an array represents a contiguous region in memory. For your example above, let us say that p points to address 0x1000, and the the five ints correspond to twenty bytes, so the array ends at the boundary of 0x1014. The compiler is free to place other variables in the memory starting at 0x1014; for example, int i might occupy 0x1014..0x1018. If you then extended the array so that it occupied four more bytes, what would happen?
If you allocate the initial buffer using malloc you can use realloc to resize the buffer. You shouldn't use realloc to resize a new-ed buffer.
int * array = (int*)malloc(sizeof(int) * arrayLength);
array = (int*)realloc(array, sizeof(int) * newLength);
However, this is a C-ish way to do things. You should consider using vector.
Why don't you look in the sources how vector does that? You can see the implementation of this mechanism right in the folder your C++ include files reside!
Here's what it does on gcc 4.3.2:
Allocate a new contiguous chunk of memory with use of the vector's allocator (you remember that vector is vector<Type, Allocator = new_allocator>?). The default allocator calls operator new() (not just new!) to allocate this chunk, letting himself thereby not to mess with new[]/delete[] stuff;
Copy the contents of the existing array to the newly allocated one;
Dispose previously aligned chunk with the allocator; the default one uses operator delete().
(Note, that if you're going to write your own vector, your size should increase "M times", not "by fixed amount". This will let you achieve amortized constant time. For example, if, upon each excession of the size limit, your vector grows twice, each element will be copied on average once.)
Same as others are saying, but if you're resizing the array often, one strategy is to resize the array each time by doubling the size. There's an expense to constantly creating new and destroying old, so the doubling theory tries to mitigate this problem by ensuring that there's sufficient room for future elements as well.