Replace specific character in a string in C++ - c++

I have a code like following -
Value = "Current &HT"; //this is value
void StringSet(const char * Value)
{
const char *Chk = NULL;
Chk = strpbrk(Value,"&");
if(Chk != NULL)
{
strncpy(const_cast<char *> (Chk),"&amp",4)
}
}
In above code I would like to replace "&" from Value with "&amp.It works fine if I have "&" single character but in current case strpbrk() return "&HT"and in below strncpy whole "&HT"is replaced.
Now I would like to know methods by which I can only replace a single character from a string.

You cannot replace one character in a C style string with several because you cannot know in a C style string how much room you have available to add new characters. You can only do this by allocating a new string and copying the old string to the new. Something like this
char* StringSet(const char* value)
{
// calculate how many bytes we need
size_t bytes = strlen(value) + 1;
for (const char* p = value; *p; ++p)
if (*p == '&')
bytes += 3;
// allocate the new string
char* new_value = new char[bytes];
// copy the old to the new and replace any & with &amp
char* q = new_value;
for (const char* p = value; *p; ++p)
{
*q = *p;
++q;
if (*p == '&')
{
memcpy(q, "amp", 3);
q += 3;
}
}
*q = '\0';
return new_value;
}
But this is terrible code. You really should use std::string.

I think you need some temp array to hold string past & and then replace & in original string and append temp array to original. Here is the above code modified, I believe you can use strstr instead of strchr it accepts char* as second argument.
void StringSet(char * Value)
{
char *Chk = NULL,*ptr = NULL;
Chk = strchr(Value,'&');
if(Chk != NULL)
{
ptr = Chk + 1;
char* p = (char*)malloc(sizeof(char) * strlen(ptr));
strcpy(p,ptr);
Value[Chk-Value] = '\0';
strcat(Value,"&amp");
strcat(Value,p);
free(p);
}
}
Thanks
Niraj Rathi

You should not modify a constant string, and certainly can't modify a string literal. Although it is much much better to use a std::string instead of dealing with resource management yourself, one way is to allocate a new c-style string and return a pointer to it:
char *StringSet(const char *Value) {
char buffer[256];
for (char *p = (char*)Value, *t = buffer; p[0] != 0; p++, t++) {
t[0] = p[0];
if (p[0] == '&') {
t[1] = 'a'; t[2] = 'm'; t[3] = 'p';
t += 3;
}
t[1] = 0;
}
char *t = new char[strlen(buffer)+1];
strcpy(t, buffer);
return t;
}

string str="Current &HT";
str.replace(str.find('&'),1,"&amp");

Related

Swap 2 char of a C++ array

I have a problem with memory access. When i = 0, Visual Studio throws an exception with reference to a line as labelled in the following code.
Can't access at 0x00AD8B3B and 0x00AD8B3B equals scr+np-i
How can I fix the for-loop body so as to fix this issue?
int o_strrev(char* scr)
{
int np = strlen(scr) - 1;
char tmp;
if (!scr) return -1;
if (!*scr) return -1;
for (int i = 0; i < np / 2; i++)
{
tmp = scr[np-i];
scr[np-i] = scr[i]; # this line
scr[i] = tmp;
}
return 0;
}
As pointed out by #Revolver_Ocelot, you are probably passing a const char* from a string literal. Since these are, by definition, constant, you can't modify them in the way you're trying to. You need some way to convert const char* into a non constant char*. Something along these lines will work for you:
string str = "string";
char* cstr = new char[str.length() + 1];
strcpy(cstr, str.c_str());
I've compiled your code in g++ using non constant char* and it works fine. Just remember to deallocate your char* when you're done with it. We don't want memory leaks ;)
I see you are trying to reverse a string.
Might I suggest a simpler way
void reverse(char *string_var)
{
int length, c;
char *begin, *end, temp;
length = strlen(string_var);
begin = string_var;
end = string_var;
for (c = 0; c < length - 1; c++)
end++;
for (c = 0; c < length/2; c++)
{
temp = *end;
*end = *begin;
*begin = temp;
begin++;
end--;
}
}
Make sure you pass character array of the form
char word[64]
Or maybe by recursion
void reverse(char *x, int begin, int end)
{
char c;
if (begin >= end)
return;
c = *(x+begin);
*(x+begin) = *(x+end);
*(x+end) = c;
reverse(x, ++begin, --end);
}
You're most likely calling o_strrev with a string literal, some thing like:
o_strrev("This ain't gonna work!");
This will compile with most compilers and at most generate a warning. Try cranking up your warning level.
Instead, you want to make a dynamic copy of your string on the heap and work with a char* pointer to that, something like:
string str = "This is gonna work!!"
size_t len = str.size();
char* my_string = new char[len + 1];
strncpy(my_string, str.data(), len)
my_string[len] = '\0';
o_strrev(my_string);
// ...
delete[] my_string;

Am I releasing the memory in the heap correctly?

I'm studying C/C++ and the exercise I'm doing is to create a program which evaluates an arithmetic expression.
To complete the exercise, I need a general purpose function which is able to tokenize a string.
As the size of the string to parse is not known at compile time, I have to allocate dynamically some data in the heap.
After the work is done, the memory in the heap can be released.
My question is simple: I'm releasing the memory correctly? See the questions in the comments.
Tokenize function
char** Tokenize(const char delimiter, const char* string)
{
const char* pString = string;
char** tokens = new char*[strlen(string)];
char* buffer = new char[strlen(string)];
char* pointer = buffer;
int c = 0;
for (int k = 0; k < strlen(string); k++)
{
if (string[k] == delimiter)
{
buffer[k] = '\0';
tokens[c] = pointer;
pointer = buffer + k + 1;
c++;
continue;
}
buffer[k] = string[k];
}
tokens[c] = nullptr;
return tokens;
}
The main function which tests Tokenize function and relases the heap.
int main()
{
char** tokens = Tokenize('.', "192.168.1.1");
char** startTokensPointer = tokens;
char* startBufferPointer = *tokens;
while (*tokens != nullptr)
{
cout << *tokens << endl;
tokens++;
}
delete[] startTokensPointer; //Releases tokens??
delete[] startBufferPointer; //Releases buffer??
system("PAUSE");
}
You are not deallocating buffer correctly. If none of the chars in string is equal to delimiter the code in this if statement :
if (string[k] == delimiter)
will never be executed and c will remain 0. Then this line :
tokens[c] = nullptr;
will set the first element of tokens that is stored in startBufferPointer to nullptr. In that case you are leaking buffer as the pointer to buffer is "forgotten" in main.
tokens is deallocated correctly in all cases.
Yes, there is no memory leak, but why not use a type that makes it guaranteed?
struct Tokens
{
explicit Tokens(size_t len) : tokens(new char*[len]), buffer(new char[len])
{ }
std::unique_ptr<char*[]> tokens;
std::unique_ptr<char[]> buffer;
};
Tokens Tokenize(const char delimiter, const char* string)
{
auto len = strlen(string);
Tokens result(len);
char* pointer = result.buffer.get();
int c = 0;
for (size_t k = 0; k < len; k++)
{
if (string[k] == delimiter)
{
result.buffer[k] = '\0';
result.tokens[c] = pointer;
pointer = result.buffer.get() + k + 1;
c++;
continue;
}
result.buffer[k] = string[k];
}
result.tokens[c] = nullptr;
return result;
}
int main()
{
auto tok = Tokenize('.', "192.168.1.1");
char** tokens = tok.tokens.get();
while (*tokens != nullptr)
{
cout << *tokens << endl;
tokens++;
}
}
Now all the memory is managed automatically and it's almost impossible to leak.

why my simple reverse char* does not working?

i wrote this code in two ways
trying to run in visual studio 2012 - i open the project as simple console application and i get access valuation exception.
code 1
void revReq(char* str)
{
if(*(str+1) != '\0')
revReq(str+1);
putchar(*str);
}
Code 2
void rev(char* str)
{
char* retVal = new char[strlen(str)]+1;
char* ptr = str + strlen(str)-1;
int i = 0;
while(ptr != str)
{
retVal[i++]=*ptr;
*ptr = '\0';
ptr--;
}
}
the inpus is
char* n = "abcdef";
revReq(n);
the exception
Unhandled exception at 0x00B11E7C in Ex003.exe: 0xC0000005: Access violation reading location 0xFFFFFFFF.
In the first function you compare a character in pointer str plus 1 with '\0' The condition can be equal to true only if char is equivalent to signed char and the internal code of *str is equal to 255 (-1).
void revReq(char* str)
{
if((*str+1) != '\0')
revReq(str+1);
putchar(*str);
}
The valid code will look
void revReq( const char *s)
{
if( *str )
{
revReq( str + 1 );
putchar( *str );
}
}
The second function is also wrong. At least you have to write
char* retVal = new char[strlen(str) + 1];
instead of
char* retVal = new char[strlen(str)]+1;
Also there is a memory leak. The function has to return the reversed string.
The valid code will look as
char * rev( const char *s )
{
size_t n = strlen( s );
char *p = new char[ n + 1];
const char *s1 = s + n;
char *q = p;
while ( s1 != s ) *q++ = *--s1;
*q = '\0';
return p;
}
Use strlen(str) + 1
The strlen function returns the size of the string not including the null character '\0'

Add characters to a character array c++

Can someone tell me what's wrong with the following?
I'm trying to add characters to a character array. name is a pointer to a character array in the MyString class.
void MyString::add_chars(char* c)
{
if(l < strlen(c)+strlen(name))
name = resize(name, l, sizeof(c));
int i,j;
for(i=0; i<strlen(c); i++) {
name[i+l-1] = c[i];
l++;
}
}
char* MyString::resize(char* vptr, int currentsize, int extra) {
char* temp = new char[currentsize + extra];
int i;
for (i = 0; i < currentsize; i++) {
temp[i] = vptr[i];
}
vptr = temp;
return vptr;
}
And in main:
MyString g ("and");
g.add_chars("baasdf");
cout << g.get_name() << "\n";
But get_name returns "andb". How can I fix my code?
Edit:
Updated code, still same result..
void StringList::add_chars(char* c)
{
char* my_new_string = resize(name, l, sizeof(char));
if( my_new_string != NULL )
{
delete [] name;
name = my_new_string;
}
int i,j;
for(i=0; i<strlen(c); i++) {
name[i+l-1] = c[i];
l++;
}
name[l-1] = '\0';
}
char* StringList::resize(char* vptr, int currentsize, int extra) {
char* temp = new char[currentsize + extra + 1];
int i;
for (i = 0; i < currentsize; i++) {
temp[i] = vptr[i];
}
vptr = temp;
return vptr;
}
This line is wrong:
name = resize(name, l, sizeof(c));
You should not take the sizeof(char*), which your c variable is, but you should do sizeof(char) or just 1.
Also, make sure that you do +1 on the size to take care of the zero termination char at the end of your string.
How can I fix my code?
Don't fix it. Throw it away and use vector<char> or just string.
But I insist, how can I fix my code!?
OK, OK, here is how...
Get a nice debugger, for example this one.
Step carefully through the code, constantly inspecting the variables and comparing them with what you expect them to be.
When you reach the call to resize, take note of sizeof(c) (assigned to extra parameter of resize). When you realize it is not what you expected, ask yourself: what is the purpose of sizeof, and you'll understand why.
BTW, you also have a memory leak and a very poor performance due all these strlens.
Firstly, am I right in assuming that this is a learning exercise for you in learning "how to create your own string class"? C++ has already got a built-in string type which you should always prefer for the most part.
the sizeof operator yields the size (in bytes) of its operand, which in this case is c whose type is char* - it looks like what you're actually after is the length of a null-terminated character array (a "C" string") - you're already using strlen, so I'd suggest you simply want to use that again. (taking a null-terminator into account too)
name = resize(name, l, strlen(c) + 1);
Note, that your code looks as if it suffers from memory leaks. You're assigning a new value to your name variable without clearing up whatever existed there first.
if(l < strlen(c)+strlen(name))
{
char* my_new_string = resize(name, l, strlen(c));
if( my_new_string != NULL )
{
delete [] name;
name = my_new_string;
}
}
EDIT: As other replies have pointed out, there's still plenty wrong with the code which could be resolved using C++'s string and vector.
Here's one possible way you could implement add_chars
void MyString::add_chars(char* c)
{
if( c != NULL && name != NULL )
{
size_t newlength = strlen(c) + strlen(name) + 1;
char* newstring = new char[newlength];
if( newstring != NULL )
{
size_t namelength = strlen(name);
size_t remaining = newlength - namelength;
strncpy( newstring, name, newlength );
strncpy( &newstring[namelength] , c, remaining );
delete [] name;
name = newstring;
}
}
}

An Extra Character At the End of Char Array (char *Result = new char) 8OI

I have a C++ function that splits LPSTR type variable an attact it into an char array (char*)
Example:
this->XMeshTexturePath = FindTexturePath(XMeshTexturePath,d3dxMaterials[i].pTextureFilename);
//the value of XMeshTexturePath is: Models\\Textures\\
//the value of d3dxMaterials[i].pTextureFilename is: BlaBlaBla\\BlaBla\\Cyrex.x
//The Result(XMeshTexturePath) should be like this:"Models\\Textures\\Cyrex.x"
This is the funcion I'm trying to write:
int FindTextLength(char* Text){
int length
h=0;
for(int i=0;i
char* FindTexturePath( char* TexturePath ,LPSTR FileNameToCombine){
int FileLength=0;
int PathAndFileLength=0;
char *FileName = new char;
char *TexPathAndName = new char;
strcpy(TexPathAndName, FileNameToCombine);
PathAndFileLength = FindTextLength(TexPathAndName);
for(int i=0; i<PathAndFileLength; i++){
if( TexPathAndName[i] != NULL){
if(TexPathAndName[i] != '\\'){
FileName[FileLength] = TexPathAndName[i];
FileLength++;
}
else
FileLength = 0 ;
}else break;
}
int PathLength = FindTextLength(TexturePath);
char *Result = new char;
//==============>> // I also tryed this:char *Result = new char[PathLength+FileLength];
//==============>> // char *Result = new char();
for(int i=0; i<PathLength; i++){
if( TexturePath[0] != NULL){
Result[i] = TexturePath[i];
}
else break;
}
for(int i=0; i<FileLength; i++){
if( FileName[0] != NULL){
Result[PathLength + i] = FileName[i];
}
else break;
}
return **Result**; // The Problem is here It should be like this:
// "Models\\Textures\\Cyrex.x"
// But I'm taking one of these as result:
// "Models\\Textures\\Cyrex.x{"
// "Models\\Textures\\Cyrex.xu"
// "Models\\Textures\\Cyrex.xY"
// The last character is random... 8O(
}
Actualy it's not wokring so bad. The problem is when I declare an char array(char *Result = new char;) it does'not metter how much is length I'm takin an extra character at the end of final result(Result)
I'm realy stucked in here if you have any idea or suggestion plase let me know.
Thanks for any advice and respons.
The Solusion is adding this at the end
of function:
Result[i] = TexturePath[i];
}
else break;
}
for(int i=0; i<FileLength; i++){
if( FileName[0] != NULL){
Result[PathLength + i] = FileName[i];
}
else break;
}
Result[PathLength+FileLength] = '\0' ; // This part is resloving the problem.
// **Thanks for helps**.
return Result;
}
char *Result = new char[PathLength+FileLength];
Result pointed data should end with the termination character \0. Or you will run into problems when returned such a string pointed by Result. So,
Result[PathLength+FileLength-1] = '\0' ;
Make sure you never overrun the buffer or even a better option is to use std::string.
new char allocates space for a single character. You probably mean to allocate space for an array of characters, which you can do with new char[N] where N is the size of the array (e.g. new char[40])
char *FileName = new char;
char *TexPathAndName = new char;
That should crash. You're allocating 1-character buffers, then trying to strcpy into them, which is clearly going to overflow those buffers pretty quickly. Also, remember that after the characters in the string you need 1 extra space for the null terminator.
Best approach is to use std::string.
If you don't, for string length there are functions like strlen/wcslen. Windows shell has also some very handy functions for path manipulation http://msdn.microsoft.com/en-us/library/bb773559%28v=vs.85%29.aspx
Most of them can come handy, and usually you manipulate static length char path[MAX_PATH]={} buffers.
Remember that max path is 256 or so, for deeper nested folders there are some problems.