why string prints junk value,if we give it size? - c++

#include <iostream>
using namespace std;
int main()
{
string a("Hello World",20);
cout<<a<<endl;
return 0;
}
I get output as "Hello WorldP". Why?
Usually we initialise string only with a data.But here i gave size.But it takes junkees.
So do i prefer not giving size?

Generally this is called garbage in, garbage out.
From cppreference:
Constructs the string with the first count characters of character string pointed to by s. s can contain null characters. The length of the string is count. The behavior is undefined if [s, s + count) is not a valid range.
The behavior of your program is undefined because "Hello World" is a const char[12] and trying to access characters up to index 20 via the const char* (resulting from the array decaying to pointer to its first element) is out of bounds.
The actual use case for that constructor is to create a std::string from a substring of some C-string, for example:
std::string s("Hello World",5); // s == "Hello"
Or to create a std::string from a C-string that contains \0 in the middle, for example:
std::string s("\0 Hello",5); // s.size() == 5 (not 0)

Related

I am facing an issue with string and null characters in C++.Null character is behaving differently

I am facing an issue with string and null characters in C++.
When I am writing '\0' in between the string and printing the string then I am getting only part before '\0' but on the other hand when I am taking string as input then changing any index as '\0' then it is printing differently. Why is it so and why the sizeof(string) is 32 in both the cases
Code is below for reference. Please help.
First code:
#include<iostream>
using namespace std;
int main(){
string s = "he\0llo";
cout<<s.length()<<"\n";
cout<<s<<endl;
cout<<sizeof(s)<<"\n";
}
output of First code:
2\n
he\n
32\n
Second code
#include<iostream>
using namespace std;
int main(){
string s;
cin>>s;
s[1] = '\0';
cout<<s<<"\n";
cout<<s.length()<<"\n";
cout<<sizeof(s)<<"\n";
return 0;
}
output of second code:
hllo\n
5\n
32\n
Below is the image for your reference.
std::string's implicit const CharT* constructors and assignment operator don't know the exact length of the string argument. Instead, it only knows that this is a const char* and is forced to assume that the string will be null-terminated, and thus computes the length using std::char_traits::length(...) (effectively std::strlen).
As a result, constructing a std::string object with an expression like:
std::string s = "he\0llo";
will compute 2 as the length of the string, since it assumes the first \0 character is the null terminator for the string, whereas your second example of:
s[1] = '\0';
is simply adding a null character into an already constructed string -- which does not change the size of the string.
If you want to construct a string with a null character in the middle, you can't let it compute the length of the string for you. Instead, you will have to construct the std::string and give it the length in some other way. This could either by done with the string(const char*, size_t) constructor, or with an iterator pair if this is an array:
// Specify the length manually
std::string s{"he\0llo",6};
Live Example
// Using iterators to a different container (such as an array)
const char c_str[] = "he\0llo";
std::string s{std::begin(c_str), std::end(c_str)};
Live Example
Note: sizeof(s) is telling you the size of std::string class itself in bytes for your implementation of the standard library. This does not tell you the length of the contained string -- which can be determined from either s.length() or s.size().
As of c++14, there is an option to specify quoted strings as a std::string by using std::literals. This prevents conversion of an array of chars to string which automatically stops at the first nul character.
#include<iostream>
#include <string>
using namespace std;
using namespace std::literals;
int main() {
string s = "he\0llo"s; // This initializes s to the full 6 char sequence.
cout << s.length() << "\n";
cout << s << endl;
cout << sizeof(s) << "\n"; // prints size of the s object, not the size of its contents
}
Results:
6
hello
28

Why runtime error occur when we try to get the length of the NULL string?

Why the following code gives an error?
// This a CPP Program
#include <bits/stdc++.h>
using namespace std;
// Driver code
main()
{
string s=NULL;
s.length();
}
I know that a runtime error will occur because I am trying to get the length of the null string but I want to know why it is happening?
You invoke the following overload of the std::string constructor (overload 5):
basic_string( const CharT* s, const Allocator& alloc = Allocator());
And this is the explanation belonging to the constructor (emphasis mine):
Constructs the string with the contents initialized with a copy of the null-terminated character string pointed to by s. The length of the string is determined by the first null character. The behavior is undefined if [s, s + Traits::length(s)) is not a valid range (for example, if s is a null pointer).
Thus, you have undefined behavior at work. Referring back to your question, that outrules any further thoughts on "why it is happening", because UB can result in anything. You could wonder why it's specified as UB in the first place - this is because std::string shall by design work with C-style, zero-terminated strings (char*). However, NULL is not one. The empty, zero-terminated C-style string is e.g. "".
Why the following code gives an error?
main must be declared to return int.
Also, to declare an empty string, make it string s; or string s="";
This would compile:
#include <iostream>
#include <string>
int main()
{
std::string s;
std::cout << s.length() << '\n'; // prints 0
}
On a sidenote: Please read Why should I not #include <bits/stdc++.h>?
There is no such thing as the null string unless by "null" you mean empty, which you don't.

std::string stops at \0

I am having problems with std::string..
Problem is that '\0' is being recognized as end of the string as in C-like strings.
For example following code:
#include <iostream>
#include <string>
int main ()
{
std::string s ("String!\0 This is a string too!");
std::cout << s.length(); // same result as with s.size()
std::cout << std::endl << s;
return 0;
}
outputs this:
7
String!
What is the problem here? Shouldn't std::string treat '\0' just as any other character?
Think about it: if you are given const char*, how will you detemine, where is a true terminating 0, and where is embedded one?
You need to either explicitely pass a size of string, or construct string from two iterators (pointers?)
#include <string>
#include <iostream>
int main()
{
auto& str = "String!\0 This is a string too!";
std::string s(std::begin(str), std::end(str));
std::cout << s.size() << '\n' << s << '\n';
}
Example: http://coliru.stacked-crooked.com/a/d42211b7199d458d
Edit: #Rakete1111 reminded me about string literals:
using namespace std::literals::string_literals;
auto str = "String!\0 This is a string too!"s;
Your std::string really has only 7 characters and a terminating '\0', because that's how you construct it. Look at the list of std::basic_string constructors: There is no array version which would be able to remember the size of the string literal. The one at work here is this one:
basic_string( const CharT* s,
const Allocator& alloc = Allocator() );
The "String!\0 This is a string too!" char const[] array is converted to a pointer to the first char element. That pointer is passed to the constructor and is all information it has. In order to determine the size of the string, the constructor has to increment the pointer until it finds the first '\0'. And that happens to be one inside of the array.
If you happen to work with a lot zero bytes in your strings, then chances are that std::vector<char> or even std::vector<unsigned char> would be a more natural solution to your problem.
You are constructing your std::string from a string literal. String literals are automatically terminated with a '\0'. A string literal "f\0o" is thus encoded as the following array of characters:
{'f', '\0', 'o', '\0'}
The string constructor taking a char const* will be called, and will be implemented something like this:
string(char const* s) {
auto e = s;
while (*e != '\0') ++e;
m_length = e - s;
m_data = new char[m_length + 1];
memcpy(m_data, s, m_length + 1);
}
Obviously this isn't a technically correct implementation, but you get the idea. The '\0' you manually inserted will be interpreted as the end of the string literal.
If you want to ignore the extra '\0', you can use a std::string literal:
#include <iostream>
#include <string>
int main ()
{
using namespace std::string_literals;
std::string s("String!\0 This is a string too!"s);
std::cout << s.length(); // same result as with s.size()
std::cout << std::endl << s;
return 0;
}
Output:
30
String! This is a string too!
\0 is known as a terminating character so you'll need to skip it somehow.
Take that as an example.
So whenever you want to skip special characters you would like to use two backslashes "\\0"
And '\\0' is a two-character literal
std::string test = "Test\\0 Test"
Results :
Test\0 Test
Most beginners also make mistake when loading eg. files :
std::ifstream some_file("\new_dir\test.txt"); //Wrong
//You should be using it like this :
std::ifstream some_file("\\new_dir\\test.txt"); //Correct
In very few words, you're constructing your C++ string from a standard C string.
And standard C strings are zero-terminated. So, your C string parameter will be terminated in the first \0 character it can find. And that character is the one you explicitly provided in your string "String!\0 This is a string too!"
And not in the 2nd one that is implictly and automatically provided by the compiler in the end of your C standard string.
Escape your \0
std::string s ("String!\\0 This is a string too!");
and you will get what you need:
31
String!\0 This is a string too!
That's not a problem, that's the intended behavior.
Maybe you could elaborate why you have a \0 in your string.
Using a std::vector would allow you to use \0 in your string.

When passing char arrays as arguments, why isn't the null terminator included in the index?

When you pass char arrays as arguments and try to find the length of the array, it returns the length without the null operator?
For example, if I passed charArray[4] = "aaa" and found the length of this using strlen, the returned value would be 3. Why is this so?
More detailed example below:
#include <iostream>
using namespace std;
int main() {
void function(char[]);
char charArray[4] = "aaa";
function(charArray);
cin.get();
return 0;
}
void function (char *array)
{
size_t index = 0;
index = strlen(array);
std::cout << index; // prints value: 3
}
You are confusing char arrays with the behavior of string literals, c-style strings respectively.
strlen() operates on NUL terminated character arrays and doesn't count the terminating \0 character by definition:
Returns the length of the given null-terminated byte string, that is, the number of characters in a character array whose first element is pointed to by str up to and not including the first null character.
The behavior is undefined if str is not a pointer to a null-terminated byte string.
To get the size of an array use sizeof() like so:
char arr[4] = "abc";
cout << sizeof(arr) << endl;
You should note that the above sample will not give you correct results, as soon the array is decayed to a pointer that is passed to a function:
char arr[4] = "abc";
void func(char* arr)
{
cout << sizeof(arr) << endl; // Prints the size of the pointer variable itself
}
Such functions need to get the array size from an extra parameter:
void func(char* arr, size_t arrsize)
{
// ...
}
If you think of the null as more of an implementation detail, that might help.
If you know std::string at all, you want length() to return the actual length. Every other major language has a string of some sort, and they all have a function to get the length.
Also, you really want strlen(a+b) == strlen(a) + strlen(b), otherwise a lot of operations get a bit more complicated. You only want to count a null once. When you strcat.
strlen does not return the length with the null character because the null character determines where the C string ends in memory.
(ie it is not part of the string, it tells the runtime where the string ends).
See:
https://en.wikipedia.org/wiki/String_%28computer_science%29#Null-terminated
https://en.wikipedia.org/wiki/Null-terminated_string

String made from the first char of another string - why is it also printing the full original string?

Learning C++. I just want to grab the first character in a string, then make a new string based on such character, and then print it out:
#include <iostream>
using namespace std;
int main(int argc, const char * argv[]) {
string name = "Jerry";
char firstCharacter = name.at(0);
string stringOfFirstCharacter = string(&firstCharacter);
cout << stringOfFirstCharacter;
return 0;
}
The output is:
J
Jerry
I don't really know why is it also printing Jerry. Why is that?
Your code has undefined behavior. The signature of the constructor that takes a pointer to char requires that it is a pointer to a null terminated string, which it is not in your case since it is a single character.
My guess is that the implementation you have uses the small object optimization, and that "Jerry" is small enough that it is stored inside the std::string object rather than dynamically allocated. The layout of the two objects in the stack happens to be first firstCharacter, then name. When you call std::string(&firstCharacter) it reads until it hits the first null character (inside the std::string buffer) and stops there.
You are constructing an std::string object from a char* (because you are taking the address of firstCharacter). A pointer to a character is not interpreted as a character itself by the constructor of std::string, but rather as a null-terminated string.
In this case, your program has Undefined Behavior, because the address of firstCharacter is not the address of the first character of a null-terminated string.
What you should be doing is:
string stringOfFirstCharacter(1, firstCharacter);
cout << stringOfFirstCharacter;
If you really want to create a one-character string. However, notice that in order to print the character to the standard output, you could have simply written:
cout << firstCharacter;
Or even:
cout << name.at(0);
With string(&firstCharacter), you are using the std::string constructor of the form
std::string( const char* s, const Allocator& alloc = Allocator() );
That form expects a pointer to a null-terminated array of characters. It is incorrect to pass a pointer to character(s) that are not null-terminated.
With your intention of initializing the string with 1 char, you should use the form:
string( 1, firstCharacter )
The string constructor you're using (the one that takes a char * argument), is intended to convert a C-style string into a C++ string object - not a single character. By passing it a single character you cause undefined behaviour.
In your specific case, there appears to not be a zero byte in memory after firstCharacter, so the constructor runs through and includes all of name along with it!