C++ Substitute function - c++

I'm having some problems with the following code:
/* replace c1 with c2 in s, returning s */
char *substitute(char *s, char c1, char c2)
{
char *r = s;
if (s == 0) return 0;
for (; *s; ++s)
if (*s == c1) *s = c2;
return r;
}
void substitute(char c1, char c2);
int main()
{
string s = "apples";
char a;
char b;
cout << "Before swap of Char : " << s << endl;
*substitute(&a, &b);
cout << "After swap of Char : " << s << endl;
system("pause");
}
The code above should replace any occurrences of char1 in the string with char2. I think I have the function down right but calling it is a bit of an issue as the Substitute part in main is showing errors.
My question is how do I continue on from here and call the function in main?
EDIT:
I've read through the answers that have been given but I'm still confused on what to do as I'm a beginner..
EDIT Again:
I've worked it out! :)

If you are in c++(11), you might want to use the standard library and the language facilities:
std::string input = "apples";
const char from='a';
const char to='b';
std::for_each(input.begin(),input.end(),
[&](char& current) {
if(current==from)
current=to;
});
or even more concise
for (char& current : input) {
if(current==from)
current=to;
}

Here are the issues I see with the code:
substitute() should get 3 arguments, char*,char,char, or if you have later a function substitute(char,char). However, you are sending char*,char* to it, so the compiler doesn't know what function to invoke (unless you have another function with this signature which is not showed here). This is the reason for the compile time error
You are trying to modify a string literal, it could create a run time error, if you will fix the compile time error. Note that the string "apples" should not be modified, as it is string literal. You will need to copy it and then change it. The exact behavior of modifying it is undefined, as pointed by #6502 (reference on comments)
Your code is poorly idented (though the edit fixed this issue).
a,b are not initialized and contain 'junk' values.

You're passing two arguments while your function requires 3, plus that the function itself will not work as intended.
Also, on a side note, use cin.get() instead of system("pause");
Just use the method replace of the string class.

As is, you can call the function like this:
char a = 's', b='t';
char s[] = "some string";
s = substitute(s, a, b);
The second and third argument are not pointers, so you can just pass a and b, you don't have to pass &a or &b.
Note that since you're simply modifying the string in the first argument, there's really no reason to assign it to anything. substitute(a, b); would do exactly the same as s = substitute(s, a, b);.
And if you don't have to use your return value, there's really no reason to return it in the first place. You can change your function to this:
/* replace c1 with c2 in s, returning s */
void substitute(char *s, char c1, char c2)
{
if (s == 0) return;
for (; *s; ++s)
if (*s == c1) *s = c2;
}

Initialize a and b then call the substitute method as substitute(s,&a, &b);
Remove the method prototype void substitute(char c1, char c2);as you don't need it.

Related

Concatenation of chars

I need to concatenate to chars and send it as argument to function, but strcat move concatenated chars to first char. I need a method that return concatenated char. Or if I can do it in different way how can I do it?
void abca(char *a)
{
Serial.println(a);
}
void setup()
{
Serial.begin(9600);
char *bb = "1";
char *aa = "2";
abca(strcat(aa, bb));
}
Edit: I'm creating program for Arduino, and I can't use strings. Strings use a lot of memory. Unfortunately Arduino have only 2kB
There are a few problems with your code. First of all, you are using non-const pointers to const arrays:
char *bb = "1"; // "1" is a char constant array
char *aa = "2"; // so it needs a pointer to constant memory
When you fix that your function calls will fail because they need non-const arrays.
One fix is to create a non-const array to receive your concatenated string:
// should be const because it is not modified
void abca(char const* a)
{
Serial.println(a);
}
void setup()
{
Serial.begin(9600);
// char const array decays to pointer to const char
char const* bb = "1";
char const* aa = "2";
// can't concatenate into constant memory
// abca(strcat(aa, bb));
// So make some writable memory and concat to that
char buffer[32]; // long eough for the combined text
strcpy(buffer, bb);
strcat(buffer, aa);
abca(buffer);
}
If you don't know how big the resulting string is you may need to allocate buffer dynamically to make sure it is big enough.
If you are able to change the function to
void abca(const char *a)
Then you could use a std::string at the calling site and the c_str() method:
int main()
{
std::string a = "aa";
std::string b = "bb";
abca((a + b).c_str());
}
Note that the overloaded + operator is used for concatenation. Better still, if you can change the function to
void abca(const std::string& a)
(note that the body of the function is unchanged), you can write
abca(a + b);
at the calling site. All standard C++, and no memory leaks or undefined behaviour either! std::string might get some bad press but it does epitomise the power of C++.

Why casting a quoted string to "string &" causes a crash?

Please note that's just a curious question, I don't need a problem solution!
I have a method that takes in a string reference (string &some_string) and only reads from referenced string. Writing some code I forgot that it needs a reference and passed a quoted string (not a variable, just like "something") and IDE suggested casting it to string reference, as it won't compile. I didn't give it a thought and applied the suggestion (now passing (string &) "something"). And my program crashed as it reached this piece of code. So, why exactly would it cause a crash, compiling without even a warning (g++, c++11)? I don't really understand it since I'm only reading from this string.
Example:
#include <string>
#include <iostream>
using namespace std;
class CharSet
{
private:
const string basis = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const int N = 26;
string array; // string containing all element of the set
int length;
bool add_element(char chr) // Add an element (as char) if not already. Returns true if added, false if not.
{
bool b = false;
if (!in_set(chr) && basis.find(chr) != string::npos) {
array += chr;
length++;
b = true;
}
return b;
}
bool in_set(char chr) const // Checks whether an element (as char) is in set. Returns corresponding bool value.
{
bool b = false;
if (array.find(chr) != string::npos) b = true;
return b;
}
public:
explicit CharSet(string& str) // str - string of possible elements
{
array = "";
length = 0;
int len = (int) str.length();
for (int i = 0; i < len; i++)
add_element(str[i]);
if (str.length() != length)
cout << "\nSome mistakes corrected. Elements read: " << array << endl;
}
};
int main()
{
CharSet A((string &)"AKEPTYUMRX");
getchar();
return 0;
}
A cast like this
(string)"a string literal"
constructs a new std::string by passing "a string literal" as an argument to its constructor. It is equivalent to static_cast<std::string>("a string literal"). It is completely valid, even though C-style casts in C++ are a bad idea in general.
On the other hand, a cast like this
(string&)"a string literal"
constructs a reference to an std::string object that resides at the same location as the string literal. Since there is no such object at that location, using this reference results in undefined behaviour (often expressed as a crash). This cast is equivalent to reinterpret_cast<std::string&>("a string literal"). You might know that reinterpret_cast is dangerous and should be avoided as much as possible. With reinterpret_cast, the compiler trusts the programmer nearly totally, which is not really a wise thing to do, but such is the C++ way.
For your function to be able to accept a string literal, it should have a const std::string& parameter, or perhaps better, if you are using C++17, an std::string_view.

Automatically Concatenate Strings and Int C++

In Lua (apologise, I like working with it the best), the conversion between int and string is done automatically, so
"hi"..2
would result as
"hi2"
In C++ (cause I can't seem to get the default C++11 stoi() and to_string() methods to work) I defined these for myself:
int stoi(string str) {
char* ptr;
strtol(str.c_str(), &ptr, 10);
}
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
which are basically how the default ones are defined anyways.
Then I did this:
string operator+ (string& stuff, int why) {
stuff.append(to_string(why));
}
I tried it on the following code:
void print(string str) {
cout << str << endl;
}
int main() {
cout << stoi("1") + 2 << endl;
print("die" + 1);
return 0;
}
And it outputs
3
ie
Why is this so, and how can I fix it?
EDIT:
Here's what the code looks like now:
using namespace std;
string to_string(int i) {
char* buf;
sprintf(buf, "%d", i);
return buf;
}
string operator+ (string stuff, int why) {
stuff.append(to_string(why));
return stuff;
}
int main() {
cout << string("die") + 2 << endl;
return 0;
}
And it just keeps giving me stackdumps.
Replace print("die" + 1); with cout << std::string("die") + 1;
print() doesn't know what to do with strings. Use std::cout. "die" is a char*, +1 will increment the pointer.
std::string to_string(int i) {
char buf[(sizeof(int)*CHAR_BIT+2)/3+3];
sprintf(buf, "%d", i);
return buf;
}
You need to make an actual buffer to print to. The math is a quick over-estimate of big the largest decimal int is in characters; 3 bits can fit in 1 decimal character, plus null, plus negation, plus rounding, plus 1 for good measure. Hopefully I did not err: do some testing.
Also use snprintf instead of sprintf while you are at it: buffer overflows are not to be toyed with.
The next problem is that "hello" is not a std::string, It is a char const[6] -- an array of 6 char. It can be converted tomstd::string, but +1 will instead convert it to a pointer to the first character, then +1 it to the 2nd character.
Cast it to std::string before.
Finally, it is ambiguous in the standard (really) of pverloading an operator on std::string + int is legal. It is definitely poor practice, as you cannot do it in std legally, and you should overload operators in the type's namespace (so ADL works): these two conflict. On top of that, if std in the future adds such a + your code starts behaving strangely. On top of that, operators are part of a class's interface, and modifying the interface of a class you do not 'own' is rude and a bad habit.
Write your own string class that owns a std::string rather. Or a string view.
Finally, consider telling your compiler to use c++11, you probably just need to pass a flag to it like -std=c++11.
std::string s1("h1");
std::string s2("2");
s1 += s2;
If you are using C++11 compatible compiler you can convert int to string like this:
int i = 2;
std::string s = std::to_string(i);
If you are using Boost library:
#include <boost/lexical_cast.hpp>
int i = 2;
std::string s = boost::lexical_cast<std::string>(i);
Please do not use raw char pointers in C++ for strings.
overloading the operator+ on other than your own types it at best dangerous.
Just use std::to_string in conjunction with operator+ or +=, e.g.
std::string x = "hi";
x += std::to_string(2);
C++14 introduces a user-defined literal that takes a string literal (conversions are applied to make this a pointer) and returns a std::string. In C++11, you can just write your own (this is taken from libstdc++):
inline std::string
operator""_s(const char* str, size_t len)
{
return std::string{str, len};
}
(Note: UDLs without a preceding underscore are reserved names)
And you can use it like this:
// Assumes operator+ is overloaded
print("die"_s + 1);
Demo
"die" is not a std::string. It's a string literal.
Thus when you add 1 to the string literal, it decays to a const char* and the + 1 simply increments that pointer — to next char, 'i'.
Then you call print with the incremented pointer, which causes a std::string to be constructed using that pointer. Since it pointed to the 'i' character, to constructed string is initialized to "ie".
You must first make a std::string out of your string literal to make it call your operator+:
std::cout << std::string("die") + 1;
And then make a few fixes to your operator+:
string operator+ (string stuff, int why) {
return stuff.append(to_string(why));
}
Now it works.

c++ pass by value segmentation fault

I have a function f() which receives a char* p and gives a const char* to it.
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
In the main() below I expect to get q = "def".
int main(){
char *q = "abc";
f(q);
cout << q << endl;
}
By running this I get segmentation fault and as I am new in C++ I don't understand why.
I also get a segmentation fault when I do not initialize q thus:
int main(){
char *q;
f(q);
cout << q << endl;
}
Knowing that the function's parameter and the way it's called must not change. Is there any work around that I can do inside the function? Any suggestions?
Thanks for your help.
You are trying to change a string literal. Any attemp to change a string literal results in undefined behaviour of the program.
Take into account that string literals have types of constant character arrays. So it would be more correct to write
const char *q = "abc";
From the C++ Standard (2.14.5 String literals)
8 Ordinary string literals and UTF-8 string literals are also referred
to as narrow string literals. A narrow string literal has type
“array of n const char”, where n is the size of the string as
defined below, and has static storage duration
You could write your program the following way
//...
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
//..
main(){
char q[] = "abc";
f(q);
cout << q << endl;
}
If you need to use a pointer then you could write
//...
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
//..
main(){
char *q = new char[4] { 'a', 'b', 'c', '\0' };
f(q);
cout << q << endl;
delete []q;
}
This is an issue that, in reality, should fail at compilation time but for really old legacy reasons they allow it.
"abc" is not not a mutable string and therefore it should be illegal to point a mutable pointer to it.
Really any legacy code that does this should be forced to be fixed, or have some pragma around it that lets it compile or some permissive flag set in the build.
But a long time ago in the old days of C there was no such thing as a const modifier, and literals were stored in char * parameters and programmers had to be careful what they did with them.
The latter construct, where q is not initialised at all is an error because now q could be pointing anywhere, and is unlikely to be pointing to a valid memory place to write the string. It is actually undefined behaviour, for obvious reason - who knows where q is pointing?
The normal construct for such a function like f is to request not only a pointer to a writable buffer but also a maximum available size (capacity). Usually this size includes the null-terminator, sometimes it might not, but either way the function f can then write into it without an issue. It will also often return a status, possibly the number of bytes it wanted to write. This is very common for a "C" interface. (And C interfaces are often used even in C++ for better portability / compatibility with other languages).
To make it work in this instance, you need at least 4 bytes in your buffer.
int main()
{
char q[4];
f(q);
std::cout << q << std::endl;
}
would work.
Inside the function f you can use std::string::copy to copy into the buffer. Let's modify f.
(We assume this is a prototype and in reality you have a meaningful name and it returns something more meaningful that you retrieve off somewhere).
size_t f( char * buf, size_t capacity )
{
std::string s = "def";
size_t copied = s.copy( buf, capacity-1 ); // leave a space for the null
buf[copied] = '\0'; // std::string::copy doesn't write this
return s.size() + 1; // the number of bytes you need
}
int main()
{
char q[3];
size_t needed = f( q, 3 );
std::cout << q << " - needed " << needed << " bytes " << std::endl;
}
Output should be:
de needed 4 bytes
In your question you suggested you can change your function but not the way it is called. Well in that case, you actually have only one real solution:
void f( const char * & p )
{
p = "def";
}
Now you can happily do
int main()
{
const char * q;
f( q );
std::cout << q << std::endl;
}
Note that in this solution I am actually moving your pointer to point to something else. This works because it is a static string. You cannot have a local std::string then point it to its c_str(). You can have a std::string whose lifetime remains beyond the scope of your q pointer e.g. stored in a collection somewhere.
Look at the warnings you get while compiling your code (and if you don’t get any, turn up the warning levels or get a better compiler).
You will notice that despite the type declaration, the value of q is not really mutable. The compiler was humoring you because not doing so would break a lot of legacy code.
You can't do that because you assigned a string literal to your char*. And this is memory you can't modify.
With your f, You should do
int main(){
char q[4 /*or more*/];
f(q);
std::cout << q << std::endl;
}
The problem is that you are trying to write on a read-only place in the process address space. As all the string literals are placed in read-only-data. char *q = "abc"; creates a pointer and points towards the read-only section where the string literal is placed. and when you copy using strcpy or memcpy or even try q[1] = 'x' it attempts to write on a space which is write protected.
This was the problem among many other solutions one can be
main(){
char *q = "abc"; \\ the strings are placed at a read-only portion
\\ in the process address space so you can not write that
q = new char[4]; \\ will make q point at space at heap which is writable
f(q);
cout << q << endl;
delete[] q;
}
the initialization of q is unnecessary here. after the second line q gets a space of 4 characters on the heap (3 for chars and one for null char). This would work but there are many other and better solutions to this problem which varies from situation to situation.

C++: set of C-strings

I want to create one so that I could check whether a certain word is in the set using set::find
However, C-strings are pointers, so the set would compare them by the pointer values by default. To function correctly, it would have to dereference them and compare the strings.
I could just pass the constructor a pointer to the strcmp() function as a comparator, but this is not exactly how I want it to work. The word I might want to check could be part of a longer string, and I don't want to create a new string due to performance concerns. If there weren't for the set, I would use strncmp(a1, a2, 3) to check the first 3 letters. In fact, 3 is probably the longest it could go, so I'm fine with having the third argument constant.
Is there a way to construct a set that would compare its elements by calling strncmp()? Code samples would be greatly appreciated.
Here's pseudocode for what I want to do:
bool WordInSet (string, set, length)
{
for (each word in set)
{
if strncmp(string, word, length) == 0
return true;
}
return false;
}
But I'd prefer to implement it using the standard library functions.
You could create a comparator function object.
struct set_object {
bool operator()(const char* first, const char* second) {
return strncmp(first, second, 3);
}
};
std::set<const char*, set_object> c_string_set;
However it would be far easier and more reliable to make a set of std::strings.
Make a wrapper function:
bool myCompare(const char * lhs, const char * rhs)
{
return strncmp(lhs, rhs, 3) < 0;
}
Assuming a constant value as a word length looks like asking for trouble to me. I recommend against this solution.
Look: The strcmp solution doesn't work for you because it treats the const char* arguments as nul-terminated strings. You want a function which does exactly the same, but treats the arguments as words - which translates to "anything-not-a-letter"-terminated string.
One could define strcmp in a generic way as:
template<typename EndPredicate>
int generic_strcmp(const char* s1, const char* s2) {
char c1;
char c2;
do {
c1 = *s1++;
c2 = *s2++;
if (EndPredicate(c1)) {
return c1 - c2;
}
} while (c1 == c2);
return c1 - c2;
}
If EndPredicate is a function which returns true iff its argument is equal to \0, then we obtain a regular strcmp which compares 0-terminated strings.
But in order to have a function which compares words, the only required change is the predicate. It's sufficient to use the inverted isalpha function from <cctype> header file to indicate that the string ends when a non-alphabetic character is encountered.
So in your case, your comparator for the set would look like this:
#include <cctype>
int wordcmp(const char* s1, const char* s2) {
char c1;
char c2;
do {
c1 = *s1++;
c2 = *s2++;
if (!isalpha(c1)) {
return c1 - c2;
}
} while (c1 == c2);
return c1 - c2;
}