char type declaration and verification - c++

How to check the char type? my variable input need to be a char, cause it contain letters and numbers.
If I use string instead of char, I don't have error with while, but I have error with cin.getline(input,10)
char input[10];
while(input != "1") //Error: result of comparison against a string literal is unspecified(use strncmp //instead)
{
cin.getline(input, 10);
}

In expressions (with rare exception as for example when they are used in sizeof operator) arrays are implicitly converted to pointers to their first elements.
In this condition
while(input != "1")
there are compared addresses of the first character of the array input and of the first character of the string literal "1".
Use instead standard C function strcmp declared in the header <cstring>.
Pay attention to that in your code snippet the array input is not initialized. So before comparing it with something you have to initialize it.

Related

How to handle POST requests in c++ CGI [duplicate]

This question already has answers here:
How do I properly compare strings in C?
(10 answers)
Closed 1 year ago.
int main (int argc, **argv)
{
if (argv[1] == "-hello")
printf("True\n");
else
printf("False\n");
}
# ./myProg -hello
False
Why? I realize strcmp(argv[1], "-hello") == 0 returns true... but why can't I use the equality operator to compare two C strings?
Because argv[1] (for instance) is actually a pointer to the string. So all you're doing is comparing pointers.
You can't compare strings in C with ==, because the C compiler does not really have a clue about strings beyond a string-literal.
The compiler sees a comparison with a char* on either side, so it does a pointer comparison (which compares the addresses stored in the pointers)
In C because, in most contexts, an array "decays into a pointer to its first element".
So, when you have the array "foobar" and use it in most contexts, it decays into a pointer:
if (name == "foobar") /* ... */; /* comparing name with a pointer */
What you want it to compare the contents of the array with something. You can do that manually
if ('p' == *("foobar")) /* ... */; /* false: 'p' != 'f' */
if ('m' == *("foobar"+1)) /* ... */; /* false: 'm' != 'o' */
if ('g' == *("foobar"+2)) /* ... */; /* false: 'g' != 'o' */
or automatically
if (strcmp(name, "foobar")) /* name is not "foobar" */;
Because there is no such thing as a C string.
In C, a string is usually an array of char, or a pointer to char (which is nearly the same). Comparing a pointer/array to a const array won't give the expected results.
UPDATE: what I meant by 'no C string' is, there is no string in C. What's usually referred to as a 'C string' is language independent (as 'Pascal string' is), it's the representation of strings as a null-terminated linear array of characters.
In C, string values (including string literals) are represented as arrays of char followed by a 0 terminator, and you cannot use the == operator to compare array contents; the language simply doesn't define the operation.
Except when it is the operand of either the sizeof or & operators, or when it is a string literal being used to initialize another array in a declaration, an expression with type "N-element array of T" will have its type implicitly converted (decay) to type "pointer to T", and the value of the expression will be the address of the first element of the array.
So when you write
if (argv[1] == "-hello")
the compiler implicitly converts the expression "-hello" from type "7-element array of char" to "pointer to char" (argv[1] is already a pointer type), and the value of the expression is the address of the character '-'. So what == winds up comparing are two pointer values, which are (most likely) never going to be equal since "-hello" and argv[1] (most likely) occupy different regions in memory.
This is why you have to use library functions like strcmp() to compare string values.
Because C strings dont exist as such. They are char arrays ending in a \0.
The equality operator == will test that the pointer to the first element of the array are the same. It wont compare lexicographically.
On the other hand "-hello" == "-hello" may return non zero, but that doesn't mean that the == operator compares lexicographycally. That's due to other facts.
If you want to compare lexicographycally, you can always
#define STR_EQ(s1,s2) \
strcmp(s1,s2) == 0
Reading harder I see that you tagged as c++. So you could
std::string arg1 ( argv[1] );
if (arg1 == "-hello"){
// yeahh!!!
}
else{
//awwwww
}
Strings are not native types in C. What you are comparing in that example are two pointers. One to your first argument, and the other is a static character array with the contents of "-hello".
You really want to use strncmp or something similar.
When you're using ==, you're comparing pointers. That is, it will return true if the two operands refer to the same string in memory. Therefore, it's unsuitable for use in comparing strings lexicographically.
Because C strings are array of characters. Arrays are simply pointers to the first element in the array, and when you compare two pointers using == it compares the memory address they point to, not the values that they point to.

Is a c-style string containing only one char considered a string?

Is a c-style string containing only one char considered a string or would you call that construct a char?
Zero or more characters followed by a NUL-terminator is a C-style string. You can use the double quotation character notation to define a literal.
In C, an int that can fit into a char, such as '3' is a char.
Something like '34' is multicharacter literal.
A one element buffer is still technically a buffer. Forming a pointer to the start of it is not at all affected by how many items are in it.
So no, it's not a char. Furthermore, even the type system would differentiate char[1] from char.
It's also worth nothing that you may be surprised by what is a 1 character string. Because this one "a" has two characters in the buffer, not one. The only one character buffer that is a valid C-string is the empty string.
Is a c-style string containing only one char considered a string or
would you call that construct a char?
Indeed a C-Style string means a string i.e. it is quite different from a char data type. Since in C language, You don't have a dedicated built-in type to manipulate and represent string type like in C++ we have std::string hence once has to use character arrays (essentially null terminated) i.e. char str[SIZE] = "something" to represent character string type. On the other hand a single character is stored in char which is altogether different from char []. These two things are not same!
Example,
char str[] = "a"; // sizeof(str) will give 2 because presence of extra NULL character
char c = 'a'; // simply a single character

C++ Comparison of String Literals

I'm a c++ newbie (just oldschool c). My son asked for help with this and I'm unable to explain it. If he had asked me "how do I compare strings" I would have told him to use strcmp(), but that isn't what is confusing me. Here is what he asked:
int main()
{
cout << ("A"< "Z");
}
will print 1
int main()
{
cout << ("Z"< "A");
}
will also print 1, but
int main()
{
cout << ("Z"< "A");
cout << ("A"< "Z");
}
will then print 10. Individually both cout statements print 1, but executed in a row I get a different answer?
You are comparing memory addresses. Apparently your compiler places the string literals in memory in the order it encounters them, so the first is "lesser" than the second.
Since in the first snippet it sees "A" first and "Z" second, "A" is lesser. Since it sees "Z" first in the second, "Z" is lesser. In the last snippet, it already has literals "A" and "Z" placed when the second command rolls around.
String literals have static storage duration. In all these comparisons there are compared addresses of memory allocated by the compiler for string literals. It seems that the first string literal that is encountered by the compiler is stored in memory with a lower address compared with the next encountered string literal.
Thus in this program
int main()
{
cout << ("Z"< "A");
cout << ("A"< "Z");
}
string literal "Z" was alllocated with a lower address than string literal "A" because it was found first by the compiler.
Take into account that comparison
cout << ("A"< "A");
can give different results depending on the options of the compiler because the compiler may either allocate two extents of memory for the string literals or use only one copy of the string literals that are the same.
From the C++ Standard (2.14.5 String literals)
12 Whether all string literals are distinct (that is, are stored in
nonoverlapping objects) is implementation defined. The effect of
attempting to modify a string literal is undefined.
The same is valid for C.
In the statement:
cout << ("A"< "Z");
You have created 2 string literals: "A" and "Z". These are of type const char * which is a pointer to a null terminated array of characters. The comparison here is comparing the pointers and not the values that they point to. It's this comparing of memory addresses here which is what gives you the compiler warning. The result of the comparison is going to be determined by where the compiler allocated the memory to which is going to be somewhat arbitrary from compiler to compiler. In this case it looks like the first literal found is getting assigned the first memory address by your compiler.
Just like in C to compare these string literals properly you need to use strcmp which will do a value comparison.
However when you do something the more idiomatic c++ way by doing:
cout << (std::string("A") < std::string("Z"));
Then you get the proper comparison of the values as that comparison operator is defined for std::string.
If you want to compare actual C++ strings, you need to declare C++ strings:
int main()
{
const std::string a("A");
const std::string z("Z");
cout << (z < a) << endl; // false
cout << (a < z) << endl; // true
}
In C++, the results are unspecified. I will be using N3337 for C++11.
First, we have to look at what the type of a string literal is.
§2.14.5
9 Ordinary string literals and UTF-8 string literals are also
referred to as narrow string literals. A narrow string literal has
type "array of n const char", where n is the size of the string
as defined below, and has static storage duration (3.7).
Arrays are colloquially said to decay to pointers.
§4.2
1 An lvalue or rvalue of type "array of N T" or "array of unknown
bound of T" can be converted to a prvalue of type "pointer to T".
The result is a pointer to the first element of the array.
Since your string literals both contain one character, they're the same type (char[2], including the null character.)
Therefore the following paragraph applies:
§5.9
2 [...]
Pointers to objects or functions of the same type (after pointer
conversions) can be compared, with a result defined as follows:
[...]
— If two pointers p and q of the same type point to different
objects that are not members of the same object or elements of the
same array or to different functions, or if only one of them is null,
the results of p<q, p>q, p<=q, and p>=q are unspecified.
Unspecified means that the behavior depends on the implementation. We can see that GCC gives a warning about this:
warning: comparison with string literal results in unspecified behaviour [-Waddress]
std::cout << ("Z" < "A");
The behavior may change across compilers or compiler settings but in practice for what happens, see Wintermute's answer.
You are comparing memory addresses. The example that follow explains how to compare 2 strings:
#include "stdafx.h"
#include <iostream>
#include <cstring> //prototype for strcmp()
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
cout << strcmp("A", "Z"); // will print -1
cout << strcmp("Z", "A"); // will print 1
return 0;
}
The string constants ("A" and "Z") in C++ are represented by the C concept - array of characters where the last character is '\0'. Such constants have to be compared with strcmp() type of function.
If you would like to use the C++ std::string comparison you have to explicitly state it:
cout << (std::string( "A") < "Z");
A String is representing a pointer to memory area. So you at first compare only memory addresses with such code
"Z"< "A"
comparing strings is done with functions. They depend on "what kind of string" you have. You have char array strings, but they mid also be objects. These objects have other comparision functions. For instance the CString in MFC has the Compare but also the CompareNoCase function.
For your strings you best use the strcmp. If you debug and step in you see what the function does: it compares every char of both strings and return an integer if the first difference occurs or zero if the same.
int result = strcmp("Z", "A");
Here you find some further sample code

comparing a char to a const char * [duplicate]

This question already has answers here:
c++ compile error: ISO C++ forbids comparison between pointer and integer
(5 answers)
Closed 5 years ago.
string line = "blerdy blah";
for (int i = 0; i < string.size(); i++)
{
line[i] != "n";
}
With this I get the error "cannot convert from char to const char *"
If I replace the last line with
line[i] != *"n";
It works. I get why in one sense, I'm dereferencing a pointer. What I don't get is why it's a pointer in the first place. Is any char written like this actually a pointer to one char somewhere? Like the program has one set of every symbol somewhere and this is what I'm pointing to?
If this is the case, can I do silly things like make the 'n' pointer point to something else?
You have to compare char with char in this case:
line[i] != 'n';
When you say *"n" you actually dereference the first element of the char array with n and \0 elements inside it, which gives you n, that's why it works, but you don't want to write it like that.
"n" is not a character literal, it is a string literal. You want 'n'.
"n" is a char array (string). While 'n' is a char.
"n" is a so called string literal, which has the type const char[2]. string::operator[] (actually basic_string<char>::operator[] returns a const char& or char& depending on the picked overload (the second one in this case). You cannot compare those types. What you want want to compare the result of operator[] to is a character literal, which is written as 'n'.
For your second question
"n" has type const char[2], dereferencing it gives you a char (the first character in the array pointed to). This is equivalent to "n"[0].
Change "n" to 'n'. The difference is that the former is a const char* whereas the latter is char. Since you want to compare one char to another, the latter is the correct form to use.
Why and how this works
Start with "n": lexically it is a null-terminated string literal, which means that the compiler will end up treating it as a char* pointing to a section of memory that holds the string "n".
So when you write *"n", what happens is that you are dereferencing a char* that points to "n", which means that the result of the expression will be 'n' (of type char). That's why the comparison to line[i] (which is also a char) works.
This pointer to "n" is a compile-time constant (so you can't change it) and in all likelihood will point to a read-only memory page (so you won't be able to change what it points to at runtime either).
What you should do instead
line[i] != 'n'; // compare char to char

Comparing character arrays and string literals in C++

I have a character array and I'm trying to figure out if it matches a string literal, for example:
char value[] = "yes";
if(value == "yes") {
// code block
} else {
// code block
}
This resulted in the following error: comparison with string literal results in unspecified behavior. I also tried something like:
char value[] = "yes";
if(strcmp(value, "yes")) {
// code block
} else {
// code block
}
This didn't yield any compiler errors but it is not behaving as expected.
Check the documentation for strcmp. Hint: it doesn't return a boolean value.
ETA: == doesn't work in general because cstr1 == cstr2 compares pointers, so that comparison will only be true if cstr1 and cstr2 point to the same memory location, even if they happen to both refer to strings that are lexicographically equal. What you tried (comparing a cstring to a literal, e.g. cstr == "yes") especially won't work, because the standard doesn't require it to. In a reasonable implementation I doubt it would explode, but cstr == "yes" is unlikely to ever succeed, because cstr is unlikely to refer to the address that the string constant "yes" lives in.
std::strcmp returns 0 if strings are equal.
strcmp returns a tri-state value to indicate what the relative order of the two strings are. When making a call like strcmp(a, b), the function returns
a value < 0 when a < b
0 when a == b
a value > 0 when a > b
As the question is tagged with c++, in addition to David Seilers excellent explanation on why strcmp() did not work in your case, I want to point out, that strcmp() does not work on character arrays in general, only on null-terminated character arrays (Source).
In your case, you are assigning a string literal to a character array, which will result in a null-terminated character array automatically, so no problem here. But, if you slice your character array out of e. g. a buffer, it may not be null-terminated. In such cases, it is dangerous to use strcmp() as it will traverse the memory until it finds a null byte ('\0') to form a string.
Another solution to your problem would be (using C++ std::string):
char value[] = "yes";
if (std::string{value} == "yes")) {
// code block
} else {
// code block
}
This will also only work for null-terminated character arrays. If your character array is not null-terminated, tell the std::string constructor how long your character array is:
char value[3] = "yes";
if (std::string{value, 3} == "yes")) {
// code block
} else {
// code block
}