Nested if-else not working for custom structure c++ - c++

I have a custom data structure date in C++11:
struct date {
int day;
int month;
int year;
};
I want to compare two dates and write function for it:
int compare_dates(date a, date b) {
int result = 0;
if (a.year < b.year) {
result = -1;
} else if (a.year == b.year) {
if (a.month < b.month) {
result = -1;
} else if (a.month == b.month) {
if (a.day < a.day) {
result = -1;
} else if (a.day > a.day) {
result = 1;
}
} else {
result = 1;
}
} else {
result = 1;
}
return result;
}
But this function doesn't work correctly. I spent a lot of time to debug it and found some issue in the following part of code:
} else if (a.month == b.month) {
if (a.day < a.day) {
result = -1;
} else if (a.day > a.day) {
result = 1;
}
} else {
result = 1;
}
There are two screenshots during debugging, first on } else if (a.month == b.month) { and second when I click next line in debugger. Such happens for all inputs. Why debbuger did not enter into if (a.day < a.day) { or result = 1; everytime?

Try with
if (a.day < b.day) {
result = -1;
} else if (a.day > b.day) {
result = 1;
}
instead of
if (a.day < a.day) {
result = -1;
} else if (a.day > a.day) {
result = 1;
}
The two tests a.day < a.day and a.day > a.day are ever false, so result = -1 and result = 1 are never executed.
I suppose that the compiler optimize the code as follows
} else if (a.month == b.month) {
} else {
result = 1;
}

It may be that compiler optimisations get in your way.
As others have observed, you have two typos inside the block. a.day < a.day and a.day > a.day are by definition always false. Consequently, nothing can ever happen in the block. There is no observable behaviour. That's probably why the compiler just completely eliminates the entire thing to save speed and/or space.
I don't know which compiler you are using, or which flags you pass it, but if you disable all optimisation, then the debugger should work as you expect. You can also try to put a std::cout << "...\n"; into the block to enforce some observable behaviour and see if that changes something.
This is also an excellent reason to actually learn how your compiler really works, without all the IDE fluff covering its functionality.

Line no 25 in screenshot first,
if (a.day < a.day)
It should be
if (a.day < b.day)
same mistake is in line 27.

Related

Linker causing seemingly random crashes?

EDIT: After some more trying and testing, it seems to set down to changing stack size everytime I change code and I want the program to run. If I don't change the stack size, the program seems to crash everytime after code change.
EDIT 2: Same seems to apply to both /HEAP and /STACK
A bit of and odd question, but as far as I can tell, based on some checking and testing.
On multiple projects (at some point) I've come across this same problem:
I change a bit of code, the program crashes.
I change stack size, the program doesn't crash(with the changed code), doesn't seem to matter if incrementing or decrementing stack size.
Seemingly as if there's a hidden randomized stack which, if below a certain value causing the program to crash (no error). I can cause the crash by testing different stack sizes.
On a recent project, the crash seems to "pinpoint" to the bit of code:
typedef unsigned int DINT;
template <typename LIST_ITEM>
struct LIST {
LIST() {
this->length = 0;
this->total = 0;
for (DINT i = 0; i < ENGINE_DATABASE_LIST_LENGTH_MAX; i++) {
//this->item[i] = { 0 };
this->existance[i] = 0;
}
};
~LIST() {
for (DINT i = 0; i < ENGINE_DATABASE_LIST_LENGTH_MAX; i++) {
//this->item[i] = { 0 };
this->existance[i] = 0;
}
this->length = 0;
this->total = 0;
};
DINT length, total;
LIST_ITEM item[ENGINE_DATABASE_LIST_LENGTH_MAX];
DINT existance[ENGINE_DATABASE_LIST_LENGTH_MAX];
DINT _set(LIST_ITEM item) {
for (DINT d = 0; d < ENGINE_DATABASE_LIST_LENGTH_MAX; d++) {
if (this->existance[d] == 0) {
this->item[d] = item;
this->existance[d] = 1;
this->length++;
this->total++;
return d;
}
}
return 0;
}
void _remove(DINT position = 0) {
this->item[position] = {};
this->existance[position] = 0;
LIST <LIST_ITEM> list = {};
DINT length = 0;
do {
if (this->existance[length] == 1) {
list._set(this->_get(length));
this->existance[length] = 0;
//this->item[l] = {};
}
length++;
} while (length < ENGINE_DATABASE_LIST_LENGTH_MAX);
this->_carry(list);
}
LIST_ITEM _get(DINT position = 0) {
return this->item[position];
}
void _carry(LIST <LIST_ITEM> list = {}) {
for (DINT d = 0; d < list.length; d++) {
if (list.existance[d] == 1) this->_set(list.item[d]);
}
}
void _deconstruct() {
/*
for (DINT i = 0; i < ENGINE_DATABASE_LIST_LENGTH_MAX; i++) {
if (this->existance[i] == 1) {
this->existance[i] = 0;
this->item[i] = { };
}
}
this->length = 0;
this->total = 0;
*/
this->~LIST();
}
};
Possible solution/fix:
void _remove(DINT position = 0) {
this->existance[position] = 0;
this->length--;
LIST <LIST_ITEM> *list = new LIST;
for (DINT a = 0; a < ENGINE_DATABASE_LIST_LENGTH_MAX; a++) {
if (this->existance[a] == 1) {
list->_set(this->item[a]);
if (list->length == this->length) break;
}
}
list->total = this->total;
*this = *list;
delete list;
}
If the max list length is set to 64, the program seems to run fine, no matter of stack, but at 128 the crashes start to happen, and if I do the above (change stack size by even just 1, the program runs fine again, until next change of code, then I change stack by 1 again and the program runs fine again).
There might be a "< 0" somewhere (which could also cause crashing), which I just can't seem to spot.
Please do point out.
Seem confusing? Please ask.

Sort file names func [duplicate]

I'm sorting strings that are comprised of text and numbers.
I want the sort to sort the number parts as numbers, not alphanumeric.
For example I want: abc1def, ..., abc9def, abc10def
instead of: abc10def, abc1def, ..., abc9def
Does anyone know an algorithm for this (in particular in c++)
Thanks
I asked this exact question (although in Java) and got pointed to http://www.davekoelle.com/alphanum.html which has an algorithm and implementations of it in many languages.
Update 14 years later: Dave Koelle’s blog has gone off line and I can’t find his actual algorithm, but here’s an implementation.
https://github.com/cblanc/koelle-sort
Several natural sort implementations for C++ are available. A brief review:
natural_sort<> - based on Boost.Regex.
In my tests, it's roughly 20 times slower than other options.
Dirk Jagdmann's alnum.hpp, based on Dave Koelle's alphanum algorithm
Potential integer overlow issues for values over MAXINT
Martin Pool's natsort - written in C, but trivially usable from C++.
The only C/C++ implementation I've seen to offer a case insensitive version, which would seem to be a high priority for a "natural" sort.
Like the other implementations, it doesn't actually parse decimal points, but it does special case leading zeroes (anything with a leading 0 is assumed to be a fraction), which is a little weird but potentially useful.
PHP uses this algorithm.
This is known as natural sorting. There's an algorithm here that looks promising.
Be careful of problems with non-ASCII characters (see Jeff's blog entry on the subject).
Partially reposting my another answer:
bool compareNat(const std::string& a, const std::string& b){
if (a.empty())
return true;
if (b.empty())
return false;
if (std::isdigit(a[0]) && !std::isdigit(b[0]))
return true;
if (!std::isdigit(a[0]) && std::isdigit(b[0]))
return false;
if (!std::isdigit(a[0]) && !std::isdigit(b[0]))
{
if (a[0] == b[0])
return compareNat(a.substr(1), b.substr(1));
return (toUpper(a) < toUpper(b));
//toUpper() is a function to convert a std::string to uppercase.
}
// Both strings begin with digit --> parse both numbers
std::istringstream issa(a);
std::istringstream issb(b);
int ia, ib;
issa >> ia;
issb >> ib;
if (ia != ib)
return ia < ib;
// Numbers are the same --> remove numbers and recurse
std::string anew, bnew;
std::getline(issa, anew);
std::getline(issb, bnew);
return (compareNat(anew, bnew));
}
toUpper() function:
std::string toUpper(std::string s){
for(int i=0;i<(int)s.length();i++){s[i]=toupper(s[i]);}
return s;
}
Usage:
std::vector<std::string> str;
str.push_back("abc1def");
str.push_back("abc10def");
...
std::sort(str.begin(), str.end(), compareNat);
To solve what is essentially a parsing problem a state machine (aka finite state automaton) is the way to go. Dissatisfied with the above solutions i wrote a simple one-pass early bail-out algorithm that beats C/C++ variants suggested above in terms of performance, does not suffer from numerical datatype overflow errors, and is easy to modify to add case insensitivity if required.
sources can be found here
For those that arrive here and are already using Qt in their project, you can use the QCollator class. See this question for details.
Avalanchesort is a recursive variation of naturall sort, whiche merge runs, while exploring the stack of sorting-datas. The algorithim will sort stable, even if you add datas to your sorting-heap, while the algorithm is running/sorting.
The search-principle is simple. Only merge runs with the same rank.
After finding the first two naturell runs (rank 0), avalanchesort merge them to a run with rank 1. Then it call avalanchesort, to generate a second run with rank 1 and merge the two runs to a run with rank 2. Then it call the avalancheSort to generate a run with rank 2 on the unsorted datas....
My Implementation porthd/avalanchesort divide the sorting from the handling of the data using interface injection. You can use the algorithmn for datastructures like array, associative arrays or lists.
/**
* #param DataListAvalancheSortInterface $dataList
* #param DataRangeInterface $beginRange
* #param int $avalancheIndex
* #return bool
*/
public function startAvalancheSort(DataListAvalancheSortInterface $dataList)
{
$avalancheIndex = 0;
$rangeResult = $this->avalancheSort($dataList, $dataList->getFirstIdent(), $avalancheIndex);
if (!$dataList->isLastIdent($rangeResult->getStop())) {
do {
$avalancheIndex++;
$lastIdent = $rangeResult->getStop();
if ($dataList->isLastIdent($lastIdent)) {
$rangeResult = new $this->rangeClass();
$rangeResult->setStart($dataList->getFirstIdent());
$rangeResult->setStop($dataList->getLastIdent());
break;
}
$nextIdent = $dataList->getNextIdent($lastIdent);
$rangeFollow = $this->avalancheSort($dataList, $nextIdent, $avalancheIndex);
$rangeResult = $this->mergeAvalanche($dataList, $rangeResult, $rangeFollow);
} while (true);
}
return $rangeResult;
}
/**
* #param DataListAvalancheSortInterface $dataList
* #param DataRangeInterface $range
* #return DataRangeInterface
*/
protected function findRun(DataListAvalancheSortInterface $dataList,
$startIdent)
{
$result = new $this->rangeClass();
$result->setStart($startIdent);
$result->setStop($startIdent);
do {
if ($dataList->isLastIdent($result->getStop())) {
break;
}
$nextIdent = $dataList->getNextIdent($result->getStop());
if ($dataList->oddLowerEqualThanEven(
$dataList->getDataItem($result->getStop()),
$dataList->getDataItem($nextIdent)
)) {
$result->setStop($nextIdent);
} else {
break;
}
} while (true);
return $result;
}
/**
* #param DataListAvalancheSortInterface $dataList
* #param $beginIdent
* #param int $avalancheIndex
* #return DataRangeInterface|mixed
*/
protected function avalancheSort(DataListAvalancheSortInterface $dataList,
$beginIdent,
int $avalancheIndex = 0)
{
if ($avalancheIndex === 0) {
$rangeFirst = $this->findRun($dataList, $beginIdent);
if ($dataList->isLastIdent($rangeFirst->getStop())) {
// it is the last run
$rangeResult = $rangeFirst;
} else {
$nextIdent = $dataList->getNextIdent($rangeFirst->getStop());
$rangeSecond = $this->findRun($dataList, $nextIdent);
$rangeResult = $this->mergeAvalanche($dataList, $rangeFirst, $rangeSecond);
}
} else {
$rangeFirst = $this->avalancheSort($dataList,
$beginIdent,
($avalancheIndex - 1)
);
if ($dataList->isLastIdent($rangeFirst->getStop())) {
$rangeResult = $rangeFirst;
} else {
$nextIdent = $dataList->getNextIdent($rangeFirst->getStop());
$rangeSecond = $this->avalancheSort($dataList,
$nextIdent,
($avalancheIndex - 1)
);
$rangeResult = $this->mergeAvalanche($dataList, $rangeFirst, $rangeSecond);
}
}
return $rangeResult;
}
protected function mergeAvalanche(DataListAvalancheSortInterface $dataList, $oddListRange, $evenListRange)
{
$resultRange = new $this->rangeClass();
$oddNextIdent = $oddListRange->getStart();
$oddStopIdent = $oddListRange->getStop();
$evenNextIdent = $evenListRange->getStart();
$evenStopIdent = $evenListRange->getStop();
$dataList->initNewListPart($oddListRange, $evenListRange);
do {
if ($dataList->oddLowerEqualThanEven(
$dataList->getDataItem($oddNextIdent),
$dataList->getDataItem($evenNextIdent)
)) {
$dataList->addListPart($oddNextIdent);
if ($oddNextIdent === $oddStopIdent) {
$restTail = $evenNextIdent;
$stopTail = $evenStopIdent;
break;
}
$oddNextIdent = $dataList->getNextIdent($oddNextIdent);
} else {
$dataList->addListPart($evenNextIdent);
if ($evenNextIdent === $evenStopIdent) {
$restTail = $oddNextIdent;
$stopTail = $oddStopIdent;
break;
}
$evenNextIdent = $dataList->getNextIdent($evenNextIdent);
}
} while (true);
while ($stopTail !== $restTail) {
$dataList->addListPart($restTail);
$restTail = $dataList->getNextIdent($restTail);
}
$dataList->addListPart($restTail);
$dataList->cascadeDataListChange($resultRange);
return $resultRange;
}
}
My algorithm with test code of java version. If you want to use it in your project you can define a comparator yourself.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;
public class FileNameSortTest {
private static List<String> names = Arrays.asList(
"A__01__02",
"A__2__02",
"A__1__23",
"A__11__23",
"A__3++++",
"B__1__02",
"B__22_13",
"1_22_2222",
"12_222_222",
"2222222222",
"1.sadasdsadsa",
"11.asdasdasdasdasd",
"2.sadsadasdsad",
"22.sadasdasdsadsa",
"3.asdasdsadsadsa",
"adsadsadsasd1",
"adsadsadsasd10",
"adsadsadsasd3",
"adsadsadsasd02"
);
public static void main(String...args) {
List<File> files = new ArrayList<>();
names.forEach(s -> {
File f = new File(s);
try {
if (!f.exists()) {
f.createNewFile();
}
files.add(f);
} catch (IOException e) {
e.printStackTrace();
}
});
files.sort(Comparator.comparing(File::getName));
files.forEach(f -> System.out.print(f.getName() + " "));
System.out.println();
files.sort(new Comparator<File>() {
boolean caseSensitive = false;
int SPAN_OF_CASES = 'a' - 'A';
#Override
public int compare(File left, File right) {
char[] csLeft = left.getName().toCharArray(), csRight = right.getName().toCharArray();
boolean isNumberRegion = false;
int diff=0, i=0, j=0, lenLeft=csLeft.length, lenRight=csRight.length;
char cLeft = 0, cRight = 0;
for (; i<lenLeft && j<lenRight; i++, j++) {
cLeft = getCharByCaseSensitive(csLeft[i]);
cRight = getCharByCaseSensitive(csRight[j]);
boolean isNumericLeft = isNumeric(cLeft), isNumericRight = isNumeric(cRight);
if (isNumericLeft && isNumericRight) {
// Number start!
if (!isNumberRegion) {
isNumberRegion = true;
// Remove prefix '0'
while (i < lenLeft && cLeft == '0') i++;
while (j < lenRight && cRight == '0') j++;
if (i == lenLeft || j == lenRight) break;
}
// Diff start: calculate the diff value.
if (cLeft != cRight && diff == 0)
diff = cLeft - cRight;
} else {
if (isNumericLeft != isNumericRight) {
// One numeric and one char.
if (isNumberRegion)
return isNumericLeft ? 1 : -1;
return cLeft - cRight;
} else {
// Two chars: if (number) diff don't equal 0 return it.
if (diff != 0)
return diff;
// Calculate chars diff.
diff = cLeft - cRight;
if (diff != 0)
return diff;
// Reset!
isNumberRegion = false;
diff = 0;
}
}
}
// The longer one will be put backwards.
return (i == lenLeft && j == lenRight) ? cLeft - cRight : (i == lenLeft ? -1 : 1) ;
}
private boolean isNumeric(char c) {
return c >= '0' && c <= '9';
}
private char getCharByCaseSensitive(char c) {
return caseSensitive ? c : (c >= 'A' && c <= 'Z' ? (char) (c + SPAN_OF_CASES) : c);
}
});
files.forEach(f -> System.out.print(f.getName() + " "));
}
}
The output is,
1.sadasdsadsa 11.asdasdasdasdasd 12_222_222 1_22_2222 2.sadsadasdsad 22.sadasdasdsadsa 2222222222 3.asdasdsadsadsa A__01__02 A__11__23 A__1__23 A__2__02 A__3++++ B__1__02 B__22_13 adsadsadsasd02 adsadsadsasd1 adsadsadsasd10 adsadsadsasd3
1.sadasdsadsa 1_22_2222 2.sadsadasdsad 3.asdasdsadsadsa 11.asdasdasdasdasd 12_222_222 22.sadasdasdsadsa 2222222222 A__01__02 A__1__23 A__2__02 A__3++++ A__11__23 adsadsadsasd02 adsadsadsasd1 adsadsadsasd3 adsadsadsasd10 B__1__02 B__22_13
Process finished with exit code 0
// -1: s0 < s1; 0: s0 == s1; 1: s0 > s1
static int numericCompare(const string &s0, const string &s1) {
size_t i = 0, j = 0;
for (; i < s0.size() && j < s1.size();) {
string t0(1, s0[i++]);
while (i < s0.size() && !(isdigit(t0[0]) ^ isdigit(s0[i]))) {
t0.push_back(s0[i++]);
}
string t1(1, s1[j++]);
while (j < s1.size() && !(isdigit(t1[0]) ^ isdigit(s1[j]))) {
t1.push_back(s1[j++]);
}
if (isdigit(t0[0]) && isdigit(t1[0])) {
size_t p0 = t0.find_first_not_of('0');
size_t p1 = t1.find_first_not_of('0');
t0 = p0 == string::npos ? "" : t0.substr(p0);
t1 = p1 == string::npos ? "" : t1.substr(p1);
if (t0.size() != t1.size()) {
return t0.size() < t1.size() ? -1 : 1;
}
}
if (t0 != t1) {
return t0 < t1 ? -1 : 1;
}
}
return i == s0.size() && j == s1.size() ? 0 : i != s0.size() ? 1 : -1;
}
I am not very sure if it is you want, anyway, you can have a try:-)

Clang Format chained else ifs on single lines

I'm trying to write a .clang-format file that will allow the following:
if (value.Is<bool>()) { index = 1; }
else if (value.Is<int>()) { index = 2; }
else if (value.Is<unsigned int>()) { index = 3; }
else if (value.Is<long long>()) { index = 4; }
else if (value.Is<unsigned long long>()) { index = 5; }
else if (value.Is<float>()) { index = 6; }
else if (value.Is<double>()) { index = 7; }
else if (value.Is<long double>()) { index = 8; }
else if (value.Is<std::string>()) { index = 9; }
else if (value.IsArray()) { index = 10; }
else { index = 0; }
I've tried every option I can find related to breaks and allowShort*, and no matter what I do it seems to split them into multi-lines after the first like so:
if (value.Is<bool>()) { index = 1; }
else if (value.Is<int>()) {
index = 2;
}
...
Is there some option I'm missing that could support this?
Unfortunately, this is currently not supported for if-else statements, only for simple if's (as of revision 329373, dating 6/4/18). The AllowShortBlocksOnASingleLine and AllowShortIfStatementsOnASingleLine options are not applicable for if-else statements.
Hopefully this will change in the future.
The doc is not explicit about this, saying that AllowShortIfStatementsOnASingleLine will allow simple if statements on a single line:
AllowShortIfStatementsOnASingleLine (bool)
If true, if (a) return; can be put on a single line.
However, clang-format code suggests that if-else blocks are not allowed on single lines:
1) UnwrappedLineFormatter.cpp, tryMergeSimpleControlStatement:
// Only inline simple if's (no nested if or else).
if (I + 2 != E && Line.startsWith(tok::kw_if) &&
I[2]->First->is(tok::kw_else))
return 0;
2) FormatTest.cpp, FormatShortBracedStatements test.
Notice the test parameters, and that in the expected formatting in the unittests, else always resides in its own line, while plain if statements with no else are on a single line with their blocks, for example:
verifyFormat("if (true) {\n"
" f();\n"
"} else {\n"
" f();\n"
"}",
AllowSimpleBracedStatements);
https://clang.llvm.org/docs/ClangFormatStyleOptions.html says:
SIS_AllIfsAndElse (in configuration: AllIfsAndElse) Always put short ifs, else >ifs and else statements on the same line.
if (a) return;
if (b) return;
else return;
if (c) return;
else {
return;
}

C++ invalid operator< when using sorting

bool sortingGame(Player Player1, Player Player2)
{
if (Player1.gamePercent() > Player2.gamePercent())// first compare precetage (float)
{
return true;
}
else if (Player2.gamePercent() > Player1.gamePercent())
{
return false;
}
else if (Player1.getLastName() > Player2.getLastName())//then names (std::string)
{
return true;
}
else if (Player2.getLastName() > Player1.getLastName())
{
return false;
}
else if (Player1.getFirstName() > Player2.getFirstName())
{
return true;
}
else
{
return false;
}
}
heres in main():
sort(Players.begin(), Players.end(), sortingGame);
Here is the error showed when debugging in Visual Studio.
Program:C:\.....\include\algorithm
Line:3014
Expression: invalid operator<
When I mockup a players class and run your code it works fine. The error must belong somewhere else.
However your code could be tightened up considerably, by checking for equality and return the result of the comparison:
bool sortingGame(Player Player1, Player Player2)
{
if (Player1.gamePercent() != Player2.gamePercent())// first compare precetage (float)
{
return Player1.gamePercent() > Player2.gamePercent();
}
else if (Player1.getLastName() != Player2.getLastName())
{
return Player1.getLastName() > Player2.getLastName();
}
else
{
return Player1.getFirstName() > Player2.getFirstName();
}
}
Consider as well that strings are usually listed in reverse sort order(alphabetical). Therefore the less than operator(<) would work better:
bool sortingGame(Player Player1, Player Player2)
{
if (Player1.gamePercent() != Player2.gamePercent())// first compare precetage (float)
{
return Player1.gamePercent() > Player2.gamePercent();
}
else if (Player1.getLastName() != Player2.getLastName())
{
return Player1.getLastName() < Player2.getLastName();
}
else
{
return Player1.getFirstName() < Player2.getFirstName();
}
}

Error: not all control paths return a value

I am writing two functions in a program to check if a string has an assigned numeric code to its structure array or if the given numeric code has an assigned string in the same structure array. Basically, if I only know one of the two, I can get the other. I wrote the following:
int PrimaryIndex::check_title_pos(std::string title) {
bool findPos = true;
if (findPos) {
for (int s = 1; s <= 25; s++) {
if (my_list[s].title == title) {
return s;
}
}
} else {
return -1;
}
}
std::string PrimaryIndex::check_title_at_pos(int pos) {
bool findTitle = true;
if (findTitle) {
for (int p = 1; p <= 25; p++) {
if (my_list[p].tag == pos) {
return my_list[p].title;
}
}
} else {
return "No title retrievable from " + pos;
}
}
However, it says not all control paths have a return value. I thought the else {} statement would handle that but it's not. Likewise, I added default "return -1;" and "return "";" to the appropriate functions handling int and string, respectively. That just caused it to error out.
Any idea on how I can keep this code, as I'd like to think it works but cant test it, while giving my compiler happiness? I realize through other searches that it sees conditions that could otherwise end in no returning values but theoretically, if I am right, it should work fine. :|
Thanks
In the below snippet, if s iterates to 26 without the inner if ever evaluating to true then a return statement is never reached.
if (findPos) {
for (int s = 1; s <= 25; s++) {
if (my_list[s].title == title) {
return s;
}
}
}