I'm trying to create a function that replaces all occurrence of specific const char* in a char* string.
Here's my Code:
#include <iostream>
void replace(char **bufp, const char *searchStr, const char *replaceStr)
{
//what should I do here?
}
int main()
{
char *txt = const_cast<char *>("hello$world$");
replace(&txt, "$", "**");
std::cout << "Result: " << txt << '\n';
}
The result I get:
Result: hello$world$
Program ended with exit code: 0
The result I want:
Result: hello**world**
Program ended with exit code: 0
Your program is already undefined behavior, as you're casting away const, string literals like "hello$world$" are usually placed in read-only memory, and any attempt to modify them will likely result in a segfault, you should use std::string instead.
With std::string your replace function could look like this:
void replace(std::string& str, const std::string& find, const std::string& replace)
{
std::size_t position{};
while((position = str.find(find)) != std::string::npos){
str.erase(position,find.size());
str.insert(position,replace);
}
}
Related
I have a function string_to_char() which attempts to give me a form of a string which I can pass into a library I am using, which wants char * (but I think works with const char *, so I've been trying both).
The code I wrote to test my implementation of string_to_char() goes as such:
#include <iostream>
const std::string endl = "\n";
char * string_to_char(std::string str)
{
return (char*) str.c_str();
}
int main()
{
std::string test1 = "Some test strin";
std::string test2 = "Some test string";
char * result1 = string_to_char(test1);
char * result2 = string_to_char(test2);
std::cout << "part1" << endl;
std::cout << result1 << endl;
std::cout << string_to_char(test1) << endl;
std::cout << "part2" << endl;
std::cout << result2 << endl;
std::cout << string_to_char(test2) << endl;
std::cout << "done" << endl;
return 0;
}
This is the output I get:
part1
Some test strin
Some test strin
part2
Some test string
done
So for some reason, string_to_char() only properly works with strings with 15 characters or shorter, and outputs from the function straight to std::cout, but can't seem to store it to a variable for 16 characters or longer.
I am relatively new to C++ so some of the code below may seem a bit strange to more experienced programmers, but here is the code that I have tried in place of return (char*) str.c_str();
#include <vector>
#include <string.h>
char * string_to_char(std::string str)
{
return (char*) str.c_str();
return const_cast<char*>(str.c_str());
std::vector<char> vec(str.begin(), str.end());
char * chr;
vec.push_back('\0');
chr = (char*) &vec[0];
//chr = & (*vec.begin());
return chr; //all outputs from both are empty with this both versions of chr
return &str[0]; //this makes the output from the 15 character string also be empty when put in a
//variable, but the function going directly to std::cout is fine
return strcpy((char *) malloc(str.length() + 1), str.c_str()); //this one works with everything, but
//it looks like it leaks memory without further changes
std::vector<char> copied(str.c_str(), str.c_str() + str.size() + 1);
return copied.data(); //returns "random" characters/undefined behaviour for both outputs in test1 and is empty for both
//outputs in test2
}
Using const instead, and changing char * result1 = string_to_char(test1); to const char * result1 = string_to_char(test1); (as with result2), to see if that works with these other solutions:
#include <vector>
#include <string.h>
const char * string_to_char(std::string str)
{
return (char*) str.c_str();
return str.c_str();
return (const char*) str.c_str();
return str.data();
return const_cast<char*>(str.c_str());
std::vector<char> vec(str.begin(), str.end());
char * chr;
vec.push_back('\0');
chr = (char*) &vec[0];
//chr = & (*vec.begin());
return chr; //completely breaks both
return &str[0]; //both appear empty when given to a variable, but works fine when taken straight to std::cout
return strcpy((char *) malloc(str.length() + 1), str.c_str()); //memory leak, as when not using const
std::vector<char> copied(str.c_str(), str.c_str() + str.size() + 1);
return copied.data(); //same as when not using const
}
I got a lot of the given methods from:
std::string to char*
string.c_str() is const?
How to convert a std::string to const char* or char*?
Converting from std::string to char * in C++
With a bit of reading around the topic for strings and vectors at https://www.cplusplus.com/reference/ and https://en.cppreference.com/w/
The pointer returned from c_str() is only valid as long as the string is alive. You get expected output when you pass a reference:
auto string_to_char(std::string& str)
{
return str.c_str();
}
Because now the pointer returned is into the buffer of the string of the caller. In your code the caller gets a pointer to the functions local string (because you pass a copy).
Though, instead of calling the function you can directly call c_str(). That also mitigates the problem of holding on to the pointer after the string is gone to some extend.
You've overthought this. There is no need two write this function yourself. std::string::data already exists and returns a pointer to the string's null-terminated internal buffer. Assuming you're using C++17 or later, this pointer will be const char* if the std::string object is const-qualified (i.e. read-only), and otherwise will be a modifiable char*.
std::string test1 = "string";
const std::string test2 = "const string";
char* result1 = test1.data();
const char* result2 = test2.data();
This pointer is valid for as long as the std::string object that it came from is alive and is not modified (except for modifying individual elements).
Also note that casting pointers and casting away const-ness is a very easy way to cause Undefined Behaviour without knowing it. You should avoid C-style casts in general (e.g. (char*)str.c_str()) because they're very unsafe. See this Q/A on the proper use of C++ casts for more information.
Live Demo
Documentation
string_to_char() is taking its str parameter by value, so a copy of the caller's input string is made. When the function exits, that copied std::string will be destroyed. Thus, the returned char* pointer will be left dangling, pointing to freed memory, and any use of that pointer to access the data will be undefined behavior.
Pass in the str parameter by reference instead:
char* string_to_char(std::string &str)
{
return const_cast<char*>(str.c_str());
}
Or, in C++17 and later, you can use this instead:
char* string_to_char(std::string &str)
{
return str.data();
}
Which then begs the question of why you need string_to_char() at all and don't just use data() directly, unless you are not using a modern version of C++.
I am trying to make a function that takes a constant reference of a string as input and returns the string after each character of the string is rotated 1 place to the right. Using references and pointers still confuses me and I am not sure how to obtain the string from the constant reference.
string rotate(const string &str){
string *uno = &str;
string dos = rotate(uno.rbegin(), uno.rbegin() + 1, uno.rend());
return dos;}
This is what I have got so far but it does not compile. Any tips on how to properly get the string from the constant reference will be appreciated.
You can't perform the rotation in-place without violating the const contract on the parameter, so you should copy the input and return a new string:
string rotate(const string &str){
string uno = str;
rotate(uno.rbegin(), uno.rbegin() + 1, uno.rend());
return uno;
}
Another reasonable option would be to use std::rotate_copy
The line
string* uno = string &str;
makes no sense. I think you mean
string* uno = const_cast<string*>(&str);
You might consider this rotate:
// rotate last char to front
std::string rotate(const std::string& str)
{
return(str[str.size()-1] +
str.substr(0,str.size()-1));
}
// 'abcdefghijklmnopqrstuvwxyz'
// 'zabcdefghijklmnopqrstuvwxy'
You could pass in a string to receive the rotated string, thus avoiding return by value copy.
I passed the string in by pointer, as its clearer at the call site that it's intended to be altered, but it could easily be passed by reference if preferred.
#include <string>
#include <iostream>
#include <algorithm>
void rotate(std::string const& str, std::string* out)
{
*out = str;
std::rotate(out->rbegin(), out->rbegin() + 1, out->rend());
}
int main(int, char**)
{
std::string out;
std::string x = "1234567";
std::cout << x << '\n';
::rotate(x, &out);
std::cout << out << '\n';
}
I have written the following function to replace substrings in a char. This way involves converting to a std::string then converting back to a const char. Is this the most efficient way or could I do it without this conversion or even a better way?!
const char* replaceInString(const char* find, const char* str, const char* replace)
{
std::string const text(str);
std::regex const reg(find);
std::string const newStr = std::regex_replace(text, reg, replace);
//Convert back to char
char *newChar = new char[newStr.size() + 1];
std::copy(newStr.begin(), newStr.end(), newChar);
newChar[newStr.size()] = '\0'; // terminating 0
return newChar;
}
const char* find = "hello";
const char* replace = "goodbye";
const char* oldStr = "hello james";
const char* newStr = m->replaceInString(find, oldStr, replace);
Assuming that you want a function to be called from a .c file you could use strdup (see code below).
#include <string>
#include <regex>
#include <cstdio>
#include <cstdlib>
char* replaceInString(char const *find, char const *str, char const *replace)
{
return strdup(std::regex_replace(std::string(str), std::regex(find), replace).c_str());
}
int main()
{
char *newStr = replaceInString("hello", "hello james", "goodbye");
printf("newStr = %s\n", newStr);
free(newStr);
return 0;
}
Note however that you have to free the returned memory after you're done.
Otherwise, as #jerry-coffin suggested go all the way with std::string (see code below):
#include <string>
#include <regex>
#include <iostream>
std::string replaceInString(std::string const &find, std::string const &str, std::string const &replace)
{
return std::regex_replace(std::string(str), std::regex(find), replace);
}
int main()
{
std::string str = replaceInString(std::string("hello"), std::string("hello james"), std::string("goodbye"));
std::cout << str << std::endl;
return 0;
}
So I have a function returning a std::string as follows:
string ReadShaderSource(const char* filename, GLint& shaderSize) // Load the shader source code.
{
ifstream::pos_type size;
string text;
ifstream file(filename, ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
shaderSize = (GLuint)size;
text.resize(size);
file.seekg(0, ios::beg);
file.read(&text[0], text.size());
file.close();
return text;
}
else
{
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error!",
"Could not load the shader source code from the file.", NULL);
Lunar::Exit();
}
return "";
}
But When I call the function like this:
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
The value of testStr is full of this:
0x036fdcd8
"îþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþîþ...
Which makes no sense. The function returns the right value, so when I return text in the function it contains the source code of the shader, but when I do
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
testStr is full of rubbish.
Any ideas?
Thank you!
You need to use
string str = ReadShaderSource("test.glsl", size);
const char* testStr = str.c_str();
instead of
const char* testStr = ReadShaderSource("test.glsl", size).c_str();
When you use the second form, you are storing a pointer in testStr that is not valid any more since the returned value of the function is a temporary string.
As was pointed out by #IInspectable, you could also use a const& to extend the lifetime of the temporary object.
string const& str = ReadShaderSource("test.glsl", size);
const char* testStr = str.c_str();
The following program is well behaved:
#include <iostream>
#include <string>
std::string foo()
{
return "This is a test.";
}
void bar(std::string const& str)
{
std::cout << str.c_str() << std::endl;
}
int main()
{
std::string const& str = foo();
bar(str);
std::cout << str.c_str() << std::endl;
}
Re
“when I do const char* testStr = ReadShaderSource("test.glsl", size).c_str(); testStr is full of rubbish.”
you're initializing the pointer to point to a buffer in a temporary string, that has ceased to exist already when the initialization finishes.
Instead use a string for the result variable.
Note that the conclusion that the function returns garbage is unwarranted, it does not follow from that observation of garbage, but might still be true.
You should test anew, with proper result variable type, to check that.
I am using strstr() function but I am getting the crash.
This part of code is crashing with error "Access violation reading location 0x0000006c."
strstr(p_czCharactersToDelete, (const char*)p_czInputString[index]))
Here is the complete code...
#include "stdafx.h"
#include <iostream>
#include <string>
void delchar(char* p_czInputString, const char* p_czCharactersToDelete)
{
for (size_t index = 0; index < strlen(p_czInputString); ++index)
{
if(NULL != strstr(p_czCharactersToDelete, (const char*)p_czInputString[index]))
{
printf_s("%c",p_czInputString[index]);
}
}
}
int main(int argc, char* argv[])
{
char c[32];
strncpy_s(c, "life of pie", 32);
delchar(c, "def");
// will output 'li o pi'
std::cout << c << std::endl;
}
The prototype of strstr() is as follows,
char * strstr ( char * str1, const char * str2 );
The function is used to locate substring from a main string. It returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
In your case you are passing the wrong parameters to the strstr(). You are calling,
strstr(p_czCharactersToDelete, (const char*)p_czInputString[index]));, which is wrong. Because the pointer p_czCharactersToDelete points to the sub string constant and p_czInputString points to the main string. Call strstr() as strstr(p_czInputString, p_czCharactersToDelete); and make corresponding changes in the function delchar().
you are using the wrong strstr.
probably you need strchr or strpbrk.
#include <cstring>
#include <algorithm>
class Include {
public:
Include(const char *list){ m_list = list; }
bool operator()(char ch) const
{
return ( strchr(m_list, ch) != NULL );
}
private:
const char *m_list;
};
void delchar(char* p_czInputString, const char* p_czCharactersToDelete){
Include inc(p_czCharactersToDelete);
char *last = std::remove_if(p_czInputString, p_czInputString + strlen(p_czInputString), inc);
*last = '\0';
}