Difference between passing string S and string S[ ] in C++ - c++

void str(string S[])
{
S=S+"jg";
cout<<S;
}
In the above code, it throws me an error. I understand because I am passing the pointer S. But, when I remove the square brackets off, it doesn't throw me an error. What is the reason?

If string is really std::string then it have an overloaded operator for + that appends a std::string to another std::string.
And character literals can decay to a const char * which is implicitly convertible to std::string.
So without the square brackets you append two strings, and
S = S + "jg";
is really equivalent to
S = operator+(S, std::string("jg")); // Add S and "jg", assign result back to S
Which is equivalent to
S += "jg";
As for the reason it doesn't work with the square brackets, it's because then S is indeed a pointer, it's a pointer to string (i.e. string*).
Character literals are really arrays of constant characters, and as any array they decay to pointers to their first element.
That means the expression S + "jg" is trying to add values of the types string* and char const*, which is not possible and you get an error because of that.

if I understand you correctly
/*
accepts array of strings, but you must specify the size also
other wise function won't know the size of array;
example:
std::string[] arrOfStrings = {"venkat", "chary", "padala"};
str( arrOfStrings );
with size parameter;
str( arrOfStrings, 3 );
*/
void str( std::string s[] )
{
}
/*
accepts std::string
example: str( "abcdefg" );
*/
void str( std::string s )
{
}

Related

how do functions read pointers?

im new to c++. I made this simple program using classes which does simple stuff like change instances of objects and copying objects.
But I'm confused how functions like std::strlen() read pointers.As far as i know pointer is just an address to another variable.If i pass in derefrenced pointer in std::strlen(*c) i get some error saying compiler cannot convert pointer to char, but if i pass in raw pointer like std::strlen(c)
the code compiles fine and gives the desired output.Why is that?std::strlen() should know the exact string to calculate length right?how does passing pointer help?
Same goes with strcpy_s() if i pass in derefrenced pointers like this strcpy_s(*str,strlen(str)+1,*c) it wont work but if i pass in pointers like strcpy_s(str,strlen(str) + 1, c), it works perfectly.
Please help me out as I'm really confused.Thanks
here is the code-
#include <iostream>
#include <cstring>
#include <vector>
class mystring
{
char* str;
public:
//constructors
mystring();
mystring(const char* c);
mystring(const mystring& original);
~mystring();
//methods
void display() const;
void length() const;
void display_vector(const std::vector <mystring>& thing) const;
//operator overloading
mystring& operator= (const mystring& source);
};
mystring::mystring() //default constructor
:str(nullptr)
{
str = new char[1];
*str = '\0';
}
mystring::mystring(const char* c) //overloded constructor (char *c)
{
str = new char[std::strlen(c) + 1];
strcpy_s(str, std::strlen(c) + 1, c);
}
mystring::mystring(const mystring& original) // copy constructor
{
str = new char[strlen(original.str) + 1];
strcpy_s(str, strlen(original.str) + 1, original.str);
}
mystring::~mystring() //destructor
{
delete[] str;
}
void mystring::display() const // display method for mystring
{
std::cout << str << std::endl;
}
void mystring::length() const // length fuc
{
std::cout << strlen(str) << std::endl;
}
mystring& mystring::operator= (const mystring& source) //= operator overload
{
delete[] this->str;
this->str = new char[std::strlen(source.str) + 1];
strcpy_s(this->str, std::strlen(source.str) + 1, source.str);
return *this;
}
int main()
{
mystring v{ "v_and_jackie" };
v.display();
mystring jackie;
jackie = v;
jackie.display();
std::vector <mystring> thing;
thing.push_back("wake up");
thing.push_back("samurai");
for (const auto i : thing)
i.display();
}
Thanks again.
std::strlen receives as an argument a pointer to the beginning of the string:
std::size_t strlen( const char* str );
Returns the length of the given 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 there is no null character in the character array pointed to by str.
https://en.cppreference.com/w/cpp/string/byte/strlen
As far as i know pointer is just an address to another variable
Correct.
If i pass in derefrenced pointer in std::strlen(*c) i get some error saying compiler cannot convert pointer to char
Read the message again. It should say that it cannot convert a char to a pointer-to-char.
but if i pass in raw pointer like std::strlen(c) the code compiles fine and gives the desired output.Why is that?
This is because of type safety that C++ language has. std::strlen accepts an argument that is a pointer to char. If you pass the function something that isn't a pointer to char nor convertible to such pointer, like a char object for example, then the program is ill-formed, and you'll get an informative message pointing out your mistake.
When you indirect through a pointer, what you get back is not a pointer of same type. Instead, the value that you get back is the pointed object, which always has a different type. In case of pointer to char, the pointed object is a char.
how does passing pointer help?
Passing an argument of correct type into a function call helps.
I'm gonna try and explain the reasoning behind why you have to pass a char:
Back in the days memory was very valuable. And instead of using memory for an Integer to keep track of the string length a convention was used: End the string with a null-byte (zero).
Every character is saved in the ASCII format (lookup ASCII table).
Because every string is null-terminated "Hello" would look like {72, 101, 108, 108, 111, 0} in memory.
So to get the length of the string you need a pointer to the first character, then advance forwards until you get to the null-byte. By counting how many bytes you advanced in memory you know the amount of characters contained in the string.
This is exactly what strlen does.
By dereferencing the pointer to the first character you get the first character.
This way strlen would not know where the first character came from in memory and cannot read the next character.
So you can think of dereferencing the pointer to a string (the first char) as loosing all information about that string except what the first character is.
Hopefully this was understandable.

Concatenation of std::string and int leads to a shift. Why?

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.

c++: How to pass a raw string to a function like evaluate( "2+2\0+2" )?

EDIT:: std::string infix="2+2\0+2"; how to pass it to the function evaluate(std::string s){cout << s}? => 2+2+2 ?
EDIT2:: \0 is a NULL character; my function to check grammar reads every character from string and if it is different than numeric or operator it throws an exception. I would like to read null character and throws an exception, but evaluate("2+2\0+2") returns 4.
I am writing a simple calculator in c++11 with tests, supporting an infix notation.
And I have a function int evaluate( const std::string & infix ) which calculates the result from my string (i.e. evaluate( "((-3+--4*-(-19+5)))" ) returns 53). And everything works just fine until...
When I create some tests I can write ASSERT_EQ(6, evaluate("2+2+2")). But when I write ASSERT_EQ(6, evaluate("2+2\0+2") everything goes wrong (this should throw an exception but it returns 4).
So how to pass an array of characters into a function, not knowing it size and having null characters inside of it? When const char cstr[] = "2+\0+2"; evaluate(cstr); does not send a full array :(
The problem is not on the function's side, but on the caller's. To construct a std::string from a string literal containing null bytes, you need to use one of the overloads that takes in information about the size of the string.
One such overload (number 4 here) takes in the char pointer, and the size. Since string literals are char arrays, you can retrieve their size with a function template :
template <std::size_t N>
std::string make_string(char const (&lit)[N]) {
return {lit, N};
}
... and use it thusly :
ASSERT_EQ(6, evaluate(make_string("2+2\0+2")));
You can also use the same principle to handle string literals directly by overloading your function :
template <std::size_t N>
auto evaluate(char const (&lit)[N]) {
return evaluate({lit, N});
}
My guess is that you are not trying to test "2 plus 2 null_byte plus 2", but rather you are trying to test "2 plus 2 divided by zero plus 2".
If so, remember that in C++ string literals you need to type in a double backslash (because backslash is used as an escape character for many untypable characters).
Try
ASSERT_EQ(6, evaluate("2+2\\0+2"))
or, because you are using C++11
ASSERT_EQ(6, evaluate(R"2+2\0+2"))
to use "raw" string literals
When const char cstr[] = "2+/0+2"; evaluate(cstr); does not send a full array :(
You can use use constructor of std::string which accepts iterator range, example:
// Using macro
#define ARR_TO_STR(a) std::string(std::cbegin(a), std::cend(a))
// And template function
template <typename T, size_t N>
std::string ArrToStr( T (&t)[N] ) {
return std::string(std::cbegin(t), std::cend(t));
}
int main()
{
ASSERT_EQ(6, evaluate(ArrToStr("2+\0+2")))
}

How can I convert const char* to string and then back to char*?

I'm just starting c++ and am having difficulty understanding const char*. I'm trying to convert the input in the method to string, and then change the strings to add hyphens where I want and ultimately take that string and convert it back to char* to return. So far when I try this it gives me a bus error 10.
char* getHyphen(const char* input){
string vowels [12] = {"A","E","I","O","U","Y","a","e","i","o","u","y"};
//convert char* to string
string a;
int i = 0;
while(input != '\0'){
a += input[i];
input++;
i++;
}
//convert a string to char*
return NULL;
}
A: The std::string class has a constructor that takes a char const*, so you simply create an instance to do your conversion.
B: Instances of std::string have a c_str() member function that returns a char const* that you can use to convert back to char const*.
auto my_cstr = "Hello"; // A
std::string s(my_cstr); // A
// ... modify 's' ...
auto back_to_cstr = s.c_str(); // B
First of all, you don't need all of that code to construct a std::string from the input. You can just use:
string a(input);
As far as returning a new char*, you can use:
return strdup(a.c_str()); // strdup is a non-standard function but it
// can be easily implemented if necessary.
Make sure to deallocate the returned value.
It will be better to just return a std::string so the users of your function don't have to worry about memory allocation/deallocation.
std::string getHyphen(const char* input){
Don't use char*. Use std::string, like all other here are telling you. This will eliminate all such problems.
However, for the sake of completeness and because you want to understand the background, let's analyse what is going on.
while(input != '\0'){
You probably mean:
while(*input != '\0') {
Your code compares the input pointer itself to \0, i.e. it checks for a null-pointer, which is due to the unfortunate automatic conversion from a \0 char. If you tried to compare with, say, 'x' or 'a', then you would get a compilation error instead of runtime crashes.
You want to dereference the pointer via *input to get to the char pointed to.
a += input[i];
input++;
i++;
This will also not work. You increment the input pointer, yet with [i] you advance even further. For example, if input has been incremented three times, then input[3] will be the 7th character of the original array passed into the function, not the 4th one. This eventually results in undefined behaviour when you leave the bounds of the array. Undefined behaviour can also be the "bus error 10" you mention.
Replace with:
a += *input;
input++;
i++;
(Actually, now that i is not used any longer, you can remove it altogether.)
And let me repeat it once again: Do not use char*. Use std::string.
Change your function declaration from
char* getHyphen(const char* input)
to
auto hyphenated( string const& input )
-> string
and avoid all the problems of conversion to char const* and back.
That said, you can construct a std::string from a char_const* as follows:
string( "Blah" )
and you get back a temporary char const* by using the c_str method.
Do note that the result of c_str is only valid as long as the original string instance exists and is not modified. For example, applying c_str to a local string and returning that result, yields Undefined Behavior and is not a good idea. If you absolutely must return a char* or char const*, allocate an array with new and copy the string data over with strcpy, like this: return strcpy( new char[s.length()+1], s.c_str() ), where the +1 is to accomodate a terminating zero-byte.

Trying to add a string object to an integer

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.