Pointer Array Sorting Algorithm in C++ - c++

hoping I can get a little advice on a sorting method I made.
This is just a test for another program i am making and this test has a bug I can't figure out. The purpose of this code is to create a int pointer array and sort the pointers in that array by the contents of regular int array.
The bug is for my second for loop which doesn't allow me to use a j!=-1 therefore not allowing me to sort the first element of the array. Please help. Thanks!!
//create array
int c[8] = {3,1,5,7,8,2,6,4};
//create pointer array
int *newptr[8];
for(int k = 0; k<8; k++)
{
newptr[k] = &c[k];
}
//sort pointer array
for(int j = 0; j<8; j++)
{
cout << "test1\n\n";
cout << *newptr[j] << "and" << *newptr[j+1];
for(;*newptr[j] < *newptr[j+1] && j!=0; j--)
//using j!=-1 doesn't work which causes me to not be able to sort the first element
//in the array properly
{
cout<< "test2";
int *temp;
temp = newptr[j+1];
newptr[j+1] = newptr[j];
newptr[j] = temp;
}
}**

Order matters.
Change
for(;*newptr[j] < *newptr[j+1] && j!=0; j--)
to:
for(; j != -1 && *newptr[j] < *newptr[j+1]; j--)
Presumably the bug is something that causes the code to crash. This happens because the expression in the for loop is evaluated left-to-right. So *newptr[j] is evaluated before checking if j != -1. So it's conceivable that, at some point, j is equal to -1 when *newptr[j] is evaluated, which is illegal.
Changing the order does make a difference for a second reason: short-circuit evaluation.
When evaluating two an expression made of two conditions A and B, C++ does not always need to evaluate both conditions.
For example in the statement
if (A && B) {
//do something
}
if A is evaluated to be false, then obviously A && B cannot evaluate to true regardless of what B evaluates to. So B's value is never even checked. So in your case, in the expression
j != -1 && *newptr[j] < *newptr[j+1]
if j != -1 is false, C++ will not need to evaluate the rest of the expression in order to know that the whole expression is false. So *newptr[j] never happens and you don't get the bug.

As pointed out by maditya the problem is that the expression tries to access an invalid index before checking the index itself but I see the question is tagged C++. Do you have any explicit reason to not use STL?
struct sorter {
bool operator() (const int* i, const int* j) { return (*i<*j);}
};
int c[8] = {3,1,5,7,8,2,6,4};
int *newptr[8];
for(int k = 0; k<8; k++)
newptr[k] = &c[k];
std::sort(newptr, newptr+8, sorter());
or even shorter in C++11:
int c[8] = {3,1,5,7,8,2,6,4};
int *newptr[8];
for(int k = 0; k<8; k++)
newptr[k] = &c[k];
std::sort(newptr, newptr+8, [](const int *i, const int *j){return *i < *j;});

Related

My array is gettting an error because it's being defined as a singular integer

The point of this program is to output whether a series of digits (the number of digits undefined) is sorted or not (largest to smallest or smallest to largest).
I have defined my array in my function parameter, and I am trying to use a for loop to store the user's input, as long as it is above 0, in said array.
However, I am getting the error argument of type int is incompatible with parameter of type int*.
The exact error is the argument of type int is incompatible with parameter of type int*.
It is referring to line 22 and 23, these two;
isSorted(list[2000]); and
bool is = isSorted(list[2000]);.
I know this means my for loop is assigning a single value to my variable repeatedly from reading similar questions however I can not figure out how to fix this.
#include <iostream>
using namespace std;
bool isSorted(int list[]);
int main()
{
int i;
int list[2000];
int k = 0;
for (i = 0; i < 2000; i++)
{
int j;
while (j > 0)
{
cin >> j;
list[i] = j;
}
}
isSorted(list[2000]);
bool is = isSorted(list[2000]);
if (is == true)
cout << "sorted";
else
cout << "unsorted";
return 0;
}
bool isSorted(int list[])
{
int i = 0;
for (i = 0; i < 2000; i++)
{
if (list[i] > list[i + 1] || list[i] < list[i - 1])
{
return false;
}
else
return true;
}
}
I removed unused variable k.
Made 2000 parameterized (and set to 5 for testing).
In isSorted you are not allowed to return
true in the else as if your first element test would end in else you would return true immediately not testing other elements. But those later elements can be unsorted as well.
In isSorted you are not allowed to run the loop as for(i = 0; i < 2000; i++), because you add inside the for loop 1 to i and end up querying for i == 1999 list[2000], which is element number 2001 and not inside your array. This is correct instead: for (i = 0; i < 1999; i++). You also do not need to check into both directions.
You cannot call isSorted(list[2000]) as this would call is sorted with an int and not an int array as parameter.
You write int j without initializing it and then query while j > 0 before you cin << j. This is undefined behaviour, while most likely j will be zero, there is no guarantee. But most likely you never enter the while loop and never do cin
I renamed the isSorted as you just check in your example for ascending order. If you want to check for descending order you are welcome to train your programming skills and implementing this yourself.
Here is the code with the fixes:
#include <iostream>
using namespace std;
bool isSortedInAscendingOrder(int list[]);
const int size = 5; // Set this to 2000 again if you want
int main()
{
int i;
int list[size];
for (i = 0; i < size; i++)
{
int j = 0;
while(j <= 0)
{
cin >> j;
if(j <= 0)
cout << "rejected as equal or smaller zero" << endl;
}
list[i] = j;
}
if (isSortedInAscendingOrder(list))
cout << "sorted" << endl;
else
cout << "unsorted" << endl;
return 0;
}
bool isSortedInAscendingOrder(int list[])
{
for (int i = 0; i < size -1; i++)
{
if (list[i] > list[i + 1])
{
return false;
}
}
return true;
}
This is a definition of an array of 2000 integers.
int list[2000];
This is reading the 2000th entry in that array and undefined, because the highest legal index to access is 1999. Remember that the first legal index is 0.
list[2000]
So yes, from point of view of the compiler, the following only gives a single integer on top of being undefined behaviour (i.e. "evil").
isSorted(list[2000]);
You probably should change to this, in order to fix the immediate problem - and get quite close to what you probably want. It names the whole array as parameter. It will decay to a pointer to int (among other things loosing the information of size, but you hardcoded that inside the function; better change that by the way).
isSorted(list);
Delete the ignored first occurence (the one alone on a line), keep the second (the one assigning to a bool variable).
On the other hand, the logic of a your sorting check is flawed, it will often access outside the array, for indexes 0 and 1999. I.e. at the start and end of your loop. You need to loop over slightly less than the whole array and only use one of the two conditions.
I.e. do
for (i = 1; i < 2000; i++)
{
if (list[i] < list[i - 1])
/* ... */
The logic for checking ascending or descending sorting would have to be more complex. The question is not asking to fix that logic, so I stick with fixing the issues according to the original version (which did not mention two-way-sorting).
You actually did not ask about fixing the logic for that. But here is a hint:
Either use two loops, which you can break from as soon as you find a conflict, but do not return from the fuction immediatly.
Or use one loop and keep a flag of whether ascending or descending order has been broken. Then return true if either flag is still clear (or both, in case of all identical values) or return false if both are set.

Function returning the wrong value

This project is a homework assignment for school. The instructor has asked us to input 20 random integers then print the smallest in the list and then search the list for the first iteration of the number entered. My problem is returning the smallest number of the list. The function, shown below accepts an integer array and an integer with the size of the array. In Visual Studio, the tests for the smallest number work until the function returns the value. Instead of returning the smallest number, the function returns some kind of default value as opposed to the smallest integer. I have been staring at this code for the past two hours, any help would be appreciated.
int theSmallest(const int a[], int number_used)
{
int temp = a[0];
// Find the smallest number in array a[]
for (int i = 0; i <= number_used; i++)
{
if (temp >= a[i])
{
temp = a[i];
}
}
return temp;
}
Your program has undefined behavior because you are accessing the array a using an invalid index.
When an array has 20 elements, the valid indices are 0-19, not 0-20.
You are using
for (int i = 0; i <= number_used; i++)
and then accessing a[i] in the loop. If number_used is equal to 20, you are accessing a using and index value of 20, which is not correct.
Change that to use i < number_used.
for (int i = 0; i < number_used; i++)
A minor issue is that you are using temp >= a[i], which can be changed to use temp > a[i]. Use of >= in this case will work but it will do more work than necessary.
Here's an updated version of the function:
int theSmallest(const int a[], int number_used)
{
int temp = a[0];
// Find the smallest number in array a[]
for (int i = 1; i < number_used; i++)
{
if (temp > a[i])
{
temp = a[i];
}
}
return temp;
}
Assuming number_used is the size of array, code can be written as:
int theSmallest(const int a[], int number_used)
{
if( a == nullptr or number_used == 0 )
throw std::runtime_error( "invalid argument" );
return *std::min_element( a, a + number_used );
}
Note: you code has issue in case number_used is equal to 0 or a pointer is passed as nullptr, you may not expect that to happen but it is good idea to always validate your input (at least by assert())
Change to i < number_used and I think change to if(temp > a[i]).
You can also start i=1 since you made the assumption index 0 is the smallest.
Change
for (int i = 0; i <= number_used; i++)
to
for (int i = 1; i < number_used; i++)

C++ Passing arrays by reference to a function but contents remain unchanged

I'm working on a program to solve an Economics model. First, I declare a namespace as follows:
namespace myNameSpace
{
const int d1{10};
const int d2{5};
const int d3{7};
double array[d1][d2][d3]={};
}
Then, I have a function that modifies array:
void doSomething(double (&array)[myNameSpace::d1][myNameSpace::d2][myNameSpace::d3])
{
int i,j,k;
for (i=0, j=0, k=0; i<myNameSpace::d1,j<myNameSpace::d2,k<myNameSpace::d3; i++,j++,k++)
array[i][j][k]=i+j+k+1.0;
}
In the main function I call doSomething as:
int main()
{
doSomething(myNameSpace::array);
for (int i=0;j<myNameSpace::d1;j++)
std::cout << myNameSpace::array[i][1][1] << std::endl;
}
The output I get in the console is:
0
0
0
Can you provide any guidance on this? I've tried passing array without the address-of operator &, but then inside doSomething, array losses the first dimension. Any help will be highly appreciated!!
First of all, your for loop
for (i=0, j=0, k=0; i<myNameSpace::d1,j<myNameSpace::d2,k<myNameSpace::d3; i++,j++,k++)
doesn't do what you think it does, and you would've (hopefully) noticed that if you compiled with warnings (warning: relational comparison result unused).
It has 2, related, major problems:
Since i<myNameSpace::d1,j<myNameSpace::d2,k<myNameSpace::d3 only returns the value of the last comparison, due to the comma operator being used. So, you are effectively iterating until k<myNameSpace::d3.
The for loop you wrote - is just a single loop. It doesn't iterate through all possible combinations of values of i, j, and k, as you might have wanted.
It initializes i, j, k to 0; checks comparison expression (which, as explained by (1) only checks the value of k); and after the code in the loop was run - increments all of i, j, k by 1. Hence - you are setting only the 0/0/0, 1/1/1, 2/2/2, ..., up until k/k/k indices of your array. And, because your middle array has a bound, which is smaller than k - you invoke undefined behavior by stepping out of bounds.
And, lastly, you are printing only the i/1/1 index of your array, and since the only one value in the index range 0/1/1-d1/1/1 that's set is 1/1/1 - it is, exactly what's printed with a non-zero value.
To iterate over the whole array, as, might have been your intention - you should use nested loops, so they would allow all of the loop variables to change independently of one another:
for (i=0; i<myNameSpace::d1; i++)
{
for (j=0; j<myNameSpace::d2; j++)
{
for (k=0; k<myNameSpace::d3; k++)
{
array[i][j][k]=i+j+k+1.0;
}
}
}
for start you have a problem with your for loop
initialize i and running over j. once I changed it, I received some values.
If your array declared with those sizes it's way shorter (and readable)to write:
void doSomething( declspec(myNameSpace::array) &array )
or much better to declare type alias to use it everywhere:
using myArrayType = double[myNameSpace::d1][myNameSpace::d2][myNameSpace::d3];
not to mention that d1,d2 and d3 should be const. Toset ALL elements of array your loops should look like this:
void doSomething( myArrayType &array )
{
int i,j,k;
for ( i = 0; i < myNameSpace::d1; i++)
for ( j = 0; j < myNameSpace::d2; j++)
for (k = 0; k < myNameSpace::d3; k++)
array[i][j][k]=i+j+k+1.0;
}
Everything written in single for divided by comma is happening in single iteration. There are perverted ways to write it in single for() but I don't recommend that code.
for() loop is very flexible. pretty much it looks like
for(expressionFirst; expressionCheck; expressionEach )
statement to execute
expressionFirst can be ANY statement OR a single declaration, it executes only once, before loop starts. expressionCheck executed at beginning of each iteration, it must be any expression that is contextually convertible to bool (i.e. if even explicit T::operator bool() const; is applicable in this case), if it returns false, the loop stops. expressionEach is any expression that evaluates at end of each iteration.
Equivalent of for()
{
expressionFirst
while ( expressionCheck )
{
statement to execute
expressionEach;
}
}
All expressions are optional, so you can use for(;;) - a "forever" loop.
Comma operator you use allows to sequence several expressions, only last one is returned as result. Thus it is called sequence operator. And that's why your loop is wrong.
And you have a typo in main function, which led you to print only the first element of array, no increment of i.
I tried to compile your code, and I got an error in this line:
for (int i=0;j<myNameSpace::d1;j++)
The variable j is undeclared. As you can note, you declared the variable i inside the for loop, but not j. Do you want to loop using i or j? ...Maybe it's i because inside the body of the loop you used it as first-dimension index?
So, maybe you meant this code?
for (int i = 0; i < myNameSpace::d1; i++)
std::cout << myNameSpace::array[i][1][1] << std::endl;
In addition, are you sure the loop inside doSomething does what you mean?
Or maybe you want to loop using three nested loops for each array dimension?
E.g.:
void doSomething(double (&array)[myNameSpace::d1][myNameSpace::d2][myNameSpace::d3])
{
for (int i = 0; i < myNameSpace::d1; i++) {
for (int j = 0; j < myNameSpace::d2; j++) {
for (int k = 0; k < myNameSpace::d3; k++) {
array[i][j][k] = i + j + k + 1.0;
}
}
}
}
Note that in C++ raw arrays are passed by reference, so the &array syntax is unnecessary. Moreover, the compiler also ignores the raw array dimensions (myNameSpace::d1, etc.) for array parameters. Those may be good for documentation purposes though.

Intersection of 2 dynamically allocated arrays c++

I am trying to create a function that will find the intersection of two dynamically allocated arrays comparing array 1 to array 2. For any values in array 1 that are not in array 2, those values should be deleted in array 1 so that array 1 now only holds the common values of both arrays (no repeats). I cannot use vectors, hashes, or any other thing outside of my current functions in my class:
here is my code so far:
bool IntSet::contains(int val) const
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
return true;
}
return false;
}
this function compares an integer parameter to values currently stored in the array...if a value is in the array it returns true and if else false;
this next function takes in a value and removes that value from the array:
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
}
numValues--;
}
here's where I've been having problems, this next function is supposed to iterate through one array and compare those values with the values in the other array...if one value from one array is in the other, it should just skip it, but if a value is not in the array calling the function, it should delete that value from the calling array:
void IntSet::removeDifferent(const IntSet &set2)
{
for (int i = 0; i < set2.size(); i++)
{
if (!set2.contains(set[i]))
{
remove(set[i]);
}
}
}
ive tried about 50 different variations on the removeDifferent() function and I just can't seem to figure this one out. Could someone point me in the right direction?
You're iterating i through the indexes of set2, but then you're testing set[i]. Try this:
void IntSet::removeDifferent(const IntSet &set2)
{
for (int i = 0; i < numValues; ) {
if (!set2.contains(set[i])) {
remove(set[i]);
} else {
i++;
}
}
Note that I also removed i++ from the for loop header. This is because when you remove an element, all the following elements are shifted down, so the next element takes its place in the array. If you incremented i, it would skip that element.
You also need to fix remove. It should start its inner loop from i, so it only shifts down the elements after the one being removed, and it should stop at numValues-1, so it doesn't try to access outside the array when it copies set[j+1]. And as an optimization, it can break out of the outer loop once it has found a match (I assume IntSet doesn't allow duplicates, since you only decrement numValues by 1).
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val) {
for (int j = i; j < numValues - 1; j++) {
set[j] = set[j + 1];
}
break;
}
}
numValues--;
}
Your problem is in your remove() function:
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
}
numValues--;
}
You can figure out yourself why this is wrong by using a paper and pencil here. Start with a typical example: let's say you found the value you're looking for in the third element of a five-element array:
if (set[i] == val)
In this example, i would be set to 2, and numValues would be set to five. It doesn't matter what val is. Whatever it is, you found it when i is 2, and numValues is five: you found it in the third element of a five element array. Keep that in mind.
Now, you know that you are now supposed to remove the third element in this five element array. But what do you think will happen next:
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
Well, using the aforementioned paper and pencil, if you work it out, the following will happen:
set[1] will be copied to set[0]
set[2] will be copied to set[1]
set[3] will be copied to set[2]
set[4] will be copied to set[3]
set[5] will be copied to set[4]
There are two problems here:
A) There is no set[5]. Recall that this is a five-element array, si you only have set[0] through set[4]
B) You're not supposed to copy everything in array down to one element. You have to copy only the elements after the element you want to remove.
Fix these two problems, and you will probably find that everything will work correctly.

Why my function isn't executing i++?

I am writing a get function within a class of an object oriented program, but the i++ in my code is not executing for some reason.
This is what is used in my .cpp file:
char MyString::Get(int i)
{
if( i = '\0')
{
exit(1);
}
else
{
return String[i];
}
}
This is what is called in the main.cpp file:
for(int i=0; i < String1.Length()+1; i++)
{
cout<< String1.Get(i)<<" ";
}
cout << endl;
This is the length method in the .cpp file for reference purposes:
int MyString::Length()
{
int counter(0);
while(String[counter] != '\0')
{
counter ++;
}
return (counter);
}
Also: String1 = Jello World
The output:
J J J J J J J J J J J J J
Well - probably cause of this. You assigned instead of compared. You assigned zero to i. That failed the 'if' test (it's zero), so exit did not get called and the rest of your routine ran with i == to zero.
if( i = '\0')
{
exit(1);
}
You haven't really shown enough code for someone to be able to figure out what your code is doing, but this looks incorrect:
if( i = '\0')
a single = symbol causes i to be assigned the value on the right-hand-side of the expression.
if( '\0' ) evaluates to if(false).
As others have pointed out, you're doing an assignment instead of a comparison, so the "comparison" will always be treated as false -- the result of a comparison is the assigned value, which in this case is 0.
Though it has never become overwhelmingly popular, there is a fairly simple technique to avoid this problem: when you're comparing to a constant, always put the constant on the left. This way, if you mis-type == as =, the code won't compile:
if ('\0' = i) // error: lvalue required (or something on that order).