C++ comparing a char to a string literal [duplicate] - c++

This question already has answers here:
c++ compile error: ISO C++ forbids comparison between pointer and integer
(5 answers)
Closed 5 years ago.
Beginning programmer here...
I'm writing a very simply program for my computer science class and I ran into an issue that I'd like to know more about. Here is my code:
#include <iostream>
using namespace std;
int main(int argc, const char * argv[])
{
char courseLevel;
cout << "Will you be taking graduate or undergraduate level courses (enter 'U'"
" for undergraduate,'G' for graduate.";
cin >> courseLevel;
if (courseLevel == "U")
{
cout << "You selected undergraduate level courses.";
}
return 0;
}
I'm getting two error messages for my if statement:
1) Result of comparison against a string literal is unspecified (use strncmp instead).
2) Comparison between pointer and integer ('int' and 'const char*').
I seem to have resolved the issue by enclosing my U in single quotes, or the program at least works anyway. But, as I stated, I'd simply like to understand why I was getting the error so I can get a better understanding of what I'm doing.

You need to use single quotes instead.
In C, (and many other languages) a character constant is a single character1 contained in single quotes:
'U'
While a string literal is any number of characters contained in double quotes:
"U"
You declared courseLevel as a single character: char courseLevel; So you can only compare that to another single char.
When you do if (courseLevel == "U"), the left side is a char, while the right side is a const char* -- a pointer to the first char in that string literal. Your compiler is telling you this:
Comparison between pointer and integer ('int' and 'const char*')
So your options are:
if (courseLevel == 'U') // compare char to char
Or, for sake of example:
if (courseLevel == "U"[0]) // compare char to first char in string
Note for completeness: You can have mulit-character constants:
int a = 'abcd'; // 0x61626364 in GCC
But this is certainly not what you're looking for.

Rapptz is right, but I think some more elaboration should help...
courseLevel == "U"
In C and C++, double-quotes create string literals - which are arrays of characters finishing with a numerical-0 ASCII-NUL terminating sentinel character so programs can work out where the text ends. So, you basically are asking if a character is equal to an array of characters... they just can't be compared. Similar questions that are valid are:
does this character variable hold a specific character value: courseLevel == 'U'
does this character variable appear in a specific array: strchr(courseLevel, "U")
does this character variable match the first element in a specific array: courseLevel == "U"[0]
Of course, the first one of these is the one that makes intuitive sense in your program.

The reason why you get an error is because string literals in C and C++ end with a null terminated character \0 while single characters don't. So when you compare to a char to a string literal you're comparing the character literal to a char array {'U','\0'}.

Related

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"))

Why do 'char' values have to have single quotation marks instead of double? [duplicate]

This question already has answers here:
Single quotes vs. double quotes in C or C++
(15 answers)
Closed 5 years ago.
Goal
At the end, I want to know why C++ doesn't support char letter = "C"; but does support char letter = 'C'; (notice that the quotation marks are different).
Code
I am using Repl.it as a code platform.
#include <iostream>
int main()
{
char letter = "C";
std::cout << letter;
}
Error message
main.cpp: In function 'int main()':
main.cpp:5:19: error: invalid conversion from 'const char*' to 'char' [-fpermissive]
char letter = "C";
They are needed because 'C' and "C" represent completely different types - the first is an integer value, while the second is an array of two characters (the letter 'C' plus an implicit null-terminator). Both are useful, and you need some way of saying which one you want, which is what the different kinds of quotes do.
Single quotes are for single characters whereas double quotes are used to create string literals. They mean different things.
See a more thorough explanation.

Convert a single character to lowercase in C++ - tolower is returning an integer

I'm trying to convert a string to lowercase, and am treating it as a char* and iterating through each index. The problem is that the tolower function I read about online is not actually converting a char to lowercase: it's taking char as input and returning an integer.
cout << tolower('T') << endl;
prints 116 to the console when it should be printing T.
Is there a better way for me to convert a string to lowercase?
I've looked around online, and most sources say to "use tolower and iterate through the char array", which doesn't seem to be working for me.
So my two questions are:
What am I doing wrong with the tolower function that's making it return 116 instead of 't' when I call tolower('T')
Are there better ways to convert a string to lowercase in C++ other than using tolower on each individual character?
That's because there are two different tolower functions. The one that you're using is this one, which returns an int. That's why it's printing 116. That's the ASCII value of 't'. If you want to print a char, you can just cast it back to a char.
Alternatively, you could use this one, which actually returns the type you would expect it to return:
std::cout << std::tolower('T', std::locale()); // prints t
In response to your second question:
Are there better ways to convert a string to lowercase in C++ other than using tolower on each individual character?
Nope.
116 is indeed the correct value, however this is simply an issue of how std::cout handles integers, use char(tolower(c)) to achieve your desired results
std::cout << char(tolower('T')); // print it like this
It's even weirder than that - it takes an int and returns an int. See http://en.cppreference.com/w/cpp/string/byte/tolower.
You need to ensure the value you pass it is representable as an unsigned char - no negative values allowed, even if char is signed.
So you might end up with something like this:
char c = static_cast<char>(tolower(static_cast<unsigned char>('T')));
Ugly isn't it? But in any case converting one character at a time is very limiting. Try converting 'ß' to upper case, for example.
To lower is int so it returns int. If you check #include <ctype> you will see that definition is int tolower ( int c ); You can use loop to go trough string and to change every single char to lowe case. For example
while (str[i]) // going trough string
{
c=str[i]; // ging c value of current char in string
putchar (tolower(c)); // changing to lower case
i++; //incrementing
}
the documentation of int to_lower(int ch) mandates that ch must either be representable as an unsigned char or must be equal to EOF (which is usually -1, but don't rely on that).
It's not uncommon for character manipulation functions that have been inherited from the c standard library to work in terms of ints. There are two reasons for this:
In the early days of C, all arguments were promoted to int (function prototypes did not exist).
For consistency these functions need to handle the EOF case, which for obvious reasons cannot be a value representable by a char, since that would mean we'd have to lose one of the legitimate encodings for a character.
http://en.cppreference.com/w/cpp/string/byte/tolower
The answer is to cast the result to a char before printing.
e.g.:
std::cout << static_cast<char>(std::to_lower('A'));
Generally speaking to convert an uppercase character to a lowercase, you only need to add 32 to the uppercase character as this number is the ASCII code difference between lowercase and uppercase characters, e.g., 'a'-'A'=97-67=32.
char c = 'B';
c += 32; // c is now 'b'
printf("c=%c\n", c);
Another easy way would be to first map the uppercase character to an offset within the range of English alphabets 0-25 i.e. 'a' is index '0' and 'z' is index '25' inclusive and then remap it to a lowercase character.
char c = 'B';
c = c - 'A' + 'a'; // c is now 'b'
printf("c=%c\n", c);

initialize char array with quotes and curly braces

I'm little confused. What is the logically difference between these codes?
#include <iostream>
using namespace std;
int main(){
char a[5]="ABCD"; // this
cout << a;
return 0;
}
Second is
char a[5]={"ABCD"}; // this
Third is
char a[5]={'A','B','C','D'}; // this
char a[5]={"ABCD"};
char a[5]={'A','B','C','D','\0'};
In both cases, the array of characters a is declared with a size of 5 elements of type char: the 4 characters that compose the word "ABCD", plus a final null character ('\0'), which specifies the end of the sequence and that, in the second case, when using double quotes (") it is appended automatically.Attention adding null character separating via commas. A series of characters enclosed in double quotes ("") is called a string constant. The C compiler can automatically add a null character '\0' at the end of a string constant to indicate the end of the string.
Source:This link can help you better
The first two are assignment of a char[5] source to a char[5] array with different syntax only. (the 5 being the four letters plus a null terminator)
The last one will also do the same, but it doesn't explicitly specify a null terminator. Since you are assigning to a char[5], the last one will still zero-fill the remaining space, effectively adding a null terminator and acting the same, but the last one will not throw a compiler error if you assign to a char[4]; it will just leave you with an unterminated array of characters.

c++ work around comparison between pointer and integer

do {
getline (myfile,temp);
if (temp[0] != "="){
MyAlbums[i].tracks.push_back(temp);
}
else {
break;
}
}while(true);
gives me this error:
ISO C++ forbids comparison between pointer and integer [-fpermissive]
i am trying to loop through lines in a text file and 'push_pack' if the line does not begin with an "=" equals character. else i want to break out of the loop.
Any help is very much appriceated!
if (temp[0] != "="){
should be
if (temp[0] != '='){
The reason is that temp[0] is of type char (assume temp is the string you read in), you should compare it with char literal '=' not string literal "=". I am assuming that you read temp successfully, so you may need to check for that if this is not the case.
EDIT(thanks Adam Liss)
strings literals like "=" are of (const char *) type, they are enclosed in double-quotes; individual characters are enclosed in single-quotes. therefore, you have that compile complain message about comparing a char (char literal are integers) with const char *.
Quoting from here:IBM C++ documentation
C A character literal has type int.
C++ A character literal that contains only one character has type char,
which is an integral type.
First, make sure that getline succeeded. Evaluate it in a boolean context to figure that out:
while (getline(myfile, temp)) {
/* code goes here */
}
instead of
do {
getline(myfile, temp);
/* code goes here */
} while (true);
Never, ever do input without checking if it failed immediately, or you will get really annoying bugs to track down.
Second, make sure temp is at least 1 character long. temp.size() >= 1 will be true if it is safe to do temp[0]. If getline ever gives you a string of length 0, doing temp[0] on it will result in undefined behavior. Undefined behavior is really annoying to track down, because it can behave completely innocuous in one situation, and then bite you in an unexpected place later.
Third, do temp[0] != '=' instead of temp[0] != "=". '=' is a character, "=" is a buffer of 2 characters the first one is '=' the second is '\0'. The array of two characters denoted by "=" is implicitly converted into a pointer to the first character when you try to do !=, which then generates an error (because it has no idea how to compare a pointer to a character to a character).