Removing int value in dynamic array and setting it to NULL - c++

So my code is suppose to insert numbers into a dynamic array, add more capacity to the array if more is needed, remove numbers from the array and then make sure the only NULLS occur at the end of the array. It also tells the user how many numbers are in the array and what is the total size of the array. My problem is when I remove a number from the array, it sometimes prints out there is a number -33686019 in my array. This doesn't occur much, but I don't want it to occur at all.
#include <stdio.h>
#include <iostream>
int* gArray = NULL;
int gSize = 0;
int gCapacity = 0;
void Insert(int value);
void Remove(int value);
void Resize(int newCapacity);
void Print(void);
void main()
{
int input = 0;
while(input != 3)
{
printf(">=== Dynamic Array ===\n");
printf("What do you want to do?\n");
printf("1. Insert\n");
printf("2. Remove\n");
printf("3. Quit\n");
printf("Your choice: ");
scanf_s("%d", &input);
printf("\n\n");
int value = 0;
switch(input)
{
case 1:
{
printf("Enter a number: ");
scanf_s("%d", &value);
Insert(value);
Print();
break;
}
case 2:
{
printf("Enter number you wish to delete: ");
scanf_s("%d", &value);
Remove(value);
Print();
break;
}
case 3:
{
break;
}
default:
{
printf("Invalid selection\n");
}
}
}
}
void Insert(int value)
{
bool valueSet = false;
while(valueSet == false)
{
if(gArray == NULL)
{
Resize(1);
gArray[gSize] = value;
++gSize;
valueSet = true;
}
else if(gArray[gCapacity] == NULL)
{
gArray[gSize] = value;
++gSize;
valueSet = true;
}
else if(gArray[gCapacity] != NULL)
{
Resize((gCapacity + 1));
gArray[gSize] = value;
++gSize;
valueSet = true;
}
}
}
void Resize(int newCapacity)
{
int* tempArray = new int[newCapacity];
std::copy(gArray, gArray+(newCapacity-1), tempArray);
gArray = new int[newCapacity];
std::copy (tempArray, tempArray+(newCapacity-1), gArray);
gCapacity = newCapacity;
}
void Remove(int value)
{
for(int i = 0; i < gCapacity; ++i)
{
if(gArray[i] == value)
{
gArray[i] = NULL;
--gSize;
}
}
for(int i = 0; i < gCapacity; ++i)
{
if(gArray[i] == NULL)
{
gArray[i] = gArray[(i + 1)];
gArray[(i + 1)] = NULL;
}
}
}
void Print(void)
{
printf("Array contains: ");
for(int i = 0; i < gCapacity; ++i)
{
if(gArray[i] != NULL)
{
printf("%d, ", gArray[i]);
}
}
printf("size = %d, capacity = %d\n", gSize, gCapacity);
}

An option, since you are using the c++ standard library would be to remove all your code, and use std::list and its insert and remove methods. If you require the data to be in a dynamic array, then use std::vector and the erase remove idiom for removal.
I have to point out that, since your question is "Removing int value in dynamic array and setting it to NULL", that setting an int to NULL is essentially setting it to the value 0, since NULL tends to be a define for 0. So if your list were to contain zeroes, this setting to NULL and checking for equality with NULL would completely break the logic of your algorithm. C++11 has nullptr, an actual null type that cannot be assigned to an int, to deal with this kind of problem.

The concrete problem is that you don't initialize the new array (resp. tempArray) in your Resize function.
When calling
int* tempArray = new int[newCapacity];
the array can contain arbitrary values. Only newCapacity-1 values are copied from the old array, so the last value is undefined. It might be 0 but haven't to be. Use
std::fill(tempArray, tempArray+newCapacity, 0);
to initialize your array with zero.
Apart from that, there are a few other problems:
You don't delete the old array before allocating a new one. Use delete[] gArray for that. Also tempArrayisn't deleted!
You don't need to copy the values twice. Just to a gArray = tempArray (after deleting the old gArray, see above)
You assume that newCapacity is just larger by one than gCapacity (you copy newCapacity-1 values from the old array). It would be better to copy gCapacity values instead.
Dynamic arrays which only grow by one are inefficient, since adding a value takes linear time (you have to copy all the old values when inserting a single one). Usually, you double the size of the array every time you run out of space, this gives constant insertion time in average.
NULL is normally used only for pointers. For ints it is equal to zero which means, you cannot store 0 in your array (given your requirements)
In production code, I'd strongly recommend using std::vector instead of any home-grown solution.
EDIT
See #StackUnderflows answer for what is probably the real cause of the error. If you run in Debug mode, some compilers will automatically initialize the array for you, which might be the ccase here.
The gArray[i]=gArray[i+1] line in your Remove function is definitely wrong on the other hand, since it accesses a value which is beyond the limits of the array.

The problem occurs on the last iteration in the second loop of Remove when you do gArray[i] = gArray[i + 1]. On the last iteration, gArray[i + 1] is actually one past the end of your array, so you are now in undefined behavior territory. You are assigning this undefined value to the last element gArray[i].
I suggest using std::vector<int> instead. It manipulates an array under the hood which grows/resizes for you as you add more elements.

Related

Arrays with unknown size on Arduino

I'm doing an Arduino project and I need to pass arrays with different sizes as parameter to my function.
The problem is that std::vector is not an option.
How can I do that?
The fallback is to pass a pointer to the first element in the array and the size:
void foo(int* arr, size_t size);
The reason for std::vector not being available on some platforms is that on some platforms dynamic allocations is a bad idea. However, once you are dynamically allocating arrays:
int* x = new int[42];
foo(arr,42); // array decays to pointer
delete[] x;
then you could as well use std::vector.
If std::vector is not available to you, then either search for an alternative (maybe this?) or write your own. The pointer + size approach is fragile and not recommended unless absolutely necessary. The power of std::vector is from the abstract concept to encapsulate the array, its size and capacity. Nobody can prevent you to apply that concept even if you cannot use std::vector.
In case you are talking about statically sized arrays, then thats not quite the use case for std::vector. You do not need dynamic allocation, and you can pass arrays by reference. I won't repeat here what you can find in this answer (std::array) or here (c-arrays).
Something like this should work
template<size_t N>
void DaFunction(std::array<int, N>& daArray)
you can do it without having to deal with memory allocation or pointers just by creating a string variable and a limited size array and then you start shifting
#include <Arduino.h>
class ArrayShifter
{
private:
// String Reservoire Tank
String _text;
// a fixed size array of 5 in my case (depending on the amount of data you expect)
String _viewPortArray[5];
int _size = 0;
// Methode to fill the array
bool shiftArray(int position);
public:
ArrayShifter(/* args */);
// Method that gets the text from Serial
String getSerialText();
// get data from the array
String getArrayData(int index);
// array size getter
int getSize();
//clear the array
void clearArray();
//remove item
void removeArrayItem(int index);
};
ArrayShifter::ArrayShifter(/* args */)
{
}
String ArrayShifter::getSerialText()
{
// lesteing to the serial and returning the value
_text = Serial.readString();
return _text;
}
bool ArrayShifter::shiftArray(int position)
{
/*Assuming that the data is comming separated with ";" for each row and ":" for each value
to optimize the size of array in this way :
name:value;age:value;gender:value;
*/
String text = getSerialText();
int index = 0;
_size = 0;
if (text.length() > 0) // text isn't empty
{
if (position <= 5) // if the data belongs to the first 5 range
{
for (int i = 0; i < 5; i++)
{
// get the index of our separator that we've chosed to be ";"
index = text.indexOf(";");
if (index > 0)
{
// index found
_size++;
// putting the value before ";" in the array
_viewPortArray[i] = text.substring(0, index);
// deleting the value from the tank
text = text.substring(index + 1);
}
}
}
else
{
_size = 0;
// to wich range the desired index belongs
unsigned int dataRange = ((position - position % 5));
int ghostIndex = 0;
// looping throught all ";" to get indexes
for (int i = 0; i < dataRange; i++)
{
ghostIndex = text.indexOf(";");
if (ghostIndex > 0)
{
_size++;
text = text.substring(ghostIndex + 1);
}
}
// grabing just 5 of the data
for (int i = 0; i < 5; i++)
{
if (ghostIndex > 0)
{
_size++;
_viewPortArray[i] = text.substring(0, ghostIndex);
text = text.substring(ghostIndex + 1);
}
// updating ghost index
ghostIndex = text.indexOf(';');
}
}
return true;
}
return false;
}
String ArrayShifter::getArrayData(int index)
{
// turn the roulette
if (shiftArray(index))
{
if (index <= 5)
{
// yes we have this
return _viewPortArray[index];
}
else
{
// but we have to put it in the range of 5
index = index - 5;
return _viewPortArray[index];
}
}
}
int ArrayShifter::getSize()
{
return _size;
}
void ArrayShifter::clearArray()
{
for(int i = 0 ; i <5 ; i ++)
{
_viewPortArray->remove(i);
_size = 0;
}
}
void ArrayShifter::removeArrayItem(int index)
{
_viewPortArray->remove(index);
_size--;
}
main class :
#include <Arduino.h>
#include <ArrayShifter.h>
ArrayShifter array;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
while (!Serial){}
}
void loop() {
if(Serial.available()>0)
{
Serial.println(array.getArrayData(7));
int sizeOption2 = array.getSize();
Serial.println(sizeOption2);
array.removeArrayItem(7);
Serial.println(array.getArrayData(7));
}
}
please check my github repository
https://github.com/Riadam/ViewPort-Array-Shifter-for-Arduino-Uno.git

C++: Char pointer to char pointer array to char array

I'll do my best to be brief:
So I have an assignment where I am creating a 'Wordlist' class. In which I will store a list of words.
These are the member variables
class WordList
{ //...
unsigned int m_count; // Number of words currently in list
unsigned int m_max; // The total size of the list.
char** m_list; // The list storing the words
};
This is my constructor
WordList::WordList(const int max_words) {
if(max_words < 1){
m_list = nullptr;
m_max = 0;
m_count = 0;
}
else
m_list = new char*[max_words];
m_count = 0;
m_max = max_words;
for (int i = 0; i < max_words; i++) {
m_list[i] = new char[20];
}
}
And this is where I start to find problems.
The following add function is supposed to add a word in the form of a c-style string that is pointed to from the array of character pointers that is pointed to from **char m_list .
int WordList::add(const char word[]) {
if (m_count == 0 && m_list != nullptr ) {
strcpy (m_list[m_count], word);
m_count++;
return 0;
}
if (m_count < m_max) {
m_count++;
strcpy (m_list[m_count], word);
return 0;
}
if (m_count == m_max) {
m_count++;
m_max ++;
strcpy (m_list[m_count], word);
return 1;
}
if (strlen(word)==0) {
return -2;
}
if (m_list == nullptr ){
return -2;
}
else
return -2;
}
So the issue I am having is that I clearly not syntactically correct with my * because I am not getting an array of 5 pointers that point to full words rather I am getting the first letter saved to the final destination char but its not copying over everything like I want.
I'm sure I didn't translate my problem to English as well as I should have but hopefully thats a start. Thank you!
An example of how I will be calling my add function:
WordList *wordlist = new WordList(5);
wordlist->add("harry");
wordlist->add("ron");
wordlist->add("hermione");
And it should add to the bottom of the pointer array a pointer to each word
so
cout << wordlist->m_list[0][2] << endl; // Expect 'r'
cout << wordlist->m_list[1] << endl; // Expect "ron"
instead I get
r
printed out only
I don't see anything wrong with your use of double-pointers.
There are other issues, though:
in your WordList::add you should check for empty word or empty list first, and fail fast. Besides, in your code if the word was empty - you would already added it and returned form that function.
in if (m_count < m_max) block, you pre-increment m_count, leaving one element empty and risking to go out-of-bounds on the last entry.
in if (m_count == m_max) { you are CERTAINLY going out-of-bounds
Suggestion: instead of pre-allocating 20-character arrays, leave them nullptr; when you need to a word - use strdup(word); that would allocated a required space for you.
As for your I am getting the first letter saved - I am guessing you are not checking it right...
The problem is that you add the first word:
if (m_count == 0 && m_list != nullptr ) {
strcpy (m_list[m_count], word);
m_count++;
return 0;
}
Which increments m_count so now m_count is 1.
Then you add the second word:
if (m_count < m_max) {
m_count++;
strcpy (m_list[m_count], word);
return 0;
}
Which increments m_count BEFORE adding the word so the second word is at index 2 and index 1 is skipped altogether.
You need to always increment the count after copying the word because m_count is 1 based and the array is 0 based.

Function that checks if an array is sorted

So I'm just a beignner programmer when it comes to C++, and I have to write a function that checks if an int array is sorted using pointers (no index notations allowed), and here's what I have so far:
bool isSorted(const int *ar, int size) {
bool sorted = true;
const int *ptr1, *ptr2, *ptr3;
ptr1 = ar;
ptr2 = ar+1;
ptr3 = ar+size;
for (ptr1; ptr1 < ptr3; ptr1++) {
for (ptr2; ptr2 < ptr3; ptr2++) {
if (*ptr1 > *ptr2) {
sorted = false;
}
}
}
return sorted;
}
However, I can't seem to get it to work as it always returns true regardless of whether the array is sorted or not. Any help is appreciated, thanks.
"The more you overthink the plumbing, the easier it is to stop up the
drain" -- Scotty, Star Trek III.
You are making this much more complicated than it has to be.
Ask yourself a basic question: what is a sorted array?
Answer: an array in which each successive element is not less than its preceding element.
Therefore: to check if the array is sorted, just look for an element that's less than its previous element. If you found one, the array is not sorted. If you couldn't find one, the array must be sorted.
bool isSorted(const int *ar, int size) {
if (size == 0)
return true; // Edge case
int previous_value= *ar;
while (size)
{
if (*ar < previous_value)
return false;
previous_value= *ar;
++ar;
--size;
}
return true;
}
No index notations, just a single pointer. No need to do any kind of a nested search, etc... If you want to use only pointers, you could do this:
bool isSorted(const int *ar, int size) {
const int *previous_value=ar;
while (size)
{
if (*ar < *previous_value)
return false;
previous_value= ar;
++ar;
--size;
}
return true;
}
Actually, I like this version even better.
You should keep ptr2 always be ptr+1,so you need to initialize ptr2 in second for() .
And I think only one loop is better.
for(; ptr2 < ptr3; ++ptr1, ++ptr2) {
if (*ptr1 > *ptr2) {
sorted = false;
}
}
return sorted;

proper usage of the remove() function?

i'm working on this personal project and i'm a bit confused on how the remove() function works.
header:
class IntSet {
public:
IntSet(); //Constructor
~IntSet(); //Destructor
int size() ; //
bool isEmpty();
bool contains(int number1);
void add(int number2);
void remove(int number2);
private:
int* ptr; //pointer to the array
int sizeOfArray; //current size of the array
int currentValue; //number of values currently in IntSet
};
main (only including add() part)
#include "IntSet.hpp"
#include <iostream>
IntSet::IntSet(){
sizeOfArray = 10;
currentValue = 0;
ptr = new int[10];
}
IntSet::~IntSet(){
delete[] ptr;
}
//returning the number of values in the IntSet
int IntSet::size()
{
return currentValue;
}
//Determining whether the stack is empty
bool IntSet::isEmpty()
{
if (currentValue == 0)
return true;
else
return false;
}
//defining contains() function
bool IntSet::contains(int number1)
{
for (int i = 0; i < currentValue; i++)
{
if (ptr[i] == number1)
return true;
}
return false;
}
//defining add() function
void IntSet::add(int number2)
{
if (currentValue == sizeOfArray)
{
sizeOfArray = sizeOfArray * 2; //doubling size of arrayCapacity
int* temp = new int[sizeOfArray]; //allocating new one that's twice as large
for (int i = 0; i < currentValue; i++)
{
temp[i] = ptr[i]; //copying old stuff into new one
}
delete[] ptr; //deallocate old array
ptr = temp; //set ptr to new array
}
}
//defining remove() function goes here
So for the add() function I had to take an int parameter add it to the array. When it gets full I have to double the size of the array, copy the contents of the old array into the new one, redirect the data member pointer to the new array and then deallocate the array.
For the remove() function I have to just take an int parameter and remove it from the IntSet by shifting over all the subsequent elements of the array. Should I just use parts of my add function and pretty much tell it to do the opposite for my remove() function? If not, how do I even begin to write the remove() function? I'll show the rest of my code if needed. Thank you guys so much!
Give this a try for removing:
void IntSet::remove(int number2)
{
bool bIntRemoved = false;
for(int i=0; i < currentValue; i++){
// check if we are currently searching or shifting
if(!bIntRemoved){
// still searching
// check if we should remove int at current index
if(ptr[i] == number2){
// found the int to remove
// We'll decrement i and set bIntRemoved = to true
// So the else-if code handles shifting over the array
i--;
bIntRemoved = true;
}
}else if(i < currentValue-1){
// We have spots to shift
// Check if this is the last index
ptr[i] = ptr[i+1];
} // else, we are at the last index and we have nothing to shift
}
if(bIntRemoved){
// The int was successfully located and any necessary shifting has been
// executed. Just decrement currentValue so the current last index will be
// disregarded.
currentValue--;
} // else, the int to remove could not be located
}
I haven't tested, but in theory, this should locate the first instance of the int you need to remove, shift all values left by one spot (unless the int to remove is in the last index of the array), and then decrement the currentValue variable so the previous last index of the array is disregarded and can be overwritten. Anyway, sorry if that's a poor explanation, but it's not the easiest concept to explain. I attempted to document the code fairly well, so hopefully that will make sense :P Let me know if you have any questions and let me know if this works or doesn't work for you (I find feedback to be very important.)
EDIT: Also, I intended to mention this, but I forgot, so thank you, #Viet, for mentioning this in your answer, your add() function does not seem to handle cases when the currentValue is less than the size of the array. I assume you are already handling that and you just omitted the else statement that takes care of it?
EDIT #2:
The following is code to properly handle adding new elements to the array:
void IntSet::add(int number2){
if (currentValue == sizeOfArray)
{
sizeOfArray = sizeOfArray * 2; //doubling size of arrayCapacity
// nothrow is used below to allow for graceful error handling if there is not enough
// ram to create the new array
int* temp = new (nothrow) int[sizeOfArray]; //allocating new one that's twice as large
// check if new int array could be create
if(temp == nullptr){
// new int array could not be created
/** Possibly set an error flag here or in some way warn the calling function that
the function failed to allocate the necessary memory space.
I'll leave that up to you, OP. **/
// Right now we'll just return without modifying the existing array at all
return;
}
for (int i = 0; i < currentValue; i++)
{
temp[i] = ptr[i]; //copying old stuff into new one
}
delete[] ptr; //deallocate old array
ptr = temp; //set ptr to new array
// Now we'll just let the code below add the number to the array
} // else we have enough space to add the number to the array
ptr[currentValue] = number2;
currentValue++;
}
Again, I have not tested this code, but let me know if it works or does not work for you. Also, I modified the line that makes a new array (int *temp = new int[sizeOfArray];) to now handle errors if memory cannot successfully be allocated. To do this I am using the (nothrow) object (more on that on this CPlusPlus page). If allocation fails, a temp is set to a null pointer. Without this, the method would instead throw a bad_alloc exception or the program would terminate. That's not very graceful, so I prefer properly handling the error (and handling it in a way that is less strenuous on the calling function). To use this, you will need to include the <new> header (which is where nothrow is defined).
Is your class is a set or a list? If your class is a set, it mean there are no same numbers in your class
Example: a set {1, 2, 3}, a list: {1, 2, 3, 1, 3, 2}
About your add function, i have some comments:
You does not check new element exist in your set
You does not increase current size and set value for new element in your set
You can use memcpy function to copy old data to new data pointer
About remove function, i have some ideas:
At first, you must find the position of number which need to be delete in current set
After that, you remove that number by shift left all member from next position of number which need to be delete to the left position. And you must decrease current size by 1
Example: you have a set {1, 2, 3, 4}, current size is 4. And you want to remove a number "2"
First, you find the position of 2 in your set. It is 1 (because the start index of array is start from 0)
Second, you remove it by pushing back all the values from next position on the front of its in your set.
Ex: the value of position 1 replaced by value 3, the value of position 2 replaced by value 4
Finally, you decrease current size by 1. Now, current size is 3, and you have a new set {1, 3, 4}

Linked list without struct

Can anyone help me with a singly linked list? I know how to do it with struct, but now i wanna know how to do it with only arrays and pointers without struct or nodes.Algorithms please thank you.
#include <iostream>
using namespace std;
const int size=5;
int data[size];
int *mem;
int add[size];
int top = -1;
void AddLast(int value)
{
if(top==-1)
{
top=data[value];
}
else
{
top++;
top=data[value];
}
}
void print()
{ cout << "Queue: ";
for(int i = 0; i != top; i = (i + 1) % size)
{
cout << data[i] << "->";
}
cout << endl;
}
int main()
{
AddLast(2);
print();
AddLast(3);
print();
AddLast(4);
print();
cin.get();
return 0;
}
I want to addlast, addfirst, and add sorted... is this the way?
You can't do it with only one array, you need at least two: One for the data and one for the links. If you don't want to use structures at all (though I don't really see the reason for it) you could have multiple data arrays.
The data array contains the actual data, it's nothing special with it. The link array contains indexes to the data array, where each index is a "next" pointer.
For example, lets say you want to have a linked list of integers, and you have three integers in the list (their values are irrelevant), lets call that data array d, then you have d[0], d[1] and d[2]. The first node in the list is d[1], followed by d[0] and last d[2]. Then you need a head variable, which tells which index is the head of the list, this head variable is initialized to 1 (and "points" to d[1]). Then we have the link array, lets call it l, since the head is "pointing" to 1 we fetch l[1] to get the next node, the contents of l[1] is 0 which tells us the next node is d[0]. To get the next node we check l[0] which gives us 2 for d[2]. The next link, l[2] could be -1 to mark the end of the list.
Of course, the data array(s) and the link array needs to be of the same size.
An array s of structs with members A, B, C, can be emulated by three arrays a, b and c, where e.g. a[i] represents s[i].A, and so forth. So that's your requirement of no structs. Then doing a linked list with arrays, i.e. with indices instead of pointers, is mere notation; the concepts are exactly the same. But you might look up the technique of using a free list, a list of available logical nodes; this allows you to free nodes as well as allocate them, in a simple way.
There is a (ugly) way to do a linked list with arrays.
Here is an example of how you might do something with arrays but I would never recommend even thinking about doing it.
template<class T>
typedef char[sizeof(T) + sizeof(uintptr_t)] listNode;
template<class T>
listNode<T>* getNext(const listNode<T>& x){
return (listNode<T>*)(((char*)x)[sizeof(T)]); //notice how you have to increment the pointer address
}
template<class T>
T& getValue(listNode<T>& x){
return (T) x;
}
That's way too many casts. It's less ugly if you make an array of two pointers and just cast the first value in a pointer on what you care about but that's still not what I would recommend.
This is a hack of sorts might help with your curiosity.
It is similar in implementation to how linked lists are typically implemented with struct.
#include<stdio.h>
#include<stdlib.h>
int * base = NULL;
int ** current = NULL;
void add(int num)
{
if(base==NULL)
{
base = (int*)malloc(sizeof(int)*3);
base[0] = num;
current = (int**)(base+1);
current[0] = NULL;
}
else
{
current[0] = (int*)malloc( sizeof(int)*3 );
current[0][0] = num;
current = (int**)(*current+1);
current[0] = NULL;
}
}
void show()
{
if(base != NULL)
{
int * data = base;
int ** tmp = (int**)(base+1);
if(tmp[0]==NULL)
printf("%d\n",data[0]);
else
{
do
{
printf("%d ",data[0]);
data = tmp[0];
tmp = (int**)(data+1);
}while(tmp[0]!=NULL);
printf("%d\n",data[0]);
}
}
}
int main()
{
int choice,num;
do
{
scanf("%d",&choice);
switch(choice)
{
case 1:scanf("%d",&num);
add(num);
break;
case 2:show();
}
}while(1);
return 0;
}
It is possible to add other function like addFirst() or addSorted() but will require some more pointer manipulation, for which I don't possess the dedication right now.