whats wrong with this c++ piece of code? - c++

In this piece of code, in every iteration of while loop, a line is read from a file. The line is something like:
13,4636137,29464742,29464746,995560164
for every number specified in bold, the existence of that number as a key in a std::map is checked in a for loop. If the key exists, then the value is appended to the string. Then the string is written to the file.
If one of keys not exist in the map, then for that line nothing should be written to the file. (bool is_points_in_range)
But in practice, in the cases that the last point (outside of for loop) is not in key list, the program logic performs well.
Why the boolean operator does not change in for loop?
vector<string> res;
ifstream infile;
map<string, string> m;
while(infile.getline(buffer, LINE_BUFFER_LEN))
{
line=string(buffer);
res = SplitBySep(line, ",");
bool is_points_in_range=true;
string geo_file_line;
for (int i=2;i<res.size()-1;i++){
if ( m.find(res[i]) == m.end() ) {
is_points_in_range=false;
break;
} else {
geo_file_line= geo_file_line.append(m[res[i]]).append("^");
}
}
if ( m.find(res[res.size()-1]) == m.end() ) {
is_points_in_range=false;
} else {
geo_file_line= geo_file_line.append(m[res[res.size()-1]]).append("\n");
}
if (is_points_in_range){
fprintf(fp_geo, "%s",geo_file_line.c_str());
}
}

res.size()-1 is extremely dangerous. res.size() is an unsigned type, and subtracting one from it when res.size() is 0 is going to give you a very large unsigned integer due to wraparound.
So your program is essentially undefined when res is unpopulated.
I'm amazed your compiler didn't warn you. Do you have warnings switched off?

It looks like
m.find(res[i]) == m.end()
is never true.
Are you sure that this table is fulled properly? res[i]

It is better to ask that why this conditional statement does not work well?
We know that for obtaining that a key exists in a std::map, we can use:
if ( m.find("f") == m.end() ) {
// not found
} else {
// found
}
as indicated in this question.
But for
map<string, string> m;
this statement does not work well. I dont have any 29464742 key (I am sure), but when I search for this key the else part is executed. Also when I use m.count('29464742') , 1 is returned. I don't know why?
I corrected my code with this conditional statement:
if ( m["f"] == "" ) {
// not found
} else {
// found
}
This works for me and my problem is solved.

Related

iterating vector of strings C++

The code is to read instructions from text file and print out graphic patterns. One is my function is not working properly. The function is to read the vectors of strings I've got from the file into structs.
Below is my output, and my second, third, and sixth graphs are wrong. It seems like the 2nd and 3rd vectors are not putting the correct row and column numbers; and the last one skipped "e" in the alphabetical order.
I tried to debug many times and still can't find the problem.
typedef struct Pattern{
int rowNum;
int colNum;
char token;
bool isTriangular;
bool isOuter;
}Pattern;
void CommandProcessing(vector<string>& , Pattern& );
int main()
{
for (int i = 0; i < command.size(); i++)
{
Pattern characters;
CommandProcessing(command[i], characters);
}
system("pause");
return 0;
}
void CommandProcessing(vector<string>& c1, Pattern& a1)
{
reverse(c1.begin(), c1.end());
string str=" ";
for (int j = 0; j < c1.size(); j++)
{
bool foundAlpha = find(c1.begin(), c1.end(), "alphabetical") != c1.end();
bool foundAll = find(c1.begin(), c1.end(), "all") != c1.end();
a1.isTriangular = find(c1.begin(), c1.end(), "triangular") != c1.end() ? true : false;
a1.isOuter = find(c1.begin(), c1.end(), "outer") != c1.end() ? true : false;
if (foundAlpha ==false && foundAll == false){
a1.token = '*';
}
//if (c1[0] == "go"){
else if (c1[j] == "rows"){
str = c1[++j];
a1.rowNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "columns"){
str = c1[++j];
a1.colNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "alphabetical")
a1.token = 0;
else if (c1[j] == "all"){
str = c1[--j];
a1.token = *str.c_str();
j++;
}
}
}
Before debugging (or posting) your code, you should try to make it cleaner. It contains many strange / unnecessary parts, making your code harder to understand (and resulting in the buggy behaviour you just described).
For example, you have an if in the beginning:
if (foundAlpha ==false && foundAll == false){
If there is no alpha and all command, this will be always true, for the entire length of your loop, and the other commands are all placed in else if statements. They won't be executed.
Because of this, in your second and third example, no commands will be read, except the isTriangular and isOuter flags.
Instead of a mixed structure like this, consider the following changes:
add a default constructor to your Pattern struct, initializing its members. For example if you initialize token to *, you can remove that if, and even the two bool variables required for it.
Do the parsing in one way, consistently - the easiest would be moving your triangular and outer bool to the same if structure as the others. (or if you really want to keep this find lookup, move them before the for loop - you only have to set them once!)
Do not modify your loop variable ever, it's an error magnet! Okay, there are some rare exceptions for this rule, but this is not one of them.
Instead of str = c1[++j];, and decrementing later, you could just write str = c1[j+1]
Also, are you sure you need that reverse? That makes your relative +/-1 indexing unclear. For example, the c1[j+1 is j-1 in the original command string.
About the last one: that's probably a bug in your outer printing code, which you didn't post.

unordered_set erase not working in C++

Consider the following situation
void first(){
unordered_set<int> validPorts;
int roundNum=0, preFunctionSize, postFunctionSize,j=0 ;
while(j <100){
if(some_condition_A){
validPorts.insert(some_int_value);
}
j++;
}
do{
preFunctionSize = validPorts.size();
second( validPorts, some_int_value );
postFunctionSize = validPorts.size();
}while(roundNum<12);
}
void second( unordered_set<int> & validPorts, int some_int_value ){
for (auto it = validPorts.begin(); it != validPorts.end();) {
if (it == validPorts.find(some_int_value)) {
validPorts.erase(it++); // <== CODE enters here, I checked
} else {
++it;
}
}
}
So I expect that the postFunctionSize should be less than the preFunctionSize since I know that it went till the erase function. But it looks like the erase function does not work since i get the same value for the two of them. I am not really sure whats happening here and what is causing it. Can you guys please help me out on what might be wrong with this?
Your code is pseudo of course in places but you need to do:
it = validPorts.erase( it );
in a loop where you are iterating through a collection erasing some of them.
However that is also not really what you want to do. You are trying to erase a value from your unordered_set so just do
validPorts.erase( some_int_value );
and no loop.

Access violation reading location 0x00000006

I have the following code which finds the strings that contain no Alphabets. Cases like mynumber123 shall not be recognized and the numberFinder() should return false and case like 123 shall be recognized and numberFinder() shall return true as well as the begin index of the number.
the constructor:
CaddressParser::CaddressParser(string fileName) //constructor
{
m_fileName=fileName;
int length=getLength(m_fileName.c_str());
m_text =fileReader(m_fileName.c_str());
m_length=length;
}
which initializes a string m_text that contains the contents of a text file
Somewhere along the implementation I come across the following code:
for (i;i<m_length;i++)
{
bool UpperCaseBeforeNoFound=false;
if(this->numberFinder (i).second)
{
//do some calculations.
}
}
the numberFinder function is implemented as follows:
pair <int,bool> CaddressParser::numberFinder(int counter)
{
bool noFound=isdigit(m_text[counter]); //number found? -> true
if(noFound)
{
int end=HouseNoDigits(counter);
if(((counter-1)>=0) && ((counter +end-1) <m_length))
{
if((!(isalpha(m_text[counter-1]))) && (!isalpha(m_text[counter+end-1])))
{
return make_pair(counter,noFound); //return index if true
}
}
}
else return make_pair(0,noFound);
}
Now the problem is for a text file containing the following text "he23 Market street London Q12 H13". I get the error mentioned in the headline and the debugger takes me to the line in the which contains :
if(this->numberFinder (i).second)
I can't figure out why this is happening. Please help me figure it out.
If this condition in CaddressParser::numberFinder(int counter) fails:
if (counter - 1 >= 0 && counter + end - 1 < m_length)
the function will exit without returning a value, resulting in undefined behavior.
The complexity of the conditionals in the function isn't helped by the poor formatting (at least as posted in the question).
You might get the behavior you need by removing the else so any 'fall-through' will return the default pair value (but that will depend on if that's the value you want to really return in that scenario):
pair <int,bool> CaddressParser::numberFinder(int counter)
{
bool noFound=isdigit(m_text[counter]); //number found? -> true
if(noFound)
{
// ...
}
return make_pair(0,noFound);
}
Access Violation error is normally due to NULL reference. One of the function that you are calling is trying to access a NULL pointer. Make sure your isdigit function returns true or false, m_text points to an exiting memory location. If not you need to allocate the memory. You should also check if the fileName is NULL.

logical comparison operator

Here is my code for my logical comparison operator (==) overloaded. I use this to check if two strings are identical in size and content. It should return false otherwise.
bool MyString::operator==(const MyString& other)const
{
if(other.Size == this->Size)
{
for(int i = 0; i < this->Size+1; i++)
{
if(&other == this)
return true;
}
}
else
return false;
}
When I ran valgrind it told me warning control reaches end of non-void function. Any suggestions on how to fix this issue and what I could do to better the code?
When control reaches the end of your for loop, you immediately get to the end of the function without returning a value.
It looks to me like you have the logic in your for loop munged anyway -- it's comparing the address of the other item to this. While it's sort of okay to do that, you only need to do it once, not in a loop.
In the loop, you undoubtedly want to compare the characters in the string, not the addresses of the objects.
Edit:
A typical implementation would be something on this general order:
class MyString {
char *data;
size_t length;
public:
// ...
bool operator==(MyString const &other) const {
if (length != other.length)
return false;
for (int i=0; i<length; i++)
if (data[i] != other.data[i]) // If we see any inequality
return false; // they're not equal
return true; // all equal, so the strings are equal.
}
};
It's not too clear what determines equality if the sizes are equal, but
the loop suggests that you're looking for something like:
bool
MyString::operator==( MyString const& other ) const
{
return size == other.size && std::equals( ??? );
}
Well, first of all, if you enter the for loop, and the condition &other == this will not be met, you will never return anything. To fix this, you should just remove the else statement. This will cause your function to return false either if the other.Size == this->Size condition is not met, or if you've gone through the whole loop, and have not used return inside of it.
The second problem is the line if(&other == this). I believe that inside of the loop you intend to check all the symbols of the strings. But now you are only checking the pointer to the class itself. To check the characters, you will need to use something like if( other->data == this->data ), provided you have a data member in which you store the...data (sorry for tautology).
Another little flow is in the design. You see, to check that the strings are equal, you need to look through each and every character and check that they match. However, to prove the strings are not equal, you need to find just 1 pair of characters that does not match. After that, it is pointless to continue comparing. So it is better to changee your condition in the cycle to a negative one, in order to stop comparing immediately after you fuond a pair that does not match, and not to do useless comparations of other characters.
Generaly, it is a good practice to return all the errors as fast as it's possible and avoid unneeded cumputation. So if you can check something in the begining of your function with a simple check, better do it.
So, after all, you should have something like this:
bool MyString::operator==(const MyString& other)const
{
if(other.Size != this->Size)
return false;//If the sizes do not match, no need to check anything else. Just return false.
//If we are here, the sizes match. Lets check the characters.
for(int i = 0; i < this->Size+1; i++)
{
//If some pair doesnt match, the strings are not equal, and we exit.
if( other->data[i] != this->data[i])
return false;
}
//If we are here, all the characters did match, so we return true.
return true;
}
Just get rid of the else. This way there is a "default" behaviour returning false if the condition is not met. It's the functionality you intend, and the compiler or syntax checker won't complain.

Valgrind detects invalid read error in simple Iterator class

Valgrind detects an invalid read error I don't know how to fix or to be more precise: I don't know what the problem is.
Invalid read of size 8
at 0x443212: std::vector<Tile*, std::allocator<Tile*> >::end() const
by 0x44296C: Collection<Tile*>::Iterator::operator++()
The Iterator class is very simple (and actually a somewhat bad piece of programming) but sufficient for my needs right now. I think there are three methods you should know to hopefully help find my problem:
Iterator(size_t x, size_t y, const TileCollection& tiles)
: mTiles(&tiles)
, mX(mTiles->begin())
, mY(mTiles->at(x).begin())
{
std::advance(mX, x);
std::advance(mY, y);
bool foundFirst = false;
while (!foundFirst)
{
while (mY != mX->end() && *mY == 0) ++mY;
if (mY != mX->end()) foundFirst = true;
else
{
++mX;
if (mX != mTiles->end()) mY = mX->begin();
}
}
}
Iterator Iterator::operator++()
{
bool foundNext = false;
++mY;
while (!foundNext)
{
while (mY != mX->end() && *mY == 0) ++mY;
if (mY != mX->end()) foundNext = true;
else
{
++mX;
if (mX != mTiles->end()) mY = mX->begin();
}
}
return *this;
}
void TileCollection::add(Tile* tile)
{
Point2D p(tile->getPosition());
std::vector<Tile*> tmp(1, (Tile*)0);
if ((size_t)p.x >= mTiles.size())
mTiles.resize(p.x + 1, tmp);
if ((size_t)p.y >= mTiles.at(p.x).size())
mTiles.at(p.x).resize(p.y + 1, (Tile*)0);
mTiles.at(p.x).at(p.y) = tile;
++mNumTiles;
}
The actual code that is causing the valgrind error is the line:
while (mY != mX->end() && *mY == 0) ++mY;
...of the Iterator::operator++ method.
It looks to me that, at the least, the following line in operator++
if (mX != mTiles->end()) mY = mX->begin();
is lacking a suitable else-clause.
Consider what happens when mX actually reaches mTiles->end(): You will enter a new iteration of the outer while loop; the first line in that loop (the line that causes the Valgrind error) will evaluate mX->end() and thus attempt to dereference mX -- but mX is mTiles->end(), and it's not correct to dereference the end iterator of a collection since it doesn't actually reference an element of the collection. It looks to me as if this may be the cause of your Valgrind error.
(Note that the constructor contains essentially the same code.)
More generally, I think you need to think about how you handle reaching the end of your two-dimensional array. How does the client of your Iterator check whether it has reached the end of the iteration? How do you expect your operator++ to handle the case when it reaches the end of the two-dimensional array? Should it protect itself against getting called too often?
You can try to split up the statement in order get find out where the error occurs:
while (mY != mX->end()) // maybe here
{
if (*mY != 0) // maybe here
{
break;
}
++mY; // maybe here
}
Compiling with GCC compiler option -fno-inline helps to get a nicer stack-trace, which can help you to trace the error. It will also make your program very slow, so don't forget to remove it later.