String comparison giving different output when used with variable [duplicate] - c++

This question already has answers here:
comparison between string literal
(4 answers)
C++ Comparison of String Literals
(8 answers)
Closed 3 years ago.
Why is the output of the following codes different?
I'm comparing two strings. I don't understand why they give different outputs?
Code 1:
#include <bits/stdc++.h>
using namespace std;
int main() {
if("35" <= "255")
{
cout << 1;
}
cout << 0;
}
Code 2:
#include <bits/stdc++.h>
using namespace std;
int main() {
string num = "35";
if(num <= "255")
{
cout << 1;
}
cout << 0;
}
The output of code 1 is 10. The output of code 2 is 0.

You made the second program different by using std::string.
std::string has an overload for the comparison operator, which compares the content of the operands lexicographically. Lexicographical ordering, which is different from numerical ordering, is same that would be used in a dictionary: 255 comes before (i.e. "is less than") 35, just like aardvark comes before zoo.
The string literals on the other hand are arrays, which will decay to a pointer to first element, and pointer comparison compares the relative location in memory, which has nothing to do with the text content, and which in this case is at best unspecified and you could either see 1 output or not.

A string is not a magic object that understands what it contains and acts differently on it.
In your case, you are comparing the address that hold a buffer of chars (containing '3', '5', 0) with the address containing another buffer of chars (containing '2', '3', '5', 0).
The output is random (in fact, it isn't, but for now, let's assume it is).
If you want to compare strings, you can use the second example (or strcmp) but that will compare the buffer content based on some logical rules, that are not those you except (you expect semantic logic, but it's not).
The rules are:
Compare each buffer char based on their ASCII/Unicode order, and return -1 if the first one is lower than the second one, 1 if it's higher. (If using < operator, it returns true if -1, false otherwise and so on)
If they are equal, continue to next char.
In the previous example, '3' is higher than '2' (even if 35 is smaller than 235).
You'll need to either convert your string to integer before comparing (and deal with potential conversion errors) or use integers from the beginning.

First convert the string to Int and then compare.
Example:
#include <iostream>
using std::cout;
string value1 = "22";
string value2 = "222";
int main()
{
if(std::stoi(value1)<=std::stoi(value2))
{
cout<<"1";
}
cout<<"0";
}

Related

C++: How can I find a specific character in a string with an if? What is the "==" equivalent for strings, if there is one?

For example, I want to detect a negative in a string. I am not sure if converting the char into a const char* would work (and because doing so would be a pain because then I would not know how it would affect the rest of my code. Is there a way I can check if for any value of input[i], it "equals" a dash/negative?
#include <iostream>
#include <string>
#define LOG(x) std::cout<<x<<std::endl;
char solveBIG(std::string input) {
for (int i = 0; i < input.size(); i += 2) {
if (input[i] = "-") {
//
}
}
}
int main() {
std::string example1 = {"1 2 3 - 5"};
LOG(solveBIG(example1))
}
You need to be careful with distinguishing operators = and ==. The first is the assignment operator, and the second is the comparison operator for equality.
You mixed that up a little bit.
Now, how to detect a '-' in the string?
Solution: You will iterate over the string and compare each charcter in the string with the '-' character'.
More explanations:
In many many programming languages, so called loops are used to execute or repeat blocks of code.
Or do iterate over "something". Therefore loops are also called Iteration statements
Also C++ has loops or iteration statements. The basic loop constructs are
for loops,
while loops,
do-while loops
Range-based for loops
Please click on the links and read the descriptions in the C++ reference. You can use any of them to solve your problem.
Additionally, you need to know that a string is a container. Container means that a variable of such a type contains other elements from nearly any type.
A string for example, contains characters.
Example: If you have a string equivalent to "Hello", then it contains the characters 'h', 'e', 'l', 'l', 'o'.
Another nice property of some containers is, that they have an index operator, or better said, a subscript operator []. So, if you want to access a character in your string, you may simply use your variable name with an index specified in the subscript operator.
Very important: Indices in C++ start with 0. So the first character in a string is at index 0. Example:
std::string test = "Hello";
std::cout << test[0];
will print H.
With all the above gained know how, we can now solve your problem easily. We will iterate over all characters in your string, and then check if each character is '-' or not.
One of many many possible implementations:
for (int i = 0; i < input.size(); ++i) {
if (input[i] == '-') {
//
}
}

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.

Subtracting two strings is giving wrong values in c++

#include<iostream>
#include<string>
using namespace std;
int main(){
string s1 = "abc";
string s2 = "xyz";
cout << s2.compare(s1) << endl;
return 0;
}
This is the Simple program in which I am just comparing two string and print the return value of the string::compare function.
Output:
1
The actual output for this program is 23.
This similar thing is happening with the ASCII characters.
#include<iostream>
#include<string>
using namespace std;
int main(){
cout << "a" - "A" << endl;
return 0;
}
The output I am getting after running the above code is:-
Output:
-2
But the output I was expecting is 32. I don't know what's the problem and why I am getting wrong output.
The output of std::string::compare() is according to the documentation:
Return value
negative value if *this appears before the character sequence specified by the arguments, in lexicographical order
zero if both character sequences compare equivalent
positive value if *this appears after the character sequence specified by the arguments, in lexicographical order
s2 is lexicographically later than s1, so compare returns a positive value, exactly as expected.
"a" - "A" is Undefined Behaviour. You are subtracting value of two pointers that do not point to the same array. Any output would be valid, as well as no output, crash, or demons flying out of your nose.
I suppose you wanted to subtract numeric values of characters, which would in fact give 32 (provided that your compiler is using an ASCII-compliant enconding):
'a' - 'A'
The return value of std::string::compare is:
negative value if *this appears before the character sequence specified by the arguments, in lexicographical order
zero if both character sequences compare equivalent
positive value if *this appears after the character sequence specified by the arguments, in lexicographical order
As you see, it is only defined as "negative / zero / positive" and the "negative" and "positive" values need not be -1 and 1.
"a" and "A" are string literals, which represents arrays. Arrays in expressions are automatically converted to pointers pointing at the first elements of them (some exception exists) and substraction of pointers will result in an integer representing the first pointer is how many elements from the second one.
What you wanted to use should be character constants, which are surrounded by ' instead of ".
cout << 'a' - 'A' << endl;
Alternatively, you can get the first elements of the arrays using subscripting operators.
cout << "a"[0] - "A"[0] << endl;
std::string::compare returns a positive or negative number or 0, it may return 1, -1 and 0 but doesn't have to.
"a" - "A" is performing pointer arithmetic on two unrelated pointers so has undefined behaviour. The behaviour you are seeing is probably that the compiler has laid out your constants in memory as "a\0A\0" so your constants are 2 bytes apart giving a result of -2.

Why is strlen(s) different from the size of s, and why does cout char display a character not a number?

I wrote a piece of code to count how many 'e' characters are in a bunch of words.
For example, if I type "I read the news", the counter for how many e's are present should be 3.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[255],n,i,nr=0;
cin.getline(s,255);
for(i=1; i<=strlen(s); i++)
{
if(s[i-1]=='e') nr++;
}
cout<<nr;
return 0;
}
I have 2 unclear things about characters in C++:
In the code above, if I replace strlen(s) with 255, my code just doesn't work. I can only type a word and the program stops. I have been taught at school that strlen(s) is the length for the string s, which in this case, as I declared it, is 255. So, why can't I just type 255, instead of strlen(s)?
If I run the program above normally, it doesn't show me a number, like it is supposed to do. It shows me a character (I believe it is from the ASCII table, but I'm not sure), like a heart or a diamond. It is supposed to print the number of e's from the words.
Can anybody please explain these to me?
strlen(s) gives you the length of the string held in the s variable, up to the first NULL character. So if you input "hello", the length will be 5, even though s has a capacity of 255....
nr is displayed as a character because it's declared as a char. Either declare it as int, for example, or cast it to int when cout'ing, and you'll see a number.
strlen() counts the actual length of strings - the number of real characters up to the first \0 character (marking end of string).
So, if you input "Hello":
sizeof(s) == 255
strlen(s) == 5
For second question, you declare your nr as char type. std::cout recognizes char as a single letter and tries it print it as such. Declare your variable as int type or cast it before printing to avoid this.
int nr = 42;
std::cout << nr;
//or
char charNr = 42;
std::cout << static_cast<int>(charNr);
Additional mistakes not mentioned by others, and notes:
You should always check whether the stream operation was successful before trying to use the result.
i is declared as char and cannot hold values greater than 127 on common platforms. In general, the maximum value for char can be obtained as either CHAR_MAX or std::numeric_limits<char>::max(). So, on common platforms, i <= 255 will always be true because 255 is greater than CHAR_MAX. Incrementing i once it has reached CHAR_MAX, however, is undefined behavior and should never be done. I recommend declaring i at least as int (which is guaranteed to have sufficient range for this particular use case). If you want to be on the safe side, use something like std::ptrdiff_t (add #include <cstddef> at the start of your program), which is guaranteed to be large enough to hold any valid array size.
n is declared but never used. This by itself is harmless but may indicate a design issue. It can also lead to mistakes such as trying to use n instead of nr.
You probably want to output a newline ('\n') at the end, as your program's output may look odd otherwise.
Also note that calling a potentially expensive function such as strlen repeatedly (as in the loop condition) can have negative performance implications (strlen is typically an intrinsic function, though, and the compiler may be able to optimize most calls away).
You do not need strlen anyway, and can use cin.gcount() instead.
Nothing wrong with return 0; except that it is redundant – this is a special case that only applies to the main function.
Here's an improved version of your program, without trying to change your code style overly much:
#include <iostream>
#include <cstring>
#include <cstddef>
using namespace std;
int main()
{
char s[255];
int nr=0;
if ( cin.getline(s,255) )
{ // only if reading was successful
for(int i=0; i<cin.gcount(); i++)
{
if(s[i]=='e') nr++;
}
cout<<nr<<'\n';
}
return 0;
}
For exposition, the following is a more concise and expressive version using std::string (for arbitrary length input), and a standard algorithm. (As an interviewer, I would set this, modulo minor stylistic differences, as the canonical answer i.e. worth full credit.)
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
if ( getline(cin, s) )
{
cout << std::count(begin(s), end(s), 'e') << '\n';
}
}
I have 2 unclear things about characters in C++: 1) In the code above,
if I replace the "strlen(s)" with 255, my code just doesn't work, I
can only type a word and the program stops, and I have been taught at
school that "strlen(s)" is the length for the string s, wich in this
case, as I declared it, is 255. So, why can't I just type 255, instead
of strlen(s);
That's right, but strings only go the null terminator, even if there's more space allocated. Consider this, per example:
char buf[32];
strcpy(buf, "Hello World!");
There's 32 chars worth of space, but my string is only 12 characters long. That's why strlen returns 12 in this example. It's because it doesn't know how long the buffer is, it only knows the address of the string and parses it until it finds the null terminator.
So if you enter 255, you're going past what was set by cin and you'll read the rest of the buffer. Which, in this case, is uninitialized. That's undefined behavior - in this case it will most likely read some rubbish values, and those might coincidentally have the 'e' value and thus give you a wrong result.
2) If you run the program above normaly, it doesn't show you a number,
like it's supposed to do, it shows me a character(I believe it's from
the ASCII table but I'm not sure), like a heart or a diamond, but it
is supposed to print the number of e's from the words. So can anybody
please explain these to me?
You declared nr as char. While that can indeed hold an integer value, if you print it like this, it will be printed as a character. Declare it as int instead or cast it when you print it.

Converting integer to string in c++

This is the code I wrote to convert integer to string.
#include <iostream>
using namespace std;
int main()
{
string s;
int b=5;
s.push_back((char)b);
cout<<s<<endl;
}
I expected the output to be 5 but it is giving me blank space.
I know there is another way of doing it using stringstream but I want to know what is wrong in this method?
Character code for numbers are not equal to the integer the character represents in typical system.
It is granteed that character codes for decimal digits are consecutive (N3337 2.3 Character sets, Paragraph 3), so you can add '0' to convert one-digit number to character.
#include <iostream>
using namespace std;
int main()
{
string s;
int b=5;
s.push_back((char)(b + '0'));
cout<<s<<endl;
}
You are interpreting the integer 5 as a character. In ASCII encoding, 5 is the Enquiry control character as you lookup here.
The character 5 on the other hand is represented by the decimal number 53.
As others said, you can't convert an integer to a string the way you are doing it.
IMHO, the best way to do it is using the C++11 method std::to_string.
Your example would translate to:
using namespace std;
int main()
{
string s;
int b=5;
s = to_string(b);
cout<<s<<endl;
}
The problem in your code is that you are converting the integer 5 to ASCII (=> ENQ ASCII code, which is not "printable").
To convert it to ASCII properly, you have to add the ASCII code of '0' (48), so:
char ascii = b + '0';
However, to convert an integer to std::string use:
std::stringstream ss; //from <sstream>
ss << 5;
std::string s = ss.str ();
I always use this helper function in my projects:
template <typename T>
std::string toString (T arg)
{
std::stringstream ss;
ss << arg;
return ss.str ();
}
Also, you can use stringstream,
std::to_string doesn't work for me on GCC
If we were writing C++ from scratch in 2016, maybe we would make this work. However as it choose to be (mostly) backward compatible with a fairly low level language like C, 'char' is in fact just a number, that string/printing algorithms interpret as a character -but most of the language doesn't treat special. Including the cast. So by doing (char) you're only converting a 32 bit signed number (int) to a 8 bit signed number (char).
Then you interpret it as a character when you print it, since printing functions do treat it special. But the value it gets printed to is not '5'. The correspondence is conventional and completely arbitrary; the first numbers were reserved to special codes which are probably obsolete by now. As Hoffman pointed out, the bit value 5 is the code for Enquiry (whatever it means), while to print '5' the character has to contain the value 53. To print a proper space you'd need to enter 32. It has no meaning other than someone decided this was as good as anything, sometime decades ago, and the convention stuck.
If you need to know for other characters and values, what you need is an "ASCII table". Just google it, you'll find plenty.
You'll notice that numbers and letters of the same case are next to each other in the order you expect, so there is some logic to it at least. Beware, however, it's often not intuitive anyway: uppercase letters are before lowercase ones for instance, so 'A' < 'a'.
I guess you're starting to see why it's better to rely on dedicated system functions for strings!