problems about map STL - c++

void huffmanDecode(string str){
string temp;
map<string, char>::iterator it;
//for(auto iter=myMap.begin();iter!=myMap.end();++iter)
//cout<<iter->first<<" "<<iter->second<<" "<<endl;
for (unsigned int i = 0; i < str.size(); i++)
{
temp += str[i];
it = myMap.find(temp);
if (it == myMap.end())
continue;
else
{
cout<<it->first<<" ";//crashed here, "Thread 1:EXC_BAD_ACCESS(code=1,address=0x0)
//cout << it->second << " ";
temp = nullptr;
}
}
}
I am trying solving the huffmandecode problem by map ,but it crashed ~~~

std::string::operator= has an overload that takes a const char*. This is the overload that is used when you say
temp = nullptr;
Now, a requirement is that the const char* point to a null-terminated string. Thus it cannot be the null pointer. You are not allowed to pass a null pointer, and an implementation is allowed to raise an exception in this case. In any case, attempting to use such a string would result in undefined behaviour. There is an analogous situation with the std::string constructor.
If your intention was to re-set temp to be an empty string, you have a few options:
temp = "";
temp.clear();
temp = std::string();

You have defined temp as a std::string, not as a pointer.
So setting it to nullptr is wrong!
If you want to clear its contents, which I assume you actually want to, try this:
temp.clear();

Related

C++ Junior interview question: function to compress a character sequence with only char pointers

I was at a job interview the other day and I had the following function to implement:
char* Compress (char * text);
Rules were also that you are not allowed to use standard libary functions like strlen, strcpy, string etc... So the function has to compress a given character sequence.
For example if the input text is"11112222333344411" after passing it to the Compress function the returned value is: "12341", or if the text input is:"aaAbbBBcCCa" ---> return: aAbBcCa
I am not sure I did everything properly (with memory handling) here so any suggestions would be great. Am I doing it right that I delete the value of temp every time? Also if there is a simpler way to implement this function (without using the standard library functions of course) I would be really pleased to see it.
#include <iostream>
char* Compress(char* text) {
char* temp;
char* _compText;
int size = 1;
_compText = nullptr;
for (size_t i = 0; text[i] != '\0'; ++i)
{
if (text[i] != text[i + 1]) {
++size;
temp = _compText;
_compText = new char[size];
for (size_t j = 0; j < size-2; ++j)
{
_compText[j] = temp[j];
}
_compText[size-2] = text[i];
_compText[size-1] = '\0';
delete[] temp;
}
}
return _compText;
}
int main()
{
char t[] = "111122222233333444444555555111";
char* compedT;
std::cout << "Before:\n";
std::cout << t;
compedT = Compress(t);
std::cout << "\nAfter: \n";
std::cout << compedT;
delete[] compedT;
return 0;
}
The function initially is implemented incorrectly.
The type of the function is
char* Compress (char * text);
^^^^^^^
that is its parameter is not const char *, This means that the function should update the source string in place and return pointer to its first character. There is no need to allocate dynamically memory to perform the task.
The function can be defined as it is shown in the demonstrative program.
#include <iostream>
char * Compress( char *s )
{
for ( char *p = s, *q = s; *q; )
{
if ( *++q != *p ) *++p = *q;
}
return s;
}
int main()
{
char s[] = "11112222333344411";
std::cout << Compress( s ) << '\n';
}
Its output is
12341
Or the function can look also the following way
char * Compress( char *s )
{
for ( char *p = s, *q = s; *q; )
{
if ( ( *++q != *p ) and ( ++p != q ) ) *p = *q;
}
return s;
}
As for your function implementation then you should read warnings as for example
warning: comparison of integer expressions of different signedness: 'size_t' {aka 'long unsigned int'} and 'int' [-Wsign-compare]
34 | for (size_t j = 0; j < size-2; ++j)
| ~~^~~~~~~~
And your function returns nullptr for an empty string. This looks logically inconsistent. And the function is very inefficient.:)
And do not use names that start with underscore.
Does my code have memory leak?
As far as I can see, no; there is no memory leak.
That said, the use of bare owning pointers makes it difficult to spot memory leaks. They are a bad design choice, especially when transferring ownership to outside of the function. At the very least, there should be a comment near the function declaration that should document how the caller must clean up the allocation. If you need a dynamic array, a better solution is to use a container.
Am I doing it right that I delete the value of temp everytime?
As far memory leaks are concerned yes, you do need to delete every allocation. But reallocating memory on every iteration is unnecessary, and quite slow. In fact, there doesn't appear to be need for any dynamic allocation (See Vlad's answer).

Member function of return type char* returns address that contains different string after while loop

My code reads input from a text file word by word and instantiates an object for each token. In the while loop, when I call get_value() on the VAR object and dereference it I get the string "foo" which is what I want, but outside of the loop I get the string belonging to the STRING object "HELLO". I'm pretty sure calling the constructor for STRING is what's causing the issue but I can't pin point the problem.
STRING and VAR have their own get_value()member function and they do not inherent from each other.
I even dynamically allocated memory in VAR's set_value() function so I'm pretty sure STRING() is not mutating anything. Excuse me if I posted too much.
Output
$ ./venom
0x7ffeeb3a02d8
foo
0x7ffeeb3a02f8
0x7ffeeb3a02d8
Hello
Hello
main.cpp
ifstream in("new.vnm");
string s;
STRING *ptr1;
VAR *ptr2;
while(in >> s){
if(s[0] == '"') {
//Address to (H)ello
STRING str(&s[1]);
ptr1 = &str;
//0x7ffeeb3a02f8 -- That's OK
cout << ptr1 << endl;
}
else if((s[0] > 'a' && s[0] < 'z') || (s[0] >'A' && s[0] < 'Z')) {
//Address to (f)oo
VAR var(&s[0]);
ptr2 = &var;
// 0x7ffeeb3a02d8 -- This is OK.
cout << ptr2 << endl;
// Value stored at ptr2 -- Prints foo -- That's OK.
for(int i = 0; ptr2->get_value()[i]; i ++)
cout << ptr2->get_value()[i];
cout << endl;
}
};
// 0x7ffeeb3a02d8 -- That's OK
cout << ptr2 << endl;
// Printing Value stored at ptr2 -- Hello -- This is NOT OK!
for(int i = 0; ptr2->get_value()[i]; i ++)
cout << ptr2->get_value()[i];
cout << endl;
// Printing Value stored at ptr1 -- That's OK.
for(int i = 0; ptr1->get_value()[i]; i ++)
cout << ptr1->get_value()[i];
cout << endl;
VAR.cpp
void VAR::set_name(char *name) {
this->name = new char[this->len+1];
for(int i = 0; i < len; i ++)
this->name[i] = name[i];
this->name[this->len+1] = '\0';
};
char *VAR::get_value() const {
return this->name;
};
STRING.cpp
char *STRING::get_value() const {
return this->value;
};
void STRING::set_value(char *str) {
this->value = new char[this->len + 1];
for(int i = 0; i < this->len; i ++)
this->value[i] = str[i];
this->value[this->len + 1] = '\0';
};
new.vnm (text file)
foo = "Hello";
ptr2->get_value() should point to foo not Hello.
Outside of the loop both ptr2 and ptr1 point to objects which no longer exist - they were already destroyed, because their scope was smaller. This is undefined behaviour and a serious error. In this case anything can happen and it's a lot of luck your program only prints not what you expect instead of just crashing.
You're taking a pointer to a locally scoped object, and then dereferencing that pointer after the object has gone out of scope. That's undefined behaviour.
Essentially your code is this
VAR *ptr2;
{
VAR var;
ptr2 = &var;
}
ptr2->get_value() // this is invalid because 'var' no longer exists.

How do I free the memory while trimming a character array?

I am coding this in C++. My current issue at hand is that I have to trim the whitespace from the beginning of the character array. I am not allowed to use any string functions. My idea is to count the number of whitespaces at the beginning, allocate memory based on how much less memory I would need in a character array if I didn't have those whitespaces, do so, and then copy over the new string and deallocate the original string.
My issue is that I can't seem to deallocate that string without Visual Studio hitting a break point for me. I can get it working with the code I have below, (not deallocating the roginal strig at all) d=but wouldn't that cause a memory leak?
Thanks for your help in advance.
#include <iostream>
using namespace std;
class SmartString{
private:
char* str;
public:
SmartString ( )
{
str = NULL;
}
SmartString (char *str){
int length = 0;
int copy_index = 0;
while(str[length] != '\0')
{
length++;
}
length++;
char * copy;
copy = (char*)malloc(sizeof(char) * length);
copy = new char[length];
while(copy_index < length)
{
copy[copy_index] = str[copy_index];
cout << str[copy_index];
copy_index++;
}
this -> str = copy;
}
~ SmartString()
{
if(str != NULL)
{
delete str;
free(str);
}
}
void ShowString()
{
cout << "[" << str << "]";
}
int Size()
{
if(str == NULL)
return 0;
else
{
int i = 0;
while(str[i] != '\0')
{
i++;
}
i++;
return i;
}
}
**void Trim()
{
int counter = 0;
while (str[counter] == ' ' && counter < Size())
{
counter++;
}
int new_length = Size() - (counter + 1);
char * temp;
temp = (char*) malloc(sizeof(char) * new_length);
temp = new char[new_length];
int counter_2 = 0;
while(counter_2 < Size())
{
temp[counter_2] = str[counter_2 + counter];
counter_2++;
}
str = temp;
}**
};
int main()
{
char *str;
str = " Hello";
SmartString * s = new SmartString(str);
str = "Change";
(*s).Trim();
(*s).ShowString();
system("Pause");
}
You have not used 'delete' in your main function to deallocate your 's' pointer variable, So that the destructor method of your 'SmartString' class never called. In your second constrcutor method, you I've allocated the 'copy' variable twice where it's not need And also you have some mistake in your 'Trim' method.
In your destructor method, You should remove the free(str); statement cause the delete str; statement will deallocate the 'str'. So there is no need to deallocate twice.
malloc - Allocates the requested memory and returns a pointer to it.
new X; - Do the same thing but also calls constructor method if X is a class or struct after allocating.
new X[] - Allocates dynamic array with the requested memory and returns a pointer to it.
free - Deallocates the memory previously allocated.
delete - Do the same thing but also calls destructor method if X is a class or struct after deallocating.
delete[] - Deallocates the memory previously allocated dynamic array.
new and delete is the standard memory allocation and deallocation implement of C++ language where malloc and free is the standard memory allocation and deallocation function of C language.
Here I've rewritten your 'Trim' method:
void Trim()
{
int counter = 0;
while (str[counter] == ' ' && counter < Size())
{
counter++;
}
int new_length = Size() - (counter + 1);
char * temp;
// There is no need to allocate twice
//temp = (char*) malloc(sizeof(char) * new_length);
temp = new char[new_length+1];
int counter_2 = 0;
while(counter_2 < //Size() ( Here is your big mistake. You should not use 'Size()' here )
new_length
)
{
temp[counter_2] = str[counter_2 + counter];
counter_2++;
}
temp[counter_2] = 0;
str = temp;
}
And for deallocating, you have to use the 'delete' like this:
int main()
{
char *str;
str = " Hello";
SmartString * s = new SmartString(str);
str = "Change";
(*s).Trim();
(*s).ShowString();
// use delete to deallocate a pointer
delete s;
system("pause");
}
I see three reasonable approaches to this.
One would be to modify the existing string in-place. Find the position of the first non-space character, then copy from there to the end of the string to positions starting from the first element of the string. This can't be applied to a string literal (or you'll get undefined behavior).
The second would be to allocate a new buffer and copy the data you want to keep into that buffer. In this case, you probably do not want to try to modify the original (and, especially, you don't want to try to free its data).
The third would be to (basically) re-implement a class about like std::string, that always allocates a buffer in a specific way, so it "knows" how to manipulate that buffer safely. In this case, you could/would have a constructor to create an object from a string literal, so by the time your function was invoked, it would only (even attempt to) manipulate such objects and could never accidentally try to manipulate/modify something like a string literal.

Segmentation fault error

`I am trying to write a program that reverses two strings, I though I had it done pretty well but when I run it, the program runs till line 26, then I get a segmentation fault error. The program compiles fine. I am wondering if there is a simple or obvious problem in my functions that I am not seeing, Any help would be appreciated!!
Thanks in advance
#include <iostream>
#include <string>
using namespace std;
// Reversing the characters in strings.
void reverse(string str);
void swap(char * first, char *last);
int main() {
// declarations and initialization
string str1;
string str2;
cout << "Please enter the first string of characters:\n";
cin >> str1;
cout << "Please enter the second string of characters:\n";
cin >> str2;
cout << "The strings before reversing are:" << endl;
cout << str1 << " " << str2 << endl;
// reverse str1
reverse(str1);
// reverse str2
reverse(str2);
// output
cout << "The strings after reversing: " << endl;
cout << str1 << " " << str2 << endl;
return 0;
}
void reverse(string str) {
int length = str.size();
char *first = NULL;
char *last = NULL;
first = &str[0];
last = &str[length - 1];
for (int i = 0; first < last; i++) {
swap(first, last);
first++;
last--;
}
}
void swap(char *first, char *last) {
char * temp;
*temp = *first;
*first = *last;
*last = *temp;
}
I don't know where line 26 is, but
char * temp;
*temp = ...
is not valid. temp should be pointed at a char, or (better yet) rewrite the function to where temp is a char.
Seth Carnegie observes that you'll have to pass the strings by reference if you want to modify the originals.
void reverse(string& str) { //pass by reference, so origional is modified
In your swap function, you are assigning a value to *temp when temp is not pointing to anything (it's uninitialized). Thus, your segmentation fault.
You want this:
void swap(char* first, char* last)
{
char temp = *first;
*first = *last;
*last = temp;
}
The other answers are valid in regards to the segfault cause.
I just think you may be interested in knowing that you can reverse a string easily using std::string's reverse_iterator:
std::string reverse(std::string str) {
std::string out;
for (std::string::reverse_iterator it = str.rbegin(); it != str.rend(); it++) {
out += *it;
}
return out;
}
So, calling:
reverse("foo");
...will return oof.
You're passing the strings by value, which means only a local copy of the string will be reversed in the reverse function. You should pass them by reference.
Also, don't alter the string's memory directly. Use operator[] like this:
for (size_t beg = 0, size_t end = str.size() - 1; beg < end; ++beg, --end)
str[beg] = str[end];
So all together:
void reverse(string& str); // prototype
....
void reverse(string& str) { // note the & which is pass by reference
int length = str.size();
for (size_t beg = 0, size_t end = str.size() - 1; beg < end; ++beg, --end)
str[beg] = str[end];
}
And as stated by Mooing Duck, the place you're probably crashing from is dereferencing a pointer which has a garbage value here:
char * temp;
*temp = ...
You're trying to assign some random memory a value, which is probably segfaulting you.
Again, others have pointed out the what the problem is and would like to show you this:
void reverse(std::string & str) {
for (int i = 0, last = str.size() - 1, lim = str.size() / 2 ; i < lim;) {
std::swap(str[i++], str[last--]);
}
}
I have not tested it thoroughly though.

c++ read content of a pointer

i'm new in c++ world, i just use it for litle app that help me in my work, now, i need to read the content of a folder, list the folder content, i've made a function that return a pointer with the name of every obj in the folder, but now, i don't know how to read the content of the pointer to just print it in a console, my function look like this
string* listdir (const char *path)
{
string* result = new string[50]; // limit to 50 obj
DIR *pdir = NULL;
pdir = opendir (path);
struct dirent *pent = NULL;
if (pdir == NULL)
{
printf ("\nERROR! pdir could not be initialised correctly");
return NULL;
}
int i = 0;
while (pent = readdir (pdir))
{
if (pent == NULL)
{
printf ("\nERROR! pent could not be initialised correctly");
return NULL;
}
//printf ("%s\n", pent->d_name);
result[i++]= pent->d_name;
}
closedir (pdir);
return result;
}
i've been trying to print the result of teh function
int main()
{
string *dirs;
dirs = listdir("c:\\");
int i = 0;
//while(dirs[i])
//{
//cout<<dirs[i]<<'\n';
//++i;
//}
}
but i really don't know what i'm doing, lol, some help would be perfect
thanks
Examine your while loop condition : dirs[i] is a std::string. You are using a string object in a boolean context : would you expect std::string to convert to bool ?
My recommendation : ditch the fixed sized array and go for std::vector.
void listdir(const char *path, std::vector<std::string> &dirs)
{
/* ... */
while (pent = readdir (pdir))
{
/* ... */
dirs.push_back(pent->d-name);
}
closedir(pdir);
}
int main()
{
std::vector<std::string> dirs;
listdir("c:\\", dirs);
for (std::vector<std::string>::const_iterator it = dirs.begin(), end = dirs.end(); it != end; ++it)
std::cout << *it << std::endl;
}
int main()
{
string *dirs;
dirs = listdir("c:\\");
for (int i = 0; i < 50 && dirs[i].size() > 0; ++i)
{
cout << dirs[i] << '\n';
}
}
dirs is a pointer to an array, so you can index it like an array. You created an array of 50, so you need to limit yourself to 50 here too. Since you might not have populated the whole array, the .size() check allows the printing loop to stop early.
There is some major confusion in your code, especially between arrays of characters, strings and arrays of strings. Also, there is a memory leak.
Here are my questions / concerns:
Issues / Concerns
The opendir function may be called
with a null parameter. You should
check for a null path before calling
opendir.
Returns NULL after declaring some
variables. IMHO, one should check
parameters before declaring
variables.
How does one know how many valid
entries are in the returned array?
If the size of the array (known only
to the listdir function) changes,
the users of the function are
doomed.
Is the type of pent->d_name the
same as string *?
The address of the directory name,
pent->d_name, is copied into the
results array, but not the content
of the directory name. The OS may
reuse this location without telling
you; so copying the address of the
text is not a good idea.
The main function does not delete
the memory allocated for the
results. This is known as a memory
leak.
Suggestions / Fixes
Use std::string within the
function. This takes care of
allocating memory for text.
Use std::vector<string> for the
results. This takes care of knowing
the quantity of directories and no
need to dynamically allocate or
deallocate memory.
Create a std::string from the
pent->d_name and use push_back
to append the string to the results.
In C++, dereferencing a pointer is achieved using the * operator, just like in 'C'.
However, there are a number of problems with your code, which I have addressed here because I was bored...
#include <string>
#include <iostream>
#include <list>
#include <dirent.h>
typedef std::list<std::string> dir_list;
bool listdir(const std::string& path, dir_list& result)
{
bool retval = true;
DIR* pdir = opendir(path.c_str());
if (pdir == NULL)
{
std::cerr << "ERROR! pdir could not be initialised correctly" << std::endl;;
retval = false;
}
else
{
for (dirent* pent = readdir(pdir); pent != NULL; pent = readdir(pdir))
{
if (pent == NULL && result.empty())
{
std::cerr << "ERROR! pent could not be initialised correctly" << std::endl;
retval = false;
}
if (result.size() < 50)
{// *really* limit to 50!
result.push_back(pent->d_name);
}
}
closedir(pdir);
}
return retval;
}
int main()
{
dir_list dirs;
if (listdir("C:/", dirs))
{
for (dir_list::const_iterator iter(dirs.begin()), end(dirs.end()); iter != end; ++iter)
{
std::cout << *iter << std::endl;
}
}
}
Since you're using C++, STL, its string and container classes will save you a World of pointer pain!
your while statement looks strange, it looks like it's expecting dirs[i] to be a pointer, but I believe dirs[i] will be a non-pointer type. Maybe change it to (assuming string is std::string):
while(i < 50 && dirs[i].length() > 0)
{
cout<<dirs[i]<<'\n';
++i;
}