I've been trying to erase an element from an array without changing the index order, for instance:
class MyObject
{
int id;
public:
MyObject() { }
void setId( int i ) { id = i; }
void showId() { std::cout << "ID: "<< id << "\n"; }
};
MyObject *myArray;
int main ( )
{
myArray = new myArray[6];
for( int i = 0; i < 6; i++ )
{
myArray[i]->setId(i);
myArray[i]->showId();
}
}
I want to remove myArray[3] without changing the index of the others. e.g:
myArray[0] = ID: 1
myArray[1] = ID: 2
myArray[2] = nothing
myArray[3] = ID: 4
myArray[4] = ID: 5
myArray[5] = ID: 6
I've tried to use use memset(), but it didn't work.
memset(&myArray[3],0,sizeof(MyObject));
There's no such thing as "nothing" in C++ language. Once you have an array, all elements of that array will contain "something". There's no way to make an array element just disappear with keeping all other elements in their original places. You can't create a hole in the array.
All you can do in this case is simply label some element as "deleted" and then later recognize it as such. The element will, of course, continue to exist physically. It is you who'll have to recognize it as "deleted" and ignore it in your further processing. You can either add some bool is_deleted field to your object, or you can use some reserved value of id (like -1) to indicate a deleted element.
In your example with memset you essentially set the id to zero. Is 0 a valid id value? If it is not, then 0 is a good choice to mark a deleted element. In that sense your memset attempt works perfectly fine, as it should. Although I'd recommend doing it by explicitly assigning zero to id, without using memset.
You are calling memset to write a bunch of zeros over the top of an object instance. Do not do this! You may get away with it if your class is a true POD class. You might end up just setting the ID to 0. But maybe there is more to your class that you aren't showing. In anycase, even if it isn't POD, don't use memset like that.
You can either store pointers to object and use the null pointer to indicate there is nothing there. I'd do this with std::vector<MyObject*>. Or you use a sentinel object instance, for example with ID of -1.
The other thing that could be a problem is that you appear to be using 1-based indices. C++ arrays are 0-based, so the first element is myArray[0] and not myArray[1].
Using memset that way is setting all the bytes of that object to 0. This is usually equivalent to setting id to 0, because the memory of an object is the memory of its members (not counting vtables, padding, etc). But don't do that anyway.
One way to do this is to use new and have an array of pointers.
MyObject* myArray[6];
int main ( )
{
for( int i = 0; i < 6; i++ )
{
myArray[i] = new MyObject;
myArray[i]->setId(i);
myArray[i]->showId();
}
}
Then to display them all:
for (int i = 0; i < 6; i++) {
cout << "myArray[" << i << "] = ";
if (myArray[i])
myArray[i]->showId();
else
cout << "nothing" << endl;
}
Then when you want to remove an object, delete it and set its pointer to NULL:
delete myArray
myArray[3] = NULL;
Then when you do anything with one of the objects in myArray, you must check if it is NULL to see if it's a valid object.
Consider boost::optional:
typedef boost::optional<MyObject> MyObjectOpt;
MyObjectOptArr *myArray;
The syntax/usage is a bit different (resembles using pointer):
for (int i = 0; i < 6; ++i) {
if (myArray[i])
cout << "myArray[" << i << "] = " << *(myArray[N]);
else
cout << "nothing" << endl;
}
To unset value do:
myArray[N] = boost::none;
Related
I don't understand how I can check if a certain position in an array is been modified or not. Below is an example:
int array[5];
array[2] = 23;
array[4] = 23;
for (int i = 0; i < 5; ++i) {
if (array[i] == ????){
cout << "in array";
} else {
cout << "not in array";
}
}
So I wanted to know how would I get it so the if statement is checking if the item has been modified. So once I becomes 2 it will says it's in array and if not the it should print 'not in array'.
This has to be done using pointers.
This is undefined behavior because array[0] isn't initialized. So when you compare it in your if, what will happen?
You could initialize them all to a value that you consider as "not modified", and check for this value. For instance:
int array[5] = {}; // initializes all elements to the default value for int, which is 0
And then, in your if:
if (array[i] != 0 ) {
If you can't do that because you need the full range of int values, then you can use std::optional instead:
#include <iostream>
#include <optional>
int main() {
std::optional<int> array[5];
array[2] = 23;
array[4] = 0;
for (int i = 0; i < 5; ++i) {
if (array[i]) {
std::cout << "in array" << std::endl;
}
else { std::cout << "not in array" << std::endl; }
}
}
You can't. In C++, it's impossible to determine if an object is uninitialized. Any attempt to read the value of an uninitialized object is Undefined Behavior. They're effectively write-only.
(You might also have a problem with the terminology, or a lack of understanding. array[0] is in the array from the very start, it's just not yet initialized. )
You might use std::map<int, int> values instead. It can truly be empty (values.empty()==true) When you write values[2]=0, a new value is added, and values.size() will be 1 to reflect the new number of elements.
I don't understand how I can check if a certain position in an array is been modified or not.
On x86 you can set a hardware breakpoint on read/write/execute access to a value at a specific address of length of up to 8 bytes. On Linux one API for that is perf_event_open with PERF_TYPE_BREAKPOINT event type. The value of the event counter is how many of interesting accesses to the value at the address have been made.
One option would be using two arrays. A bool array to store the initialization state, and another array to keep desired objects.
(However std::array or std::vector would be better choices than using normal arrays, but that's a different concern)
E.g.
constexpr unsigned int ArrayLen = 5;
bool isInitialized[ArrayLen] = {false};
MyType myArray[ArrayLen]; // In your case `MyType = int`
...
// When setting/resetting update both arrays
void Set(int i, MyType obj)
{
assert(i < ArrayLen);
isInitialized[i] = true;
myArray[i] = std::move(obj);
}
...
// check isInitialized array first before accessing an element
unsigned int targetIndex = 2;
if (isInitialized[targetIndex])
{
auto& obj = myArray[targetIndex];
// use `obj` ...
} else {
// object in `targetIndex` is not initialized
}
In C++17 you can use std::optional so that the initialization state doesn't need to be separately maintained but instead both the state and the object will be bound to a single std::optional object.
I'm working on an assignment involving string pointers. There are two functions. The first takes in an array of strings, places the address of each element into a separate array, and then returns the pointer to that array. The second function takes the pointer that was returned and prints out the elements of the original array with just the pointer. But when I test it, the dereferenced string** ptrToPtr is different in each pointer. I want to know why
Here is Function 1:
string** arrayOfPtrs(string arr[], int size)
{
string* ptrArray; //The array of string pointers
string** ptrToPtr; //A pointer to the array of string pointers
ptrArray = new string[size];
//ptrArray = arr;
int i = 0;
while (i < size)
{
ptrArray = &arr[i];
i++;
ptrArray++;
}
ptrToPtr = &ptrArray;
return ptrToPtr;
}
Here is Function 2:
void outputArray(string** arr, int size)
{
int count = size; //An int variable that stores the size of array
string* ptr = *arr; //A pointer that stores the address to the last element
//in the string pointer array
while (count > 0)
{
cout << *(ptr - count) << " ";
count--;
}
cout << endl;
}
And here is part of main():
string strArr[] = { "echo", "charlie", "delta", "bravo", "delta" };
string** strPtrs;
strPtrs = arrayOfPtrs(strArr, 5);
cout << "Actual results: ";
outputArray(arrayOfPtrs(strArr, 5), 5);
cout << endl << endl;
I'm I going wrong anywhere? Or is there a better way to deference a pointer to a string pointer?
Here is a similar program ran completely in main:
int main()
{
string words[30];
string* s;
s = new string[30];
string** t;
createArray(30, words);
int num = 0;
t = &s;
while (num < 30)
{
s = &words[num];
num++;
s++;
}
string* u = *t;
int j = 30;
for (int i = 0; i < 30; i++)
{
cout << "*(s - " << j << ") - " << *(s - j) << endl;
cout << "words[ " << i << " ] - " << words[i] << endl;
cout << "*(u - " << j << " ) - " << *(u - j) << endl << endl;
j--;
}
}
And this program works perfectly. Any ideas?
This is incorrect:
while (i < size)
{
ptrArray = &arr[i];
i++;
ptrArray++;
}
Replace ptrArray = &arr[i]; with *ptrArray = arr[i];. As it stands now, you're just overwriting the same pointer each time through the loop and never doing anything useful with it.
This is also incorrect:
string* ptrArray; //The array of string pointers
// ...
ptrToPtr = &ptrArray;
return ptrToPtr;
As soon as you return that, it becomes dangling. You're not allowed to use pointers to local (stack) variables once they're out of scope.
Firstly, I see a few problems in your setup
You don't need this for practical reasons. If you want to have the address of each element in the array, you can calculate it by incrementing the pointer to the first element (which is the array in fact). If you only do that for educational reasons forget about this
string* ptrArray = new ... Now you have an array of strings (array is semantically equaivalent to pointer to first element). But you want an array of string pointers. So you need string** ptrArray = new ... and this cascades to the rest of the function being incorrect.
You never delete the array allocated with new. This results in the memory not being free'd. You need to delete[] *strPtrs;in your last code snippet to free the memory you allocated in your method. In general it is a good idea to let the one who allocates the memory be responsibly for freeing it. I show you another idea below to handle this.
After your copy operations the pointer points past your array. Then you return a pointer to it. You applied the correct arithmetics when outputting the values in you second snippet, but I would never want to have such a pointer going around. Conventionally it should point to the first element. At least when deleting the array-pointer it has to point to the first element, otherwise you get undefined behavior e.g. deleting another array.
Lastly:
string* ptrArray; //The array of string pointers
string** ptrToPtr; //A pointer to the array of string pointers
ptrToPtr points to ptrArray, which is a local variable. It becomes invalid when leaving the function and thus it will be undefined behavior to dereference the returned pointer.
There is a common approach used by some standard libraries (e.g. snprintf from cstdio), so the caller is responsible for allocation and deallocation:
void arrayOfPtrs(string arr[], int size,/*new param*/ string** outArray)
{
string** iter = outArray; // Iterator pointer
int i = 0;
while (i < size)
{
*iter = &arr[i];
i++;
iter++;
}
}
What happens here, is that the caller gives the function a pointer to the pointers (it points to the first pointer). Note that a pointer can be used as an array with index operators etc. So it is in fact an array of pointers. You then fill it by incrementing the copied pointer so it jumps from pointer element to pointer element. Where the array actually is stored is not the problem of this function.
Use it like this:
// Variant 1: Use local variable if size is constant
string* arr[5];
arrayOfPtrs(strArr, 5, arr);
std::cout << *arr[0]; // Dereferences a pointer in arr to get the string which is actually in strArr
// Variant 2: Allocate heap memory (if you need dynamic size)
int size ...; // From somewhere
string** arr = new string[size];
arrayOfPtrs(strArr, size, arr);
std::cout << *arr[0]; // Same again
... // Do further work
delete[] arr; // Free memory
So you have to allocate memory (or use a local variable) before you call the function and then pass it to the function. In the double pointer, the first * is meant for the data type which is "pointer to string" and the second designates it as a "pointer-array".
Where does a list inside an object gets its stack?
The program below shows a size of the object of 40. So where did the list allocate its memory from?
class TEST
{
public:
TEST(void);
void Push(void);
private:
std::list<int> _list;
std::list<int>::iterator _it;
int f;
};
TEST::TEST(void) : f(1)
{
}
void TEST::Push(void)
{
_list.push_back(f++);
}
main:
{
TEST n;
int a = sizeof(n);
std::cout << a << std::endl;
n.Push();
a = sizeof(n);
std::cout << a << std::endl;
for(int r=0; r<10000; r++){
n.Push();
}
a = sizeof(n);
std::cout << a << std::endl;
}
Output:
40 <br/>
40 <br/>
40
Just to add on to the comment about your use of sizeof()
I would take a look at the answer to this question here:
Size of class object in C++
Essentially the sizeof() operator only takes into account the members of the class and not any associated heap allocations. Although a member variable, _list is essentially just a pointer to an area of memory on the heap, so it maintains a constant size no matter how many items it is referring to - since in reality it is basically just storing a single address of memory. (It obviously stores some more information than that, but I want to keep it simple)
So no matter what you do to _list, the result of sizeof will remain constant since the actual members within n remain constant size.
You can use the public method std::list::get_allocator to see where your data is stored.
Here is an example of how you can use it(but just to reaserch, It's not supposed to be used like that):
int main ()
{
int * ptr;
// allocate an array of 5 elements using _list's allocator:
ptr=_list.get_allocator().allocate(5);
// assign some values to array
for (int i=0; i<5; ++i) ptr[i]=i;
std::cout << "The allocated array contains:";
for (int i=0; i<5; ++i) std::cout << ' ' << ptr[i];
std::cout << '\n';
_list.get_allocator().deallocate(ptr,5);
return 0;
}
BTW: Is not a good idea to name members starting with underscore:
all identifiers that begin with an underscore are reserved for use as
names in the global namespace
Hello I am sorry this shouldn't be a hard problem. Im trying to get the pointer to call that objects function in the array. the block id is the key, however i cannot seem to get it running.
blocks* objects[28];
int index = 0;
for (int i = 0; i < 6; i++)
{
for (int j = i + 0; j < 6; j++)
{
objects[index] = new blocks(key, i, j);
key = key + 1; //used to make sure each block can id with a key
index = index + 1;
}
}
for (int i = 0; i < 28; i++)
{
double id = objects[i]->getblockid(); //FIXED
cout << "Object is: " << i << " id is: " << id << endl;
}
Are you saying that your code doesn't compile? It seems fine for me.
Howerver I can see see a few problems at runtime.
First, in inner loop you are instantiating block object 21 times, but you operate on only first 6 elements of this array. So when you are iterating from 0 to 28 in last loop, you will get exception thrown since 7th and further elements are not instantiated. This is because 7th element of this array is not instantiated. It points to some memory location which is just a garbage.
The other problem is that when you overwrite your pointers, you loose information of created objects, this causes memory leaks. Perhaps you should familiarize yourself with smart pointers concept?
Use std::vectors instead of vanila arrays. Alternatively use std::array.
You should also familiarize with concept of iterators.
I created this function to change the size of the dynamic array
size = 4; //this is what size is in my code
int *list = new int[size] // this is what list
void dynArray::doubleSize( )
{
int *temparray;
int currentsize = size;
int newsize = currentsize * 2;
temparray = new int[newsize];
for (int i = 0 ; i < newsize;i++)
{
temparray[i] = list[i];
}
size = newsize;
delete [] list;
list = new int[size];
list = temparray;
// this it help see if i made any changes
cout << sizeof(temparray) << "temp size:\n";
cout << sizeof(list) << "list size:\n";
cout << size << "new size:\n\n\n";
}
I want it to output the size of array is the function each time it changes size.I know this can be done with vectors but I would like to understand how to do it with arrays
what can I do differently to make this happen.
You can't: the C++ Standard provides no mechanism to access dynamic array dimensions. If you want to know them, you have to record them when creating the array, then look at the variables you set (much as you've got size hanging around for printing at the end of your program.
Problems in your code:
Problem 1
The following for loop accesses list using out of bound indices. Number of element in list is size, not newSize.
for (int i = 0 ; i < newsize;i++)
{
temparray[i] = list[i];
}
You need to change the conditionals to i < size;.
Then, you need to figure out how how to initialize the rest of the items in temparray.
Problem 2
The following lines cause a memory leak.
list = new int[size];
list = temparray;
You allocate memory using new and immediately lose that pointer in the second line.
Answer to your question
To print the new size, you can use:
cout << "new size: " << size << "\n";
However, I wouldn't recommend putting such code in that function. You are making your class dependent on std::cout for not much benefit, IMO.