I'm trying to write a class that contains an array of numbers that you can sort with a function myArray.quicksort().
When creating a new Objekt of Array I pass the constructor the length and then fill it:
public: int Items[];
/*-- Constructor --*/
Array(int n){
length = n;
for(int i=0; i<length; i++){
int zahl;
Items[length];
cout << "Item" << i << ": ";
cin >> number;
Items[i] = number;
}
...
Right after creating the Array this function to print it out works just fine:
void Array::show(){
for(int i=0; i<this->length; i++){
cout << this->Items[i] << " ";
}
}
However after I try to sort it it prints out nonsense:
void Array::quickSort(int left, int right){
int i=left, j=right;
int tmp;
int pivot = this->Items[(left + right) / 2];
while(i <= j){
while (this->Items[i] > pivot)
i++;
while (this->Items[j] < pivot)
j--;
if (i <= j) {
tmp = this->Items[i];
this->Items[i] = this->Items[j];
this->Items[j] = tmp;
i++;
j--;
}
};
if (left < j)
quickSort(left, j);
if (i < right)
quickSort(i, right);
}
I'm sure I totally mix up something with the array pointers..
But I can't seem to find a solution for it.
Where is the big flaw here?
Standard C++ does not have flexible array members (like C99 has).
You don't need your Array class, use std::vector<int> instead (or perhaps std::array with C++11 if the array length is a compile time constant)
If you want to declare your Array class containing Items, follow the hints in the comment of Joachim Pileborg, learn about the rule of three (in C++11, it became the rule of five), so declare:
int *Items;
in your class, then initialize it with
Items = new int[n];
in its constructor[s], and destroy it with
delete [] Items;
in your destructor.
Related
i keep getting garbage value on one of the indexes in the dynamic array when i try to remove a value which was entered by user from a list of elements in the dynamic array.
used pointer as function parameters and replaced the value to be removed with 0 and by using a counter and for loop tried to skip all the 0s but in place of zero theres a garbage value.
#include<iostream>
#include<fstream>
using namespace std;
int size = 0;
int final = 0;
int* read(ifstream& a){
int temp;
a.open("data(1).txt");
while (!a.eof()){
a >> temp;
size++;
}
a.close();
a.open("data(1).txt");
int* arr = new int[size];
for (int i = 0; i < size; i++)
a >> arr[i];
return arr;
}
int* remove(int* a,int search){
for (int i = 0; i < size; i++){
if (a[i] == search)
a[i] = 0;
else final++;
}
int* change = new int[final+1];
for (int i = 0; i < size; i++){
if (a[i] > 0){
change[i] = a[i];
}
else continue;
}
delete[] a;
a = nullptr;
return change;
}
int main(){
int* ptr = nullptr;
int num;
cout << "please enter the number to remove: ";
cin >> num;
ifstream in;
ptr=read(in);
ptr=remove(ptr, num);
for (int i = 0; i < final; i++)
cout << ptr[i] << " ";
cout<<endl;
system("pause");
return 0;
}
There is much to discuss and critize about your code. Also your question is very unclear because we do not have your input file, nor do you tell us what the code should actually do. However, I will leave all "please write actual c++ rather than c without classes" aside and just point you to the one critical mistake:
This loop
int* change = new int[final+1];
for (int i = 0; i < size; i++){
if (a[i] > 0){
change[i] = a[i];
}
else continue;
}
And then this loop
for (int i = 0; i < final; i++)
cout << ptr[i] << " ";
It seems like you want to copy all elements that are >0 to change. Or maybe you want to copy all, its really hard to tell, because broken code is just broken, it does not explain itself. Anyhow...
The first loop leaves all elements change[i] where a[i] <= 0 uninitialized. The values at those indices i are indeterminate. There isn't really a value you can read. Attempting to read an indeterminate value results in undefined behavior.
You are attempting to read all elements of change, but some of them are not initialized, they are indeterminate values. Hence your code has undefined behavior.
There are other situations the will bring your code into bad states, like for example search not begin found in the input array or a[i] > 0 for some i > final. Though, I don't see a possiblity for any input to your code that would not eventually invoke undefined behavior.
You sould use a debugger to see where your code is doing something unexpected.
I've tried the (somewhat questionable) convention of deleteing after usage, but that doesn't seem to work. The program is supposed to receive an input of a single integer, sort a randomly created array, and print elapsed time for sorting, yet when I leave the delete in there, the program abnormally ends without even a warning after I do the input. In other words, it crashes. However, when I comment out just the delete line, the program executes perfectly.
The MWE is measuring time for a simple Quick Sort Algorithm, and since this is a school project I cannot change the main() function and using the QuickSort class and its pointers, etc..
The only things I can change are the stuff that goes in the various functions, and although it does seem that set(double*, int) can just be integrated into the constructor, that's not a possible option here for some reason.
The objective is to define a default double* in the constructor, and then delete it and copy input_array into this->arr in set:
EDIT: I use Windows 10 and the GCC C++ Compiler from MinGw-w64. All compilations have been executed in the Windows Command Prompt.
main.cpp
#include <iostream>
#include <cstdlib> // Just for good measure, though this shouldn't be needed
#include "Sort.hpp"
bool check_quick(QuickSort *quick_sort) {
int i = 0;
while(i < (quick_sort->size) - 1) {
if (quick_sort->arr[i] > quick_sort->arr[i + 1]) break;
++i;
} if (i == (quick_sort->size) - 1) return true;
else return false;
}
int main() {
int n; cin >> n;
double *input_array = new double[n];
srand((unsigned int)time(NULL));
for (int k = 0; k < n; k++) input_array[k] = (double)((rand() % n));
QuickSort* quick_sort = new QuickSort();
quick_sort->set(input_array, n);
quick_sort->run();
if (check_quick(quick_sort)) {
cout << "QuickSort is validated" << endl << endl;
} delete quick_sort;
}
Sort.hpp
#define CLOCKS_PER_SECOND 1000
#include <iostream>
#include <ctime>
#include <iomanip> // Use to call setprecision(4)
using namespace std;
class QuickSort {
friend bool check_quick(QuickSort*); // Give access for private variables
public:
void print_time() const {
cout << "QuickSort : " << fixed << setprecision(4) << seconds
<< " sec" << endl;
// << fixed << setprecision(4) always prints to four numbers after point
}
QuickSort() {
this->arr = new double[10];
for (int i = 0; i < 10; ++i) this->arr[i - 1] = i; // Set default array
seconds = clock(); // Set current Millisecond to starting time
}
~QuickSort() {
delete this->arr; // Delete array in object of this class
}
void sorter(double *arr, int begin, int end) { // Sorting Recursive Function
// Size of array without pivot is: end - begin
int pivot = arr[end];
// PIVOT is element at end of subarray "arr[begin...end]"
int i = begin, j = end;
while (i <= j) {
while (arr[i] < pivot) i++; // Increment until arr[i] is larger than
while (arr[j] > pivot) j--; // Decrement until arr[j] is lesser than
if (i <= j) { // If the larger element precedes lesser element
swap(arr[i], arr[j]); // Call Swap function
i++; j--;
} // If i is larger than j now, i was 1 lesser than j before,
// effectively leaving no more elements to scan.
}
if (begin < j) sorter(this->arr, begin, j); // Recursive, larger part
if (end > i) sorter (this->arr, i, end); // Recursive, lesser part
}
void run() {
sorter(this->arr, 0, this->size - 1); // Call Sorter function
seconds = (double)(clock() - seconds) / (double)(CLOCKS_PER_SECOND);
// Calculate Difference of Ticks and divide by Ticks per second.
// Now, `seconds` is passed seconds with millisecond precision.
}
void set(double *arr, int size) {
this->arr = new double[size]; // Make new array of `size` size
for (int i = 0; i < size; i++) this->arr[i] = arr[i]; // Copy input_arr
for (int i = 0; i < size; i++) cout << this->arr[i] << endl; // Copy input_arr
this->size = size; // Save global `size` to object of class
}
void swap(double &p, double &q) { // Swap Function
// Ampersand precedence to change input
double x = p; // Temporary `double` saver
p = q; // p is q
q = x; // q is x, which is p
}
private:
double *arr;
int size;
double seconds;
};
In your QuickSort constructor you are writing outside the bounds of the array that you are allocating:
this->arr = new double[10];
for (int i = 0; i < 10; ++i) this->arr[i - 1] = i; // Set default array
In the first iteration i is 0 so this->arr[i - 1] writes to the element -1. This is only crashing when you call delete as if you don't the runtime doesn't notice this corruption and exits cleanly.
Presumably just changing i-1 to i will produce the desired behaviour.
The first line of QuickSort::set:
this->arr = new double[size]; // Make new array of `size` size
leaks the array allocated in QuickSort's constructor. You need to delete[] that array first, before assigning arr to point to another one:
delete[] arr;
this->arr = new double[size]; // Make new array of `size` size
If this were the real world, and not a shcool assignment, it would be much better not to use a raw pointer in this case. Rather, a std::vector<double> would be much more appropriate.
A quick look reveals that you are using delete instead of delete[]..
this line:
delete this->arr; // Delete array in object of this class
should be:
delete[] this->arr; // Delete array in object of this class
Additionally, as per the convention of delete you should also do this:
delete[] this->arr;
this->arr = nullptr; // This is important, else your are double deleting which is calling for trouble.
I am trying to implement a binary tree as a 2d array. I want the user to enter the required height of the tree and the program should give an appropriate size array. Then, I want to print the array, which is why I need to pass it as a parameter. However, I get the following error:
arrayTree/main.cpp|19|error: cannot convert ‘std::__cxx11::string** (*)[maxNumberOfNodes] {aka std::__cxx11::basic_string<char>** (*)[maxNumberOfNodes]}’ to ‘std::__cxx11::string** {aka std::__cxx11::basic_string<char>**}’ for argument ‘1’ to ‘void printTree(std::__cxx11::string*)’|
Please, what is causing the error and how can I fix it?
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
void printTree(string** tree);
int main()
{
int treeHeight = 0;
int maxNumberOfNodes = 1;
cout << "enter tree height";
cin >> treeHeight;
cout << treeHeight<< "\n";
//create an array that can hold every combination for a given tree height
maxNumberOfNodes = pow(2,treeHeight) - 1;
string** tree [3][maxNumberOfNodes];
cout << maxNumberOfNodes;
printTree(tree);
}
void printTree(string** tree){
//not fully implemented yet
for(int i=0; i < sizeof(tree); i++){
cout << "*" << " ";
}
}
string** tree [3][maxNumberOfNodes];
is the syntax of a static 2D array of type string** , where both dimensions have to be declared const.
The difference between a static and a dynamic array is shown in here: Multidimensional variable size array in C++
Instead you want to write something like
string** tree = new string*[3];
for(int i = 0; i < 3; i++)
tree[i] = new string[maxNumberOfNodes];
As #Remy Lebeau commented: Every occurrence of new[] needs to be answered by a delete[] call, like this:
for (int i = 0; i < 3; i++)
delete tree[i];
delete[] tree;
to remove the dynamic allocation from the heap.
Like #drescherjm pointed out sizeof(tree) is not valid, as tree is just a pointer and does not include size information about the array.
You could solve this by additionally passing the dimensions of your array with it:
void printTree (string** tree, int dim, int dim2)
and rewriting the loop to
for(int i = 0; i < dim; i++){
for(int j = 0; j < dim2; j++){
cout << tree[i][j]; //...
}
}
string** tree [3][maxNumberOfNodes];
This declares a 2D array of string** pointers. That is not what you want. You want a 2D array of string objects instead, so drop the pointers:
string tree [3][maxNumberOfNodes];
Also, your printTree() is not implemented correctly. It would need to be implemented more like this instead:
void printTree(string** tree, int height) {
for(int i = 0; i < 3; i++) {
for(int j = 0; j < height; j++) {
// use tree[i][j] as needed ...
}
}
}
That being said, since the value of maxNumberOfNodes is not known until runtime, the string tree [3][maxNumberOfNodes] syntax is declaring a Variable Length Array, which is not officially supported by the C++ standard, only as an extension by a few C++ compilers. You need to use new[] instead to allocate the 2nd dimension:
string* tree [3];
for(int i = 0; i < 3; ++i)
tree[i] = new string[maxNumberOfNodes];
printTree(tree, maxNumberOfNodes);
for(int i = 0; i < 3; ++i)
delete[] tree[i];
Or better, use std::vector instead:
std::vector<string> tree [3];
for(int i = 0; i < 3; ++i)
tree[i].resize(maxNumberOfNodes);
Though, in this latter case, you won't be able to pass tree to a string** function parameter, so you will have to adjust the code accordingly.
the method call is given by
printTree(tree [3][maxNumberOfNodes]);
it's working for me
For this assignment, I need to make a sorted copy of an array the user has given values to. All of my code works as intended, except for this specific part. I need this function (sortedCopy) to print out the sorted version of their array, without actually changing the array itself. As far as I can tell, to do so I need to used a constant version of the array in the function so the prototype would be something like: int *sortedCopy(const int *array, int size), but all this does is give the error shown in the title. Specifically:
main.cpp:72:29: error: assignment of read-only location '*(array +
((sizetype)(((long unsigned int)i) * 4)))' array[i] = array[min]
and it does this error twice, except with array[min] = temp; at the end instead
This is the code used, with the relevant parts of main:
#include <iostream>
using namespace std;
int* sortedCopy(const int *array, int size) {
int i, j, min, temp;
for (i = 0 ; i < size - 1; i++) {
min = i;
for (j = i + 1; j < size; j++) {
if (array[j] < array[min]) {
min = j;
}
}
temp = array[i];
array[i] = array[min];
array[min] = temp;
}
cout << "Sorted array is: " << endl;
for(int i = 0; i < size; i++) {
cout << array[i] << " ";
}
cout << endl;
// Not sure if I need to return anything or not either
}
int main() {
cout << "Please enter the size of the array." << endl;
int arraySize;
int array[arraySize];
cin >> arraySize;
cout << "Please enter integer values until the array is filled." << endl;
for (int i = 0; i != arraySize; i++) {
cout << "Value " << (i + 1) << ": ";
cin >> array[i];
cout << endl;
sortedCopy(array, arraySize);
for (int i = 0; i != arraySize; i++) { // I want this part to print the
cout << array[i] << " "; // original array entered by the user
}
}
If I remove the const part of the function, it works totally fine, except it will print the sorted array after the function is called, instead of the original array.
Firstly, C/C++ is best read "top-down":
int arraySize;
int array[arraySize]; // arraySize is undefined here!!
cin >> arraySize;
On the second line, ArraySize, might be 1, or 0, or -1000. You haven't defined it until line 3.
Also, C++ doesn't allow you to allocate arrays of variable size (unless that size is const [ so it is known at compilation time]):
int array[4];
The above is fine. This helps the operating system know how much memory to provide for you on the stack (it needs to do this before your programme starts running).
const int arraySize = 4;
int array[arraySize];
Because the C++ compiler knows that arraySize is 4, it processes this just like the above code, so this is also fine.
So to handle arrays of genuinely variable length (length that depends on inputs), you need to first read the user inputs, then use dynamic allocation ("new", or a container that does dynamic allocation for you, like a vector).
As for the problem with "const", what I think that you need to understand here is that "const" is really just a promise from the programmer: The programmer is communicating to the compiler (and any programmers reading the code) that this data is not supposed to change. All the compiler does is check whether you keep your promise (or if you send it to another function / pointer that doesn't hold that promise). So by using "const" there is no work done being done for you to actually keep the data constant - just that it will complain if you don't do the work.
int* sortedCopy(const int *array, int size) {
Above you're flagging to the compiler that the sortedCopy function will keep the data in the array constant.
array[i] = array[min];
array[min] = temp;
And here (above) you are breaking that promise.
If you don't want to edit the original array, then the easiest solution is just to copy it before you send it to your sorting function.
I'm new to c++ and I'm writing an array manipulator program. How would you write a function that removes an element from an array? What parameters would you pass to it? The function cannot have any cout or cin statements, they must be in main instead. How would you call the function? I wrote a function for adding an element to an array, and it looks like this:
int insertValue(int arr[], int value, int pos, int size)
if (size == 10)
cout << "Array full" << endl;
else
{
int i;
for (i = size - 1; i >= pos; --i) {
arr[i + 1] = arr[i];
}
arr[pos] = value;
++size;
}
cout << endl;
return size;
This function works when called. Would removing an element from an array and moving everything to the left follow the same layout? This is what I have so far for that function:
int removeValue(int arr[], int value, int pos, int size)
for (int i = pos; i < size; ++i) {
array[i] = array[i + 1];
}
arr[pos] = value;
return size;
I don't think I have the right idea for this code, which is why I am confused. Can someone explain the idea behind this function and how it would be written correctly?
Thanks for your help!
Use std::vector or std::array instead of c-array([]).
To remove elements from container, you should use std::vector + std::remove + std::vector::erase
This line is going to overflow the array, with all the attended horrors, as you are indexing one past the end.
array[i] = array[i + 1];
But other than that as long as you keep track of how many elements your array has it should be OK