Merge sort on array of string C - c++

Is it possible to merge sort an array of strings? For example if I have an array of strings in C like...
arr[0]="Hello";
arr[1]="cat";
arr[2]="there";
arr[3]="apple";
arr[4]="flower";
The sorted output should be...
apple
cat
flower
hello
there
Also I don't understand what I should do if I have 2 words like "Hello" and "Hell?" Everywhere the examples are always for integers and never strings especially in C++.

Yes, in your comparision, use strcmp for C, and std::string::compare for C++. Both functions will compare the strings, and return an integer with the following meanings...
< 0 — Either the value of the first character that does not match is lower in the compared string, or all compared characters match but the compared string is shorter.
= 0 — They compare equal
> 0 — Either the value of the first character that does not match is greater in the compared string, or all compared characters match but the compared string is longer.
This will also take into account "Hello" vs. "Hell" and will will subsequently sort "Hell" before "Hello".
Note: If you find that you are like me, and have a hard time remembering what the result means. Simply put the comparison operator (as in the example above) inbetween str1 and str2. So, for example, if you called strcmp(str1, str2) and the result was < 0, then look at it like str1 < str2.

Related

Is the comparison of strings or string views terminated at a null-character?

May a string or string_view include '\0' characters so that the following code prints 1 twice?
Or is this just implementation-defined?
#include <iostream>
#include <string_view>
#include <string>
using namespace std;
int main()
{
string_view sv( "\0hello world", 12 );
cout << (sv == sv) << endl;
string str( sv );
cout << (str == sv) << endl;
}
This isn't a duplicate to the question if strings can have embedded nulls since they obviously can. What I want to ask if the comparison of strings or string views is terminated at a 0-character.
Language lawyer answer since the standards documents are, by definition, the one true source of truth :-)
The standard is clear on this. In C++17 (since that's the tag you provided, but later iterations are similar), [string.operator==] states that, for using strings and/or string views, it:
Returns: lhs.compare(rhs) == 0.
The [string.compare] section further states that these all boil down to a comparison with a string view and explain that it:
Determines the effective length rlen of the strings to compare as the smaller of size() and sv.size(). The function then compares the two strings by calling traits::compare(data(), sv.data(), rlen).
These sizes are not restricted in any way by embedded nulls.
And, if you look at the traits information in table 54 of [char.traits.require], you'll see it's as clear as mud until you separate it out into sections:
X::compare(p,q,n) Returns int:
0 if for each i in [0,n), X::eq(p[i],q[i]) is true; else
a negative value if, for some j in [0,n), X::lt(p[j],q[j]) is true and for each i in [0,j) X::eq(p[i],q[i]) is true; else
a positive value.
The first bullet point is easy, it gives zero if every single character is equal.
The second is a little harder but it basically gives a negative value where the first difference between characters has the first string on the lower side (all previous characters are equal and the offending character is lower in the first string).
The third is just the default "if it's neither equal nor lesser, it must be greater".
nul-character is part of comparison, see https://en.cppreference.com/w/cpp/string/basic_string/operator_cmp
Two strings are equal if both the size of lhs and rhs are equal and each character in lhs has equivalent character in rhs at the same position.

Compare strings ignore NUL

I'm trying to compare two std::strings, "abc\0" and "abc".
Is there a way to ignore a character, in this case '\0' (NUL), when comparing?
Right now I'm doing a pop_back() on the string with the trailing NUL to remove it, but there must be a better way to handle this.
If the null terminator is always at the end, you could use std::strcmp.
Otherwise you can write the loop yourself to iterate both strings and compare the characters, with special rules when encountering the terminator.
A less efficient version can be implemented purely using standard algorithms: Create a copy of each string with the terminators removed (std::copy_if), and then use comparison operator of std::string.
Unlike C-style strings, NUL is a valid character for std::string and will be treated no difference as other characters.
Therefore, if one of your std::strings suffixes a NUL character and, that is not your want, you may should better figure it out why a NUL was included in the first place.
If you can't locate the source and fix it, there are two general workarounds.
(1) Trimming the string before the comparison
you can use a trim()-like funcion from third-party libraries, e.g. boost; or write your own implementation.
This function simply removes NUL character(s).
(2) Comparing strings in C-Style
use std::string::c_str() to obtain a c-style string and then use function like strcmp to do comparison。
Note, if there is a NUL character in the middle of the string, like ab\0c, this workaround would provide you a incorrect result.
If you are comparing two strings, one of length 4 "abc\0" and one of length 3 "abc", of course they are not going to compare equal. The fact that one of the characters is a NUL is not relevant here.
If you're trying to see if one string is the same as the other except that it has a NUL embedded in it at the end - that can be written thus:
std::string s1{"abc\0", 4};
std::string s2{"abc" , 3};
return s2.length() == s1.length() - 1 && // sizes differ by one char
s1.back() == '\0' && // last char is a NUL
s1.compare(0, s1.length() - 1, s2) == 0; // all the other ones are the same

String comparison of char* to uint8_t [duplicate]

This question already has an answer here:
Comparing uint8_t data with string
(1 answer)
Closed 4 years ago.
I'm new to C and C++, and can't seem to work out how I need to compare these values:
Variable I'm being passed:
typedef struct {
uint8_t ssid[33];
String I want to match. I've tried both of these:
uint8_t AP_Match = "MatchString";
unsigned char* AP_Match = "MatchString";
How I've attempted to match:
if (strncmp(list[i].ssid, "MatchString")) {
if (list[i].ssid == AP_Match) {
if (list[i].ssid == "MatchString") {
// This one fails because String is undeclared, despite having
// an include line for string.h
if (String(reinterpret_cast<const char*>(conf.sta.ssid)) == 'MatchString') {
I've noodled around with this a few different ways, and done some searching. I know one or both of these may be the wrong type, but I'm not sure to get from where I am to working.
There is no such type as "String" defined by any C standard. A string is just an array of characters that are stored as unsigned values based on the chosen encoding. 'string.h' provides various functions for comparison, concatenation, etc. but it can only work if the values you are passing to it are coherent.
The operator "==" is also undefined for string comparisons, because it would require comparing each character at each index, for two arrays that may not be the same size and ultimately may use different encodings, despite the same underlying unsigned integer representation (raising the prospect of false positive comparisons). You can possibly define your own function to do it (note C doesn't allow overloading operators), but otherwise you're stuck with what the standard libraries provide.
Note that strncmp() takes a size parameter for the number of characters to compare (your code is missing this). https://www.tutorialspoint.com/c_standard_library/c_function_strncmp.htm
Otherwise you would be looking at the function strcmp(), which requires the input strings to be null-terminated (last character equal to '\0'). Ultimately it's up to you to consider what the possible combinations of inputs could be and how they are stored and to use a comparison function that is robust to all possibilities.
As a final side note
if (list[i].ssid == "MatchString") {
Since ssid is an array, you should know that when you do this comparison, you are not actually accessing the contents of ssid, but rather the address of the first element of ssid. When you pass list[i].ssid into strcmp (or strncmp), you are passing a pointer to the first element of the array in memory. The function then iterates over the entire array until it reaches the null character (in the case of strcmp) or until it has compared the specified number of elements (in the case of strncmp).
To match two strings use strcmp:
if (0==strcmp(str1, str2))
str1 and str2 are addresses to memory holding a null terminated string. Return value zero means the strings are equal.
In your case one of:
if (0==strcmp(list[i].ssid, AP_Match))
if (0==strcmp(list[i].ssid, "MatchString"))

Does an empty string contain an empty string in C++?

Just had an interesting argument in the comment to one of my questions. My opponent claims that the statement "" does not contain "" is wrong.
My reasoning is that if "" contained another "", that one would also contain "" and so on.
Who is wrong?
P.S.
I am talking about a std::string
P.S. P.S
I was not talking about substrings, but even if I add to my question " as a substring", it still makes no sense. An empty substring is nonsense. If you allow empty substrings to be contained in strings, that means you have an infinity of empty substrings. What is the point of that?
Edit:
Am I the only one that thinks there's something wrong with the function std::string::find?
C++ reference clearly says
Return Value: The position of the first character of the first match.
Ok, let's assume it makes sense for a minute and run this code:
string empty1 = "";
string empty2 = "";
int postition = empty1.find(empty2);
cout << "found \"\" at index " << position << endl;
The output is: found "" at index 0
Nonsense part: how can there be index 0 in a string of length 0? It is nonsense.
To be able to even have a 0th position, the string must be at least 1 character long.
And C++ is giving a exception in this case, which proves my point:
cout << empty2.at( empty1.find(empty2) ) << endl;
If it really contained an empty string it would had no problem printing it out.
It depends on what you mean by "contains".
The empty string is a substring of the empty string, and so is contained in that sense.
On the other hand, if you consider a string as a collection of characters, the empty string can't contain the empty string, because its elements are characters, not strings.
Relating to sets, the set
{2}
is a subset of the set
A = {1, 2, 3}
but {2} is not a member of A - all A's members are numbers, not sets.
In the same way, {} is a subset of {}, but {} is not an element in {} (it can't be because it's empty).
So you're both right.
C++ agrees with your "opponent":
#include <iostream>
#include <string>
using namespace std;
int main()
{
bool contains = string("").find(string("")) != string::npos;
cout << "\"\" contains \"\": "
<< boolalpha << contains;
}
Output: "" contains "": true
Demo
It's easy. String A contains sub-string B if there is an argument offset such that A.substr(offset, B.size()) == B. No special cases for empty strings needed.
So, let's see. std::string("").substr(0,0) turns out to be std::string(""). And we can even check your "counter-example". std::string("").substr(0,0).substr(0,0) is also well-defined and empty. Turtles all the way down.
The first thing that is unclear is whether you are talking about std::string or null terminated C strings, the second thing is why should it matter?. I will assume std::string.
The requirements on std::string determine how the component must behave, not what its internal representation must be (although some of the requirements affect the internal representation). As long as the requirements for the component are met, whether it holds something internally is an implementation detail that you might not even be able to test.
In the particular case of an empty string, there is nothing that mandates that it holds anything. It could just hold a size member set to 0 and a pointer (for the dynamically allocated memory if/when not empty) also set to 0. The requirement in operator[] requires that it returns a reference to a character with value 0, but since that character cannot be modified without causing undefined behavior, and since strict aliasing rules allow reading from an lvalue of char type, the implementation could just return a reference to one of the bytes in the size member (all set to 0) in the case of an empty string.
Some implementations of std::string use small object optimizations, in those implementations there will be memory reserved for small strings, including an empty string. While the std::string will obviously not contain a std::string internally, it might contain the sequence of characters that compose an empty string (i.e. a terminating null character)
empty string doesn't contain anything - it's EMPTY. :)
Of course an empty string does not contain an empty string. It'll be turtles all the way down if it did.
Take String empty = ""; that is declaring a string literal that is empty, if you want a string literal to represent a string literal that is empty you would need String representsEMpty = """"; but of course, you need to escape it, giving you string actuallyRepresentsEmpty = "\"\"";
ps, I am taking a pragmatic approach to this. Leave the maths nonsense at the door.
Thinking about you amendment, it could be possible that your 'opponent' meant was that an 'empty' std::string still has an internal storage for characters which is itself empty of characters. That would be an implementation detail I am sure, it could perhaps just keep a certain size (say 10) array of characters 'just incase', so it will technically not be empty.
Of course, there is the trick question answer that 'nothing' fits into anything infinite times, a sort of 'divide by zero' situation.
Today I had the same question since I'm currently bound to a lousy STL implementation (dating back to the pre-C++98 era) that differs from C++98 and all following standards:
TEST_ASSERT(std::string().find(std::string()) == string::npos); // WRONG!!! (non-standard)
This is especially bad if you try to write portable code because it's so hard to prove that no feature depends on that behaviour. Sadly in my case that's actually true: it does string processing to shorten phone numbers input depending on a subscriber line spec.
On Cppreference, I see in std::basic_string::find an explicit description about empty strings that I think matches exactly the case in question:
an empty substring is found at pos if and only if pos <= size()
The referred pos defines the position where to start the search, it defaults to 0 (the beginning).
A standard-compliant C++ Standard Library will pass the following tests:
TEST_ASSERT(std::string().find(std::string()) == 0);
TEST_ASSERT(std::string().substr(0, 0).empty());
TEST_ASSERT(std::string().substr().empty());
This interpretation of "contain" answers the question with yes.

Does strcmp in C++ check every value in a string if the second parameter is "0"?

If my string input is 1234567890, and I do the following:
(strcmp(input,"0"))
Will that return 1 if there is a 0 in my character array of 1234567890 and 0 if there isn't?
I know I can test this, and I did, and the answer is yes, but I'm not sure why and I can't find absolute specifics on strcmp.
No. strcmp returns 0 if the two strings are the same, non 0 otherwise.
Looks like you didn't even bother to google!
No, it compares two strings.
strcmp() returns 0 only if both strings are the same. Otherwise, the return value says something about the first non-matching character.
In your case, this has to do with the comparison between '1' and your '0'. It makes no difference that the other string has a '0' at the end.
strcmp() will typically check all characters from the first one until the last one or until there's a mismatch in the two strings.
The exact internal implementation of strcmp(), if you're asking about that, is not specified in the language standard. In theory, it could find lengths of the two strings and if they are equal, compare the strings using units bigger than char and even do that backwards.
strcmp() compares strings, not searches for one in the other. It returns 0 if the strings are identical. Otherwise it returns either a positive or a negative value, representing the sign of the difference between the first mismatching characters (the characters' values being treated as unsigned).
Does strcmp in C++ check every value in a string if the second
parameter is “0”
No it does not, strcmp() is a string compare function which checks if one string equals another. If it does, it returns 0 if one string is ordinally greater than the other, it returns 1 and returns -1 otherwise.
To check if it does exist, I suggest you write your own function for this.
//return 1 if if the character exists, 0 otherwise
int DoesCharExist(const char *pData, char character)
{
char *data = pData;
while(*data++){
if(*data == character) return 1;
}
return 0;
}