I am trying to reverse a char* by using a stack.
stack<char> scrabble;
char* str = "apple";
while(*str)
{
scrabble.push(*str);
str++;
count++;
}
while(!scrabble.empty())
{
// *str = scrabble.top();
// str++;
scrabble.pop();
}
In the second While-loop, I'm not sure how to assign each char from the stack's top to the char* str.
When you have a string defined using
char* str = "apple";
you are not supposed to change the value of the string. Changing such a string causes undefined behavior. Instead, use:
char str[] = "apple";
In the while loops, use an index to access the array instead of incrementing str.
int i = 0;
while(str[i])
{
scrabble.push(str[i]);
i++;
count++;
}
i = 0;
while(!scrabble.empty())
{
str[i] = scrabble.top();
i++;
scrabble.pop();
}
You can also iterate a pointer to the char[] if you'd like
char str[] = "apple";
char* str_p = str;
int count = 0;
while(*str_p)
{
scrabble.push(*str_p);
str_p++;
count++;
}
// Set str_p back to the beginning of the allocated char[]
str_p = str;
while(!scrabble.empty())
{
*str_p = scrabble.top();
str_p++;
scrabble.pop();
}
Related
I'm dealing with dynamic arrays in C++. Help with the following code.
I'm trying to read the characters one by one and make the C-string. If the array size is not enough, I increase it. But the function increaseArray works with an error and returns a string with other characters. What I am wrong?
void increaseArray(char* str, int &size){
char* newStr = new char[size * 2];
for (int i = 0; i < size; i++){
newStr[i] = str[i];
}
size *= 2;
delete[] str;
str = newStr;
}
char* getline()
{
int size = 8;
char* str = new char[size];
char c;
int index = 0;
while (c = getchar()) {
if (index == size) increaseArray(str, size);
if (c == '\n') {
str[index] = '\0';
break;
};
str[index] = c;
index++;
}
return str;
}
In function increaseArray you are assigning newStr to str however str is local copy of pointer in increaseArray function thus change is not visible outside it.
Simplest fix is to change increaseArray signature to:
void increaseArray(char*& str, int &size)
So reference to pointer will be passed, thus changes to str inside increaseArray will be visible outside it.
You could do that.
Its simple..
#include <string.h>
#include <stdlib.h>
using namespace std;
void increaseArray(char* &str, int size){
str = (char *)realloc(str,size*2);
}
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.
How do I return a pointer to something in the middle of a char array?
// Returns a pointer to the first occurrence of the given character in the
// given string.
const char* strchr(const char* string, char charToFind) {
for (int i = 0; i < strlen(string); i++) {
if (string[i] == charToFind) {
return string[i]; // <== THIS IS WRONG, How do I fix this?
}
}
return '\0';
}
You can do it like this
return &string[i];
or like this:
return string+i;
It's the same thing.
Returning '\0', a char constant equal to zero, is logically incorrect: you should return 0 for a NULL pointer, or if you wish to return an empty C string, you could return a pointer to local static empty string, like this:
const char* strchr(const char* string, char charToFind) {
for (int i = 0; i < strlen(string); i++) {
...
}
// Not found - return an empty string:
static const char *empty = "";
return empty;
}
If you have a pointer to a string, adding N to it will return the pointer to the part of the same string, starting from the Nth character (for zero-based count).
Also, it's better to have a constant for the pointer to empty string.
static const char* EMPTY_STRING = '\0';
const char* strchr(const char* string, char charToFind) {
for (int i = 0; i < strlen(string); i++) {
if (string[i] == charToFind) {
return string+i;
}
}
return EMPTY_STRING;
}
As #dasblinkenlight mentioned, &string[i] or string + i both work for returning pointers to the middle of the string. And as #Oliver Matthews stated, you should be returning NULL if the character is not found. Perhaps beyond the scope of your original query, but for performance reasons, you may want to avoid calling strlen(), and just check for the end of string as you scan, like so:
const char* strchr(const char* string, char charToFind) {
for (int i = 0; string[i]; i++) { // Or you could say string[i] != '\0'
if (string[i] == charToFind) {
return string + i;
}
}
return NULL;
}
I am trying to remove characters from a char pointer and would like to store them back in a new char pointer variable let's say "temp". So I would have something like this:
char *test = "1#2#3$4%5^6&7*8!9#1#0";
char *temp = "";
then remove the "#,#,$,%,^,*,!,#,#," and place the new values of "12345678910" into *temp. This would make temp be equal to "12345678910".
Is this possible?
I have been doing this with string but I really need to do this with the char pointers. Here is how I have done this with string:
std::string str("1#2#3$4%5^6&7*8!9#1#0");
std::string temp("");
char chars[] = "##$%^&*!";
for (unsigned int i = 0; i < strlen(chars); ++i)
{
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
}
temp = str;
So you see here I am doing this all will strings but I just cannot seem to get away with asigning a char * variable like test to a string because its an illegal conversion. However why am I able to set my char * variables equal to string like so?
char *test = "123456789";
However this is illegal?
std::string str("1#2#3$4%5^6&7*8!9#1#0");
char chars[] = "#";
for (unsigned int i = 0; i < strlen(chars); ++i)
{
str.erase (std::remove(str.begin(), str.end(), chars[i]), str.end());
}
char *test = str; //Illegal point
Thank you for your time.
change
char *test = str;
into:
char *test = str.c_str();
c_str is a method that creates c style char array from original string for you.
EDIT: this is a more safe way, a copy of the c string will be obtained:
#include <cstring>
#include <cstdlib>
...
char *test = strdup(str.c_str());
... // process the string
free(test);
Here you have a reference to std string class.
Manpage for strdup.
Anything you can do with iterators you can also do with pointers to an array. Say, an array of chars:
char str[] = "1#2#3$4%5^6&7*8!9#1#0";
char chars[] = "#";
for (unsigned int i = 0; i < strlen(chars); ++i)
{
*std::remove(str, str+strlen(str), chars[i])=0;
}
Notice that I used the fact that std::remove returns an iterator (in this case char*) to the "one after last" element and set that char to 0 - making sure it stays a zero-delimited string
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),"&",4)
}
}
In above code I would like to replace "&" from Value with "&.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 &
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,"&");
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,"&");