This is probably a very basic question for which I have been searching on google for the last 20 mins. I am not sure if i am phrasing it correctly, but I am not getting an explanation that I understand.
Basically, I have a string object and when I add an integer value x, it shortens the string by x characters.
Here is the code:
#include <iostream>
#include <string>
void Print::print(std::string str)
{
std::cout << str << std::endl;
}
print("formatString:" + 5);
The output is: tString:
Now i realise that the above is incorrect and during my search I have found ways correct the behaviour, but I haven’t found what is actually happening internally for me to get the above result.
Thanks
The answer is simple: Pointer arithmetic.
Your string literal (array of const char including implicit 0-terminator), decays to a const char* on use, which you increment and pass to your print()-function, thus invoking the std::string-constructor for string literals.
So, yes, you start with a string object (0-terminated array of const char), but not a std::string object.
Basically, I have a string object
No, you do not have a string object. "formatString:" is not a std::string, but a "string" literal. It is in fact a const char*. A const char* has a operator + defined that takes an integer and advances the value of the pointer with a number of positions. In your case it's 5.
To get a compiler error you'd have to wrap the literal in a std::string.
print(std::string("formatString:") + 5);
"formatString:" is a string literal that has type const char[14] That is it is an array of const char with size equal to 14 (the array includes the terminating zero).
In expressions like this
"formatString:" + 5
the array is implicitly converted to a pointer to its first element. So if for example const char *p denotes this pointer then the expression looks as
p + 5
The result of the expression is a pointer that points to the element of the array with index 5. That is there is used the pointer arithmetic.
P + 5 points to the first symbol of string "tString"
And this expression is used by the constructor of class std::string.
Examine the following,
#include <iostream>
void print(std::string str)
{
std::cout << str << std::endl;
}
int main(int argc, char* argv[])
{
//following two lines created implicitly by the compiler
const char* pstr = "formatString";
std::string tmp(pstr + 5); //string c-tor: string (const char* s);
// now tmp: --> "tString"
print(tmp);
return 0;
}
pstr is a pointer and you are doing pointer arithmetic when you use + operation.
Note:Compiler may create different internal structure, but it is a instructive way to think the above two lines.
Related
Today I was surprised when trying to concatenate an std::string with an int. Consider the following MWE:
#include <iostream>
#include <string>
void print(const std::string& text)
{
std::cout << "The string is: " << text << ".\n";
}
int main()
{
print("iteration_" + 1);
return 0;
}
Instead of printing
The string is: iteration_1.
which I would expect, it prints
The string is: teration_.
What exactly is going on in the background? Does the string for some reason get converted into char[] or something of the sort? The documentation of operator+ does not list any with an std::string and int.
And what is the proper way of concatenating an std::string with a number? Do I really have to throw them both into an std::stringstream or convert the number into std::string explicitely with std::to_string()?
Does the string for some reason get converted into char[]
Actually it is the other way around. "iteration_" is a char[11] which decays to a const char* when you add 1. Incrementing the pointer by one makes it point to the next character in the string. This is then used to construct a temporary std::string that contains all but the first character.
The documentation you link is for operator+ of std::string, but to use that you need a std::string first.
This line is the problem:
print("iteration_" + 1);
The string literal is decaying to a char*. You are adding 1 to this char*, moving it to the next character.
If you wanted to add the string "1" to the end of your literal, a fairly simple way is to pass the string literal to the std::string constructor and convert the 1 to a string manually. For example:
print(std::string("iteration_") + std::to_string(1));
"iteration_" is not std::string, but const char[]. Which decays to const char*, and "iteration_" + 1 just performs pointer arithmetic and move the pointer pointing to the next char (i.e. 't'), then you got the c-style string "teration_".
You can use std::to_string to convert int to std::string, then concatenate them. e.g.
print("iteration_" + std::to_string(1));
For this case std::operator+(std::basic_string) is called and the 1st argument "iteration_" is converted to std::string implicitly and then passed to operator+, then the concatenated std::string is passed to print.
LIVE
If you try to use the following:
std::string str = "iteration" + 1;
compiler will throw the warning:
warning: adding 'int' to a string does not append to the string
[-Wstring-plus-int]
It is because you are incrementing the pointer to "iteration" string by 1 which means that now "teration" string is being assigned to str variable.
The proper way of concatenating would be:
std::string str = "iteration" + std::to_string(1);
The expression "iteration_" + 1 is a const char[11] literal added to the int 1.
In that expression, "iteration_" decays to a const char* pointer to the first element of the array. + 1 then takes place in pointer arithmetic on that pointer. The entire expression evaluates to a const char* type (pointing to the first t) which is a valid NUL-terminated input to a std::string constructor! (The anonymous temporary std::string binds to the const std::string& function parameter.)
This is completely valid C++ and can occasionally be put to good use.
If you want to treat + as a concatenation, then
print("iteration_" + std::to_string(1));
is one way.
Please explain the difference in the output of two programs.
cout << branch[i] in first program gives output as:
Architecture
Electrical
Computer
Civil
cout << *branch[i] in second program gives output as:
A
E
C
C
Why?
What is the logic behind *branch[i] giving only first character of each word as output and branch[i] giving full string as an output?
Program 1
#include <iostream>
using namespace std;
int main()
{
const char *branch[4] = { "Architecture", "Electrical", "Computer", "Civil" };
for (int i=0; i < 4; i++)
cout << branch[i] << endl;
system("pause");
return 0;
}
Program 2
#include <iostream>
using namespace std;
int main()
{
const char *branch[4] = { "Architecture", "Electrical", "Computer", "Civil" };
for (int i=0; i < 4; i++)
cout << *branch[i] << endl;
system("pause");
return 0;
}
When you declare a const char* with assignment operator, for example:
const char* some_string = "some text inside";
What actually happens is the text being stored in the special, read-only memory with added the null terminating char after it ('\0'). It happens the same when declaring an array of const char*s. Every single const char* in your array points to the first character of the text in the memory.
To understand what happens next, you need to understand how does std::cout << work with const char*s. While const char* is a pointer, it can point to only on thing at a time - to the beginning of your text. What std::cout << does with it, is it prints every single character, including the one that is being pointed by mentioned pointer until the null terminating character is encountered. Thus, if you declare:
const char* s = "text";
std::cout << s;
Your computer will allocate read-only memory and assign bytes to hold "text\0" and make your s point to the very first character (being 't').
So far so good, but why does calling std::cout << *s output only a single character? That is because you dereference the pointer, getting what it points to - a single character.
I encourage you to read about pointer semantics and dereferencing a pointer. You'll then understand this very easily.
If, by any chance, you cannot connect what you have just read here to your example:
Declaring const char* branch[4]; you declare an array of const char*s. Calling branch[0] is replaced by *(branch + 0), which is derefecencing your array, which results in receiving a single const char*. Then, if you do *branch[0] it is being understood as *(*(branch + 0)), which is dereferencing a const char* resulting in receiving a single character.
branch[i] contains a char* pointer, which is pointing to the first char of a null-terminated string.
*branch[i] is using operator* to dereference that pointer to access that first char.
operator<< is overloaded to accept both char and char* inputs. In the first overload, it prints a single character. In the second overload, it outputs characters in consecutive memory until it reaches a null character.
This is because of operators precedences.
Subscript operator [] has a higher precedence than an indirection operator *.
So branch[i] returns const char * and *branch[i] returns const char.
*branch[i] prints a single char located at the address pointed to by branch[i].
branch[i] prints the whole char* array starting with the address pointed to by branch[i].
This question already has answers here:
C++ Adding String Literal to Char Literal
(8 answers)
Closed 5 years ago.
In case 1 the output is blank when I initialize a string like this:
#include <iostream>
#include<string>
using namespace std;
//CODE 1
int main()
{
string s="hello" + 'c';
cout<<s<<endl;
return 0;
}
but when I write it this way it works fine:
#include <iostream>
#include<string>
using namespace std;
//CODE 2
int main()
{
string s="hello";
char k='c';
s+=k;
cout<<s<<endl;
return 0;
}
Now I am confused as in another question asked on stack overflow it says that there is no difference between string and std::string when namespace std is used, those answers go by saying that -> There is no functionality difference between string and std::string because they're the same type
std::string vs string in c++
whereas the answers provided for this question are pointing differences:
compiler is g++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-4)
When you have
string s="hello" + 'c';
It's equal to
string s=("hello" + 'c');
With ASCII encoding it's the same as
string s=("hello" + 99);
which is the same as
string s=(&"hello"[99]);
That is, you get a pointer to the 100:th element of the string "hello", which only have six elements (don't forget the terminator).
Going out of bounds leads to undefined behavior.
Because "string" is not a std::string but a const char*, and a pointer plus a number (a character is "just" a number) uses pointer arithmetic, so after your addition, you'll get a const char* which points possibly to garbage memory after your string literal.
The second example works because in this case, s is a std::string which has a operator += for char and does not use pointer arithmetic.
The codes are not the same. In
string s="hello" + 'c';
"hello" is not a std::string. It is a string literal and has the type of const char[N]. When you add a character to it to the array decays to a pointer and you are doing pointer arithmetic. That arithmetic is going past the end of the string literal so it is undefined behavior.
In order to get the first code to act like the second example you need to make "hello" a string. You can use a user defined literal for std::string like
string s = "hello"s + 'c';
or just use a constructor call like
string s = std::string("hello") + 'c';
The expression "hello" + 'c'; is adding a char type to a const char[6] type, with an obscure result. Formally the first argument decays to a const char* pointer, and c is added to that pointer using the normal rules of pointer arithmetic. The behaviour is probably undefined, since the numeric value of c is, in all encodings I've ever come across, a value greater than 6, so you end up attempting to index an element outside the const char array "hello".
In the second version, you are exploiting the overloaded += operator of the std::string class taking a char as an argument, and the character c is concatenated to that string.
"hello" + 'c' gives a pointer past the end of "hello" (e.g. assuming an ASCII character set, 'c' has the numeric value 99, and "hello" + 99 gives a pointer to a memory location that is 99 characters past the 'h' in "hello").
Using such a pointer to initialise an std::string gives undefined behaviour.
The "CODE 2" works std::string has an operator+=() that accepts a char, and appends it to the end of the string.
This question already has answers here:
Why in the code "456"+1, output is "56" [duplicate]
(3 answers)
Closed 6 years ago.
This is my program! I want to know the reason behind such output.
#include <iostream>
using namespace std;
class A{
public:
void fun(int i){
cout<<"Hello World" + i<<endl;
}
};
int main()
{
A obj1;
obj1.fun(2);
return 0;
}
Expected Output :
Hello World2
Actual Output :
llo World
PS:To print "HelloWorld2", I can also code cout<<"Hello World"<< i
"Hello World" is not std::string, it's a string literal so it's type is const char[]. When adding an integer like you're doing with i here you're actually creating a temporary const char* that first points to the first element of the const char[] which is 'H', then you move it 2 spots (because i is 2) so it points to 'l', then you pass that pointer to cout and thus cout starts printing from 'l'. Doing binary operations on such types is called Pointer Arithmetic.
To get a better understanding using an example char array, your code under the hood is similar to:
const char myHello[] = "Hello World";
const char* pointer = myHello; // make pointer point to the start of `myHello`
pointer += i; // move the pointer i spots
cout<< pointer <<endl; // let cout print out the "string" starting at the character pointed to by the new pointer.
Note that if you try to "move" the pointer too much so that it's pointing to something out of the string and then try to access this pointer you get Undefined Behaviour. Same as how accessing an array out of bounds is UB. Just make sure index < size.
"Hello World" + i doesn't do string concatenation. It does pointer arithmetic.
It takes the address of the c-string literal "Hello World", let's call it a.
And then adds to it a + i. Dereferencing the resulting pointer is undefined behavior when i is larger than the length of the c-string literal.
If it's within bounds, however, you'd get an address inside the literal, which will appear as a suffix when printed. However, since a c-string literal is const, attempting to write into that address is UB again.
Long story short, don't do it.
"Hello World" is compiled to an array of characters and is passed to operator<< as a pointer to those characters. Then you add i to the pointer, which moves the pointer on that many characters.
Pointer Arithmetic.
"Hello World" is a string litteral, pointed to implicitly by a const char*.
Adding an integer i to a pointer will move it i positions forward (or backward if i<0).
Hence the result of "Hello World" + 2 is a const pointer (const char*) indicating the address of the third letter in the string.
// example: class constructor
#include <iostream>
#include <string>
class Test{
public:
char* getColor(){
return color;
}
private:
char color[5] = "Blau";
};
int main () {
Test s;
char *myChar = s.getColor();
std::cout << myChar;
return 0;
};
I don't really understand how this actually returns "Blau" instead of just B or something else.
What I'm doing is assigning the starting pointer if a char array to a single char pointer.
I'd really like to understand why this happens like this. Maybe it's because of std::cout getting all values of that type? So instead of "B" it says "Blau"
There is no difference between a pointer to a single object and a pointer to the first element of an array. It's up to the programmer to know how it should be interpreted; or to use friendlier types like std::string.
When you stream a char* with <<, it assumes that it's the pointer to the first element of a zero-terminated C-style string, and prints all the characters it finds, starting from that one, until it finds one with a zero value.
myChar is not a single char but a pointer to such (and you can always do pointer-arithmetic / indexing instead of straight dereferencing).
And operator<< has an overload for ostream&+char*, to output it as a pointer to a 0-terminated string.
So, not really any surprise.
Array in c++ is the const pointer to first element of data block. Therefore your color variable is the pointer.