I wrote a program to swap two strings using pointers.
char *names[]={"Sachin","Kapil","Ajay","Sunil","Anil"};
cout<<"String II is ";cout<<names[1];
cout<<"\nString IV is ";cout<<names[3];
char *t;
t=names[1];
names[1]=names[3];
names[3]=t;
cout<<"\nString II is ";cout<<names[1];
cout<<"\nString IV is ";cout<<names[3];
In the first line I used an array of char pointers to store the address of the 1st characters of the strings.
When I cout names[1] and names[3]:
The entire string was printed,but shouldn't the address of the character pointer alone be printed?
Also,how is the program printing the entire string instead of printing the first character alone?
After I compiled I got a warning from line 1 saying:
warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]|
The program runs as intended,but I would love to know how it is working.I came across an implementation where they used cout.write(names[i],len) to print the entire string(which makes sense),but to my surprise the above method works too (even without any sort of increase in the pointer value to print the next character).
Any tips and suggestions on the issues listed above would be appreciated.Thank you!
First up - why you don't just get the address output.
When you 'insert' any char* into a stream such as std::cout<<s; where s is of type char* the insertion logic assumes s points to the first character of a 'C' String. A 'C' String is a series of characters ending in a nul ('\0' character).
So the insertion logic outputs that series of characters.
You'll get a different result if you use std::cout<<static_cast<void*>(c); because the insertion of a void* pointer is treated differently.
The << operator on streams is overloaded to do different things depending on what you're inserting.
Now why you get that warning. You're uncovering some of the unhappy legacy of C++ particularly baggage inherited from C.
In the bad old days of early C without the const modifier there was no way of indicating that string literals (e.g. "Sachin") couldn't be modified at run-time and on different platforms doing so had different effects ranging from harmlessy amending the data, throwing an access exception to modifying all literal references to that string value in the code (there may be several).
So when C++ came along and introduced const (soon back adopted by C) it was quite rightly seen fit to make the type of string literals in the code const char[]. However some compilers (when you've got the wrong settings!) still allow you to assign literals to char[] (or char*) for backward compatibility.
Unless you're maintaining ancient code and the senior programmer has instructed you accordingly never leave that option enabled.
The stream library recognises the char* type and treats it as a null terminated c-style string which is simply an array of chars terminated by null.
To get it to print addresses, type cast the string to void*.
i.e.
cout << "String II is "; cout << (void *)names[1];
Will now output:
String II is 0x400a0b
As to why the first character is not printed only, it's because the stream library treats it as null terminated C string. But if you really only wanted the first character printed you could just as easily done this:
cout << "String II is "; cout << *names[1];
or:
cout << "String II is "; cout << names[1][0];
Manipulating pointers like you are is OK, but manipulation what they contain is not when declared like you have them. So you should really declared them const. This also removes the compilation warnings.
So the code would become.
const char *names[]={"Sachin","Kapil","Ajay","Sunil","Anil"};
cout << "\nString II is "; cout << (void*)names[1];
cout << "\nString IV is "; cout << (void*)names[3];
const char *t;
t = names[1];
names[1] = names[3];
names[3] = t;
cout << "\nString II is "; cout <<(void*)names[1];
cout << "\nString IV is "; cout <<(void*)names[3];
Related
I was playing around with c strings in c++ and found some behavior I don't understand when I don't terminate a char array.
char strA[2] = {'a','\0'};
char strB[1] = {'b'};
cout << strA << strB;
I would expect this to print ab, but instead it prints aba. If I instead declare strB before strA, it works as expected. Could someone explain what's going on here?
This is undefined behaviour and you simply are lucky that replacing the declaration of these 2 arrays works for you. Let's see what is happening in your code:
char strA[2] = {'a','\0'};
Creates an array that can be treated like a string - it is null terminated.
char strB[1] = {'b'};
Creates an array that cannot be treated like a string, because it lacks the null terminating character '\0'.
std::cout << strA << strB;
The first part, being << strA, works fine. It prints a since strA is treated as a const char*, which provided as an argument for std::ostream& operator << will be used to print every character untill the null terminating character is encountered.
What happens then? Then, the << strB is being executed (actually what happens here is a little different and more complicated than simply dividing this line into two, separate std::cout << calls, but it does not matter here). It is also treated as a const char*, which is expected to ended with mentioned '\0', however it is not...
What does that lead to? You are lucky enough that there randomly is only 1 character before (again - random) '\0' in memory, which stops the (possibly near-infinite) printing process.
Why, if I instead declare strB before strA, it works as expected?
That is because you were lucky enough that the compiler decided to declare your strA just after the strB, thus, when printing the strB, it prints everything that it consists + prints strA, which ends with null terminating character. This is not guaranteed. Avoid using char[] to represent and print strings. Use std::string instead, which takes care of the null terminating character for you.
When printing char arrays, the C (and C++) convention is to print all bytes until a '\0'.
Because of how the local variables are organized, strB's memory is behind strA's, so when printing strB the printing just 'overflows' and keeps printing strA until the terminating '\0'.
I guess when the deceleration is reversed, the printing of strB is terminated by a 0 that is just there because nothing else was set there, but you shouldn't rely on that - this is called a garbage value.
Don't use unterminated C-strings, at all. Also avoid C-strings in general, you can use C++ std::string which are much more secure and fun.
When I run this code on my computer, I have a bunch (exactly seven) of weird chars printed between the ab to the a, which are probably whatever was between strA's and strB's memory spaces.
When I reverse the declarations, I get ab$%^& where $%^& are a bunch of weird chars - the ones between the end of strB's memory to the next random \0.
I followed this tutorial (http://codebase.eu/tutorial/linux-socket-programming-c/) and made a server. The thing is that when the server receives a string from the client, I don't know how to compare it. For example, the following doesn't work:
bytes_received = recv(new_sd, incomming_data_buffer, 1000, 0);
if(bytes_received == 0)
cout << "host shut down." << endl;
if(bytes_received == -1)
cout << "receive error!" << endl;
incomming_data_buffer[bytes_received] = '\0';
cout << "Received data: " << incomming_data_buffer << endl;
//The comparison in the if below doesn't work. The if isn't entered
//if the client sent "Hi", which should work
if(incomming_data_buffer == "Hi\n")
{
cout << "It said Hi!" << endl;
}
You are attempting to compare a character pointer with a string literal (which will resolve to a character pointer), so yeah, the code you have definitely won't work (nor should it). Since your in C++, I would suggest this:
if(std::string(incomming_data_buffer) == "Hi\n")
cout<<"It said Hi!"<<endl;
Now, you need to include string for this work, but I assume you are already doing this, especially if you are comparing strings using this method other places in your code.
Just an explanation of what's going on here, since you appear to be relatively new to C++. In C, string literals are stored as const char*, and mutable strings are simply character arrays. If you've ever programmed C, you might remember that (char* == char*) doesn't actually compare strings, you would need the strcmp() function for that.
C++, however, introduces the std::string type, which can be directly compared using the '==' operator (and concatenated using the '+' operator). But, C code still runs in C++, so char* arrays are not necessarily promoted to std::string unless they are being operated on by a std::string operator (and even then, if I recall, they aren't so much promoted as the operator allows string/char* comparisons), so (std::string == char*) will perform the expected comparison operation. When we do std::string(char*), we call the std::string constructor, which returns a string (in this case, a temporary one) that is compared with your string literal.
Note that I am assuming incomming_data_buffer is of type char*, you are using it like it is, although I can't see the actual declaration.
Why does the C++ standard allow the following?
#include <iostream>
#include <string>
int main()
{
std::string s(10, '\0'); // s.length() now is 10
std::cout << "string is " << s << ", length is " << s.length() << std::endl;
s.append(5, '\0'); // s.length() now is 15
std::cout << "string is " << s << ", length is " << s.length() << std::endl;
// the same with += char and push_back
// but:
s += "hello"; // s.length() returns 20 string is "hello"
std::cout << "string is " << s << ", length is " << s.length() << std::endl;
return 0;
}
Why does it add 0 and count it?
It looks like broken integrity of string, doesn't it? But I checked standard and it is correct behavior.
Why does standard allows following?
Because the people designing C++ strings decided that such things should be allowed. I'm not sure if anyone that was part of the team that designed C++ strings are on SO... But since you yourself say that the standard allows it, that's the way it is, and I doubt it's about to change.
It's sometimes quite practical to have a string that can contain "anything". I can think of a few instances when I've had to work around the fact that C style strings can't contain zero-bytes. Along with the fact that long C style strings take a long time to find the length of, the main benefit of C++ strings is that they are not restricted to "what you can put in them" - that's a good thing in my book.
Not sure what is problem here.
Adding '\0' in the middle of the std::string changes nothing - null character is treated like any other. The only thing that can change is if you use .c_str() with function that accepts null-terminated strings. But then it's not problem of .c_str(), only with the function that treats '\0' specially.
If you want to know how many characters has this string as if treated like null-terminated string, use
size_t len = strlen(s.c_str());
Note that it's O(n) operation, because that's how strlen works.
If you ask why += operator doesn't add the implicit null character of string literal "hello" to the string, I say the reverse (adding it) is unclear and definitely not what you want 99% of the time. On the other hand, if you want to add '\0' to your string, just append it like a buffer:
char buffer[] = "Hello";
s.append(buffer, sizeof(buffer));
or (even better) drop the char arrays and null-terminated strings altogether and use C++-style replacements like std::string as NTS-replacement, std::vector<char> as contiguous buffer, std::vector as dynamic array with pointers replacement, and std::array (C++11) as standard C array replacement.
Also, (as mentioned by #AdamRosenfield in comments), your string after adding "hello" does have in fact 20 characters, it's probably only that your terminal doesn't print nulls.
NUL char '\0' is the ending character for c style string, not std::strings. However, it supports this character to get values from a const char pointer so that it can find the end of a c-style string. Otherwise, it is treated just like other characters
std::string is more of a container for characters than anything else and \0 is a character. As a real world example, take a look at the CreateProcess function in Windows. The lpEnvironment parameter takes a null-terminated block of null-terminated strings (i.e. A=1\0B=2\0C=3\0\0). If you're building a block it's convenient to use an std::string.
According to the text at http://www.cplusplus.com/reference/string/string/, string library in C++ is a class, not just a " mere sequences of characters in a memory array".
I wrote this code to find out more:
string s = "abcd";
cout << &s << endl; // This gives an address
cout << s[0] << endl; // This gives 'a'
cout << &s[0] << endl; // This gives "abcd"
I have some questions:
1. Is string library in C++ still an array of sequence characters?
2. How can I get the address of each character in string? (As in the code, I can retrieve each character, but cannot get its address using & operator)
Much (most) of this really isn't about the string class itself.
std::string does store its contents as a contiguous array of characters.
&s[0] will yield the address of the beginning of that array -- but std::ostream has an overload of operator<< that takes a pointer to char, and prints it as a string.
If you want to see the addresses of the individual characters in a string, you need to take their addresses and then cast each address to pointer to void. std::iostream also has an overload of operator<< that takes a pointer to void, and that overload prints out the address instead of a string that (it assumes) is at that address.
Edit: demo code:
#include <iostream>
#include <string>
int main(){
std::string x("this is a string");
std::cout << &x[0] << "\n";
std::cout << (void *)&x[0] << '\n';
return 0;
}
Result:
this is a string
00481DE0
std::string stores the string as essentially a vector of characters, see basic_string
From Stroutrup's book, chapter 20 on strings, page 579 (2000 edition)
From C, C++ inherited the notion of strings as zero terminated arrays of char..... In C, the name of the array is same as the address of the first character. That's why you get the whole string printed when you pass &s[0] as it same as passing s itself.
This is trivial, probably silly, but I need to understand what state cout is left in after you try to print the contents of a character pointer initialized to '\0' (or 0). Take a look at the following snippet:
const char* str;
str = 0; // or str = '\0';
cout << str << endl;
cout << "Welcome" << endl;
On the code snippet above, line 4 wont print "Welcome" to the console after the attempt to print str on line 3. Is there some behavior I should be aware of? If I substitute line 1-3 with cout << '\0' << endl; the message "Welcome" on the following line will be successfully printed to the console.
NOTE: Line 4 just silently fails to print. No warning or error message or anything (at least not using MinGW(g++) compiler). It spewed an exception when I compiled the same code using MS cl compiler.
EDIT: To dispel the notion that the code fails only when you assign str to '\0', I modified the code to assign to 0 - which was previously commented
If you insert a const char* value to a standard stream (basic_ostream<>), it is required that it not be null. Since str is null you violate this requirement and the behavior is undefined.
The relevant paragraph in the standard is at §27.7.3.6.4/3.
The reason it works with '\0' directly is because '\0' is a char, so no requirements are broken. However, Potatoswatter has convinced me that printing this character out is effectively implementation-defined, so what you see might not quite be what you want (that is, perform your own checks!).
Don't use '\0' when the value in question isn't a "character"
(terminator for a null terminated string or other). That is, I think,
the source of your confusion. Something like:
char const* str = "\0";
std::cout << str << std::endl;
is fine, where str points to a string which contains a '\0' (in this
case, two '\0'). Something like:
char const* str = NULL;
std::cout << str << std::endl;
is undefined behavior; anything can happen.
For historical reasons (dating back to C), '\0' and 0 will convert
implicitly to any pointer type, resulting in a null pointer.
A char* that points to a null character is simply a zero-length string. No harm in printing that.
But a char* whose value is null is a different story. Trying to print that would mean dereferencing a null pointer, which is undefined behavior. A crash is likely.
Assigning '\0' to a pointer isn't really correct, by the way, even if it happens to work: you're assigning a character value to a pointer variable. Use 0 or NULL, or nullptr in C++11, when assigning to a pointer.
Just regarding the cout << '\0' part…
"Terminating the string" of a file or stream in text mode has an undefined effect on its contents. The C++ standard defers to the C standard on matters of text semantics (C++11 27.9.1.1/2), and C is pretty draconian (C99 §7.19.2/2):
Data read in from a text stream will necessarily compare equal to the data that were earlier written out to that stream only if: the data consist only of printing characters and the control characters horizontal tab and new-line; no new-line character is immediately preceded by space characters; and the last character is a new-line character.
Since '\0' is a control character and cout is a text stream, the resulting output may not read as you wrote it.
Take a look at this example:
http://ideone.com/8MHGH
The main problem you have is that str is pointer to a char not a char, so you should assign it to a string: str = "\0";
When you assign it to char, it remains 0 and then the fail bit of cout becomes true and you can no longer print to it. Here is another example where this is fixed:
http://ideone.com/c4LPh