comparing a char to a const char * [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.
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

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.

How does conversion of string literals to char arrays actually work in C++?

I am trying to understand how pointers,arrays and string literals work in C++.
Suppose we have the following line of code:
const char* const letters[] = {"A+","A"};
If I understand correctly, this declaration declares letters to be an array of constant pointers to constant characters. From my understanding, the compiler will actually convert each string literal to a null terminated char array and each element of letters is actually a constant pointer to the first element of that array.
So, for instance, letters[0] is actually a pointer to the "A" of "A+". However
std::cout<< letters[0];
actually outputs "A+" to the standard output. How can this be? Especially since letters[0] is a constant pointer?
My second question is related to the declaration above: if string literals are actually const char arrays, then why does the following line of code
const char* const letters[] = {{'A','+','\0'},{'A','\0'}};
throws
error: braces around scalar initializer for type ‘const char* const’
const char* const letters[] = {{'A','+','\0'},{'A','\0'}};
^
Thank you!
The standard specifies that a string literal is represented - as far as your program is concerned - as an array of const characters of static storage duration with a trailing '\0' terminator. The standard doesn't specify HOW a compiler achieves this effect, only that your program can treat the string literal in that way.
So modifying a string literal is either prevented (e.g. passing a string literal to a function expecting a char * is a diagnosable error, and the code will not compile) or - if code works around the type system to modify any character in a string literal - involves undefined behaviour.
In your example, letters[0] is of type const char *, and has a value equal to the address of the first character in the string literal "A+".
std::cout, being of type std::ostream, has an operator<<() that accepts a const char *. This function is called by the statement std::cout << letters[0] and the function assumes the const char * points at a zero-terminated array of char. It iterates over that array, outputting each character individually, until it encounters the trailing '\0' (which is not output).
The thing is, a const char * means that the pointer is to a const char, not that the pointer cannot be changed (that would be char * const). So it is possible to increment the pointer, but not change the value it points at. So, if we do
const char *p = letters[0];
while (*p != '\0')
{
std::cout << *p;
++p;
}
which loops over the characters of the string literal "A+", printing each one individually, and stopping when it reaches the '\0' (the above produces the same observable output std::cout << letters[0]).
However, in the above
*p = 'C';
will not compile, since the definition of p tells the compiler that *p cannot be changed. However, incrementing p is still allowed.
The reason that
const char* const letters [] = {{'A','+','\0'},{'A','\0'}};
does not compile is that an array initialiser cannot be used to initialise pointers. For example;
const int *nums = {1,2,3}; // invalid
const * const int nums2 [] = {{1,2,3}, {4,5,6}}; // invalid
are both illegal. Instead, one is required to define arrays, not pointers.
const int nums[] = {1,2,3};
const int nums2[][3] = {{1,2,3}, {4,5,6}};
All versions of C and C++ forbid initialising pointers (or arrays of pointers in your example) in this way.
Technically, the ability to use string literals to initialise pointers is actually the anomaly, not the prohibition on initialising pointers using arrays. The reasons C introduced that exemption for string literals are historical (in very early days of C, well before K&R C, string literals could not be used to initialise pointers either).
As for your first question, the type of letters[0] is const char * const. This is a pointer to a character, but not a character itself. When passing a pointer to a character to std::cout, it will treat it as a NUL-terminated C string, and writes out all characters from the start of the memory pointed to until it encounters a NUL-byte. So that is why the output will be A+. You can pass the first character of the first string by itself by writing:
std::cout << letters[0][0];
The fact that the pointers and/or the C strings themselves are const doesn't matter here, since nothing is writing to them.
As for your second question, const char * const declares a single array, but you are providing a nested array on the right-hand side of that statement. If you really wanted two arrays of characters, write:
const char *const letters[] = {{'A', '+', '\0'}, {'A', '\0'}};
That is equal to your code form the first question. Or if you want a single array:
const char *const letters = {'A', '+', '\0', 'A', '\0'};
That line is equal to:
const char *const letters = "A+\0A";

pointer to string and char catch 22

I'm studying on pointers and I'm stuck when I see char *p[10]. Because something is misunderstood. Can someone explain step-by-step and blow-by-blow why my logic is wrong and what the mistakes are and where did I think wrong and how should I think. Because I want to learn exactly. Also what about int *p[10]; ? Besides, for example x is a pointer to char but just char not chars. But how come char *x = "possible";
I think above one should be right but, I have seen for char *name[] = { "no month","jan","feb" }; I am really confused.
Your char *p[10] diagram shows an array where each element points to a character.
You could construct it like this:
char f = 'f';
char i = 'i';
char l1 = 'l';
char l2 = 'l';
char a1 = 'a';
char r1 = 'r';
char r2 = 'r';
char a2 = 'a';
char y = 'y';
char nul = '\0';
char *p[10] = { &f, &i, &l1, &l2, &a1, &r1, &r2, &a2, &y, &nul };
This is very different from the array
char p[10] = {'f', 'i', 'l', 'l', 'a', 'r', 'r', 'a', 'y', '\0'};
or
char p[10] = "fillarray";
which are arrays of characters, not pointers.
A pointer can equally well point to the first element of an array, as you've probably seen in constructions like
const char *p = "fillarray";
where p holds the address of the first element of an array defined by the literal.
This works because an array can decay into a pointer to its first element.
The same thing happens if you make an array of pointers:
/* Each element is a pointer to the first element of the corresponding string in the initialiser. */
const char *name[] = { "no month","jan","feb" };
You would get the same results with
const char* name[3];
name[0] = "no month";
name[1] = "jan";
name[2] = "feb";
char c = 'a';
Here, c is a char, typically a single byte of ASCII encoded data.
char* ptr = &c;
ptr is a char pointer. In C, all it does is point to a memory location and doesn't make any guarantees about what is at that location. You could use a char* to pass a char to a function to allow the function to allow the function to make changes to that char (pass by reference).
A common C convention is for a char* to point to a memory location where several characters are stored in sequence followed by the null character \0. This convention is called a C string:
char const* cstr = "hello";
cstr points to a block of memory 6 bytes long, ending with a null character. The data itself cannot be modified, though the pointer can be changed to point to something else.
An array of chars looks similar, but behaves slightly differently.
char arr[] = "hello";
Here arr IS a memory block of 6 chars. Since arr represents the memory itself, it cannot be changed to point to another location. The data can be modified though.
Now,
char const* name[] = { "Jan", " Feb"..., "Dec"};
is an array of pointer to characters.
name is a block of memory, each containing a pointer to a null-terminated string.
In the diagram, I think string* was accidentally used instead of char*. The difference between the left and the right, is not a technical difference really, but a difference in the way a char* is used. On the left each char* points to a single character, whereas in the one on the right, each char* points to a null-terminated block of characters.
Both are right.
A pointer in C or C++ may point either to a single item (a single char) or to the first in an array of items (char[]).
So a char *p[10]; definition may point to 10 single characters or 10 arrays (i.e. 10 strings).
Let’s go back to basics.
First, char *p is simply a pointer. p contains nothing more than a memory address. That memory address can point to anything, anywhere. By convention, we have always used NULL (or, I hate this method, assigning it to zero – yeah, they are the same “thing”, but NULL has traditionally been used in conjunction with pointers, so when you’re eyes flit across the code, you see NULL – you think “pointer”).
Anyway, that memory address being pointed to can contain anything. So, to use within the language, we type it, in this case it is a pointer to a character (char *p). This can be overridden by type casting, but that’s for a later time.
Second, we know anytime we see p[10], that we are dealing with an array. Again, the array can be an array of characters, an array of ints, etc. – but it’s still an array.
Your example: char *p[10], is then nothing more than an array of 10 character pointers. Nothing more, nothing less. Your problem comes in because you are trying to force the “string” concept onto this. There ain’t no strings in C. There ain’t no objects in C. The concept of a NULL-terminated string can most certainly be used. But a “string” in C is nothing more than an array of characters, terminated by a NULL (or, if you use some of the appropriate functions, you can use a specific number of characters – strncpy instead of strcpy, etc.). But, for all its appearance, and apparent use, there are no strings in C. They are nothing more than arrays of characters, with a few supporting functions that happen to stop going through the array when a NULL is encountered.
So – char a[10] – is simply an array of characters that is 10 characters long. You can fill it with any characters you wish. If one of those is the NULL character, then that terminates what is typically called a “C-style string”. There are functions that support this type of character array (i.e. “string”), but it is still a use of a character array.
Your confusion comes in because you are trying to mix C++ string objects, and forcing that concept onto C arrays of characters. As ugoren noted – your examples are both correct – because you are dealing with arrays of character pointers, NOT strings. Again, putting a NULL somewhere in that character array is happily supported by several C functions that give you the ability to work with a “string-like” concept – but they are not truly strings. Unless of course, you want to phrase it that a string is nothing more than one character following another – an array.

Why can std::cout print a char[]? [duplicate]

This question already has answers here:
cout << with char* argument prints string, not pointer value
(6 answers)
Closed 5 years ago.
Below code prints the entire string. I am confused why its does so.
char test[] = "jeff";
cout<<test<<endl;
The output is "Jeff", I was expecting it to print the value of char array "test", since test is pointer, pointer the first element which is 'J'.
Why is it printing the whole string, when I cout<<test??
Because of operator<< (basic_ostream<charT,traits>& os, const char* s); (#2 "character sequence" in that list) (slightly more technical list). test decays to a pointer, or char*, which then gets printed as a C-string.
It's the exact same reason cout << "Jeff"; works (instead of printing the address of "Jeff").
The first element is 'j', certainly, but a char* isn't meant to represent only one char, but a string of them. cout will keep reading chars til it find the null char, or '\0'. This is implicitly put there when you use a string literal such as "jeff".
To print only the first char, dereference the pointer to get it like cout<<*test<<endl;.
In C++ (as in C), strings are modeled as NUL-terminated character arrays I.e., the last character's ordinal value is 0, in your example it's character with index 4, inserted by the compiler immediately after the last "f" in "jeff". So in many contexts pointers to "char" are assumed to be NUL-terminated; in this case "cout" keeps printing characters until it hits the NUL character at the end, at which point it stops. C++ also has an actual string class, "std::string", that is in many ways superior to char arrays.

What is a char*?

Why do we need the *?
char* test = "testing";
From what I understood, we only apply * onto addresses.
This is a char:
char c = 't';
It can only hold one character!
This is a C-string:
char s[] = "test";
It can hold multiple characters. Another way to write the above is:
char s[] = {'t', 'e', 's', 't', 0};
The 0 at the end is called the NUL terminator. It denotes the end of a C-string.
A char* stores the starting memory location of a C-string.1 For example, we can use it to refer to the same array s that we defined above. We do this by setting our char* to the memory location of the first element of s:
char* p = &(s[0]);
The & operator gives us the memory location of s[0].
Here is a shorter way to write the above:
char* p = s;
Notice:
*(p + 0) == 't'
*(p + 1) == 'e'
*(p + 2) == 's'
*(p + 3) == 't'
*(p + 4) == 0 // NUL
Or, alternatively:
p[0] == 't'
p[1] == 'e'
p[2] == 's'
p[3] == 't'
p[4] == 0 // NUL
Another common usage of char* is to refer to the memory location of a string literal:
const char* myStringLiteral = "test";
Warning: This string literal should not be changed at runtime. We use const to warn the programmer (and compiler) not to modify myStringLiteral in the following illegal manner:
myStringLiteral[0] = 'b'; // Illegal! Do not do this for const char*!
This is different from the array s above, which we are allowed to modify. This is because the string literal "test" is automatically copied into the array at initialization phase. But with myStringLiteral, no such copying occurs. (Where would we copy to, anyways? There's no array to hold our data... just a lonely char*!)
1 Technical note: char* merely stores a memory location to things of type char. It can certainly refer to just a single char. However, it is much more common to use char* to refer to C-strings, which are NUL-terminated character sequences, as shown above.
The char type can only represent a single character. When you have a sequence of characters, they are piled next to each other in memory, and the location of the first character in that sequence is returned (assigned to test). Test is nothing more than a pointer to the memory location of the first character in "testing", saying that the type it points to is a char.
You can do one of two things:
char *test = "testing";
or:
char test[] = "testing";
Or, a few variations on those themes like:
char const *test = "testing";
I mention this primarily because it's the one you usually really want.
The bottom line, however, is that char x; will only define a single character. If you want a string of characters, you have to define an array of char or a pointer to char (which you'll initialize with a string literal, as above, more often than not).
There are real differences between the first two options though. char *test=... defines a pointer named test, which is initialized to point to a string literal. The string literal itself is allocated statically (typically right along with the code for your program), and you're not supposed to (attempt to) modify it -- thus the preference for char const *.
The char test[] = .. allocates an array. If it's a global, it's pretty similar to the previous except that it does not allocate a separate space for the pointer to the string literal -- rather, test becomes the name attached to the string literal itself.
If you do this as a local variable, test will still refer directly to the string literal - but since it's a local variable, it allocates "auto" storage (typically on the stack), which gets initialized (usually from a normal, statically allocated string literal) on every entry to the block/scope where it's defined.
The latter versions (with an array of char) can act deceptively similar to a pointer, because the name of an array will decay to the address of the beginning of the array anytime you pass it to a function. There are differences though. You can modify the array, but modifying a string literal gives undefined behavior. Conversely, you can change the pointer to point at some other chars, so something like:
char *test = "testing";
if (whatever)
test = "not testing any more";
...is perfectly fine, but trying to do the same with an array won't work (arrays aren't assignable).
The main thing people forgot to mention is that "testing" is an array of chars in memory, there's no such thing as primitive string type in c++. Therefore as with any other array, you can't reference it as if it is an element.
char* represents the address of the beginning of the contiguous block of memory of char's. You need it as you are not using a single char variable you are addressing a whole array of char's
When accessing this, functions will take the address of the first char and step through the memory. This is possible as arrays use contiguous memory (i.e. all of the memory is consecutive in memory).
Hope this clears things up! :)
Using a * says that this variable points to a location in memory. In this case, it is pointing to the location of the string "testing". With a char pointer, you are not limited to just single characters, because now you have more space available to you.
In C a array is represented by a pointer to the first element in it.