to_lower function entering an infinite loop

Started by
27 comments, last by MarcusAseth 6 years, 7 months ago

Why should it return found? If it gets to that line it's always a nullptr.

At this point I think we'd just be looking to use std::string::find, substr

Advertisement
39 minutes ago, h8CplusplusGuru said:

Why should it return found? If it gets to that line it's always a nullptr.

Try it with the findx("ababac", "abac"), it gets there and return a nullptr instead of the substring starting at found. That's why it should return found.

This thread is a great example of why it is important to write tests.  We have at least five different implementations in this thread of `findx`, each with varying levels of “correct”.  Automated tests can provide an empirical measure of correctness.  And since `findx` is a pure function, we can easily write automated tests to help us.

First, a crude testing routine for any `findx` implementation:


const char* findx(const char*, const char*);

void test_findx() {
	struct test_t {
		const char* input;
		const char* subject;
		const char* expected;

		test_t(const char* input, const char* subject, const int pos) {
			this->input    = input;
			this->subject  = subject;
			this->expected = ( pos == -1 ) ? nullptr : (input + pos);
		}
	} tests[] = {
		test_t("abc",         "abc",  0),
		test_t("abcdef",      "abc",  0),
		test_t("ababac",      "abac", 2),
		test_t("ababac-----", "abac", 2),

		test_t("abc",         "xyz",  -1),
		test_t("abc",         "",     -1),
		test_t("",            "",     0),
		test_t("",            "a",    -1),

		// ...
	};

	int failed = 0;
	for ( const auto& test : tests ) {
		const char* result = findx(test.input, test.subject);

		if ( result != test.expected ) {
			failed ++;
			cerr << "Test #" << (&test - tests) << " failed" << endl;
		}
	}

	return failed;
}

And running the full example test here:  https://ideone.com/G2Suog#stdout


Test #0 failed: "abc" in "abc", expected "abc", got nullptr
Test #2 failed: "abac" in "ababac", expected "abac", got nullptr
Test #5 failed: "" in "abc", expected nullptr, got "abc"
Test #6 failed: "" in "", expected "", got nullptr
Failed 4 of 8 tests.

... we can see that there are a few cases we’ve missed.  And while we continually fix the implementation, we can think of more corner cases to add to the tests.

Testing can go along way in helping you write correct code and can also help you keep your sanity in face of bizarre bugs.

mine passes the tests, yay! :D

well, actually it "fails" this 

Quote

test_t("abc",         "",     -1)

Test #5 failed: "" in "abc", expected nullptr, got "abc"

but I don't consider it a fail, because my original intention was indeed to return the left-hand side argument in case someone did something as pointless as to try to find nothing. But I don't actually know how the usual function decide to handle that case, so I will assume they return nullptr as expected by the testcase.

Anyway I've already saw in the code above something interesting I wasn't fully aware I could write, so I go back to read carefully trough it, thanks for posting it @fastcall22 :)

 

As a mathematician, the desired behavior of findx when the second argument is the empty string is obvious: The first instance of the empty string is found at the beginning of the string.

For instance, I could make a function that splits a string into substrings using a separator, like "split" in Perl. This is how that Perl function behaves:


	$ perl -e 'for $x (split ",", "a,b,c") { print "\"$x\"\n";}'
	"a"
	"b"
	"c"
	$ perl -e 'for $x (split "", "a,b,c") { print "\"$x\"\n";}'
	"a"
	","
	"b"
	","
	"c"

So if you look for the empty string, you find it everywhere, and "split" separates every character.

@alvaro interesting point of view. Though now that I think about it, both returning the beggining and returning nullptr seems wrong to me now (based on my use of this c strings, which is not math related), the reason is that it seems there really is no "empty C string" in c++ because it will always contain this terminating null character, therefore is a mismatch of names, the "empty string" should really be called "the null string" or something like that, and looking for that should return the null terminating character position in the other string, which is not a nullptr either, so it should return something like vector::end which is 1 past the last element, which also correspond to the first element in case the C string is actually "empty" (only a null character).

And if someone gets in trouble for messing with it, well, he/she asked for it xD

 

Edit: After thinking more about it, my previous conclusion was wrong, was based on the fact that maybe the user actually needed to find "one past the end" to do something, but I just realized that that should be it's own function that returns one past the end and does only that, this function that need to find a substring has really nothing to do with it.

So probably '\0' should be excluded from the searchable character just because is an internal mechanism to represent the end of the array, so returning a pointer to that from this function doesn't makes that much sense now. Returning a nullptr for an "empty string" seems the right way to go because '\0' in an internal mechanism and shouldn't be searched for nor found (from this particular function!) xD 

Lol, yes, the thread turned into unit tests because I apparently suck at doing them on the whim. And, yes, It should return found and did originally until I preferred the idea of only returning if strx:'\0' was encountered but did not test it well. My entire point in this thread was to expose marcus to some different coding ideas, and although he *hates* it, I think it has turned out ok, and I will probably continue to do it hopefully with "correctness" in the future. In the words of cartman, "i do wat i want". The function, I think, came a long way since its original conception. I did not realize early that a side-thought of a function project would indeed benefit from a proper unit testing routing or a better programmer, but it did turn out that way. 

I totally don't hate it though, I'm always glad to see the way other people would have done something

I might mildly dislike when I am exposed to buggy code though :D , because I'm constantly worried to get crippled from memorizing incorrect informations (is easy to learn and hard to un-learn), that's why I'm always suspicious when I am not convinced about something, is my memorization firewall kicking in :D

Though really, I'm always glad to see people in forums that partecipates, so thanks and keep at it :)

 

This topic is closed to new replies.

Advertisement