C++ Why is my program throwing an exception? - c++

I'm new to programming and I'm trying to code a function that gets the shortest string from a list, but everytime I run it, visual studio shows an error "Exception thrown: read access violation". Where is the mistake?
#include <iostream>
#include <string>
using namespace std;
const string &shortest_string(initializer_list<string> strings) {
string *shortest_one = nullptr;
for (string string : strings) {
if (shortest_one == nullptr) shortest_one = &string;
else {
if (string.size() < shortest_one->size()) shortest_one = &string;
}
}
return *shortest_one;
}
int main() {
cout << shortest_string({ "hello" , "my", "name", "is", "dan" }) << endl;
return 0;
}

if (shortest_one = nullptr) is not a comparison operation. It is an assignment, that sets shortest_one to nullptr. This operation evaluates to 0, so the if expression is equivalent to if (0), or if (false).
Then in the else block, you are using shortest_one->size() but shortest_one is null...
Try to use if (shortest_one == nullptr) instead.

You made variable with name that matches type name (string variable, string type?). Plus there is issue that you return pointer to object with local scope of life. That is UB. Using iterators your function would work like this:
const string shortest_string(initializer_list<string> strings) {
if(!strings.size()) return string();
auto shortest_one = strings.begin();
for (auto it = shortest_one+1; it < strings.end(); it++ )
{
shortest_one = (it->size()< shortest_one->size()) ? it : shortest_one;
}
return *shortest_one;
}

Related

I want to combine the list and find(), but I don't know how to merge them

Please see the part where the find() function is called. (I ran it in Visual Studio.)
Code:
using namespace std;
int main(void) {
//Implementing the find()
/*
bool Find(const Stu & a); {
return (*it).name;
}
*/
list<Astu>::iterator that;
//that = astu.begin();
//that = find(astu.begin(), astu.end(), (*it).name);
for (it = stu.begin(); it != stu.end(); it++) {
that = find_if(astu.begin(), astu.end(), (*it).name);
if (that != astu.end()) {
all = astu.erase(all);
all++;
}
else
all++;
}
/*
//Filter absenteeism from the total student roster
for (it = stu.begin(); it != stu.end(); it++) {
for (all = astu.begin(); all != astu.end();) {
if (!strcmp((*all).name, (*it).name)) {
//Delete attendees and latecomers from the list
all = astu.erase(all);
}
else
all++;
}
}
*/
cout << "---------------------\n결석자: " << endl;
//이름순으로 정렬
astu.sort(SizeComp2);
//결석자들 출력
for (all = astu.begin(); all != astu.end(); all++) {
cout << "이름: " << (*all).name << endl;
}
return 0;
}
Output:
C2064 error occurred: Term does not evaluate to a function that takes
1 argument.
Even with find_if() in this code, there is a problem. The bool() part in the comment was used for the find_if object, but it doesn't seem to be used well here.
I deleted the part where there was no problem as a result of debugging. You must use an unconditional list, not a vector.
Where should I fix it?
The third argument to std::find_if is a function.
You could use a lambda as the function:
auto that = find_if(astu.begin(), astu.end(), [it](Astu const& astu)
{
return astu.name == it->name;
});
[This assumes that Astu::name is a std::string]

Error when calling void function with <set> operator

I am trying to pass a string and and an empty set into my function. Then I would like to call the function in my main and print all of the elements in the set.
This is my function code:
#include<iostream>
using std::cout; using std::endl;
#include<algorithm>
using std::set_union; using std::copy;
#include<iterator>
using std::inserter; using std::ostream_iterator;
#include<string>
using std::string;
#include<set>
using std::set;
void removing(const string &word, set<string> &result) {
string del_word = word;
char erased_l;
for(int i = 0; i < del_word.length(); i++) {
erased_l = word[i];
del_word.erase(0, 1);
del_word = erased_l + del_word;
}
}
Below is my main code where I call the function:
int main (){
set<string> jump = {};
set<string> del = removing("axiom", jump);
for (string ele:del) {
cout << ele << endl;
}
}
I get the following error:
No viable conversion from 'void' to 'set<std::__1::string>' (aka 'set<basic_string<char, char_traits<char>, allocator<char> > >')
The error is in line 16:
set<string> del = removing("axiom", jump);
My code is trying to accomplish:
If I pass in axiom, then I would like my string set to have {xiom, aiom, axom, axim, axio}. So remove first letter, keep rest of the word. Then remove second letter, keep rest of the word, etc...
Primary issues include:
The return value of a void function can't be assigned to a set, hence your compiler error. Your design is to pass a reference to an empty result set into the removing function and have it populated with the result data, so you can remove the assignment here.
Nothing is added to your result inside your removing function, so it starts empty and ends empty after the function call.
Here's a working version:
void removing(const string &word, set<string> &result) {
for (int i = 0; i < word.length(); i++) {
result.insert(word.substr(0, i) + word.substr(i + 1, word.length()));
}
}
int main () {
set<string> jump = {};
removing("axiom", jump);
for (string ele : jump) {
cout << ele << endl;
}
}
Output:
aiom
axim
axio
axom
xiom
Having said that, it's not clear to me why result should be a parameter to the function. If you're only planning on using it to store this particular result, this design seems much cleaner from the perspective of the caller:
set<string> removing(const string &word) {
set<string> result;
for (int i = 0; i < word.length(); i++) {
result.insert(word.substr(0, i) + word.substr(i + 1, word.length()));
}
return result;
}
int main () {
set<string> jump = removing("axiom");
for (string ele : jump) {
cout << ele << endl;
}
}
Try it!

Vector losing contents between files in C++

I have some methods in lexer.h which make use of a Vector made of Tokens.
In this method void getNextToken() I am making use of the said vector where I am adding new tokens to it.
The problem is, that when I go to a different file, I am trying to access ANOTHER method which makes use of this vector, but it is crashing with an out of bounds error (most probably it's being deferenced or something)
Is there a way how I can fix this?
The methods in concern are:
Token* nextToken()
{
if (it!= tokensUsed.end())
{
// we Assigned what is found in the iterator it (of the vector)
// so we get the data found in that pointer
itrToken = &*it;
//Move Iterator forward
it ++;
return itrToken;
}
}
/*
Used in Parser to go get the PREVIOUS Tokens
*/
Token* prevToken()
{
itrToken --;
if (it!= tokensUsed.begin())
{
itrToken = &*this->it;
return itrToken;
}
}
void getNextToken()
{
//CODE ADDING TOKENS
//EXAMPLE
if (ch == '"')
{
addAndGetNext(ch);
cout << "STRING: " << strBuffer << endl; //TEST
//create new token and push it into the vector
tk = new Token (Token::ttString, strBuffer, row, col);
tokensUsed.push_back(*tk); //Add the new token to the Vector
startNewString(); //Clear the string
}
tokenMatch = true;
}
The above is just partial code, to show an example.
Now in Parser.h I am using this method to call the lexer.h:
void relOpP()
{
Token* tk = nextToken();
if (tk -> getType() == Token::ttString)
{
cout << "Ture";
}
}
which calls the Lexer's nextToken() it crashes, and when I tried checking it's contents it goes outofBounds error (and CodeBlocks giving me a SIGSEGV error)
I know it's something from the pointers that it's going awry, but how can I fix it?
Edit:
These are the global variables I have declared:
vector<Token>::iterator it;
vector<Token> tokensUsed;
Token* itrToken; // used for iterator
bool checkQuote = false;
Token* tk = new Token (syNewToken, "", 1,0);
Token token; // Creates an instance of the class Token found in the file token.h
Token* t;
SAMPLE CODE:
main.cpp
#include <iostream>
#include "lexer.h"
#include "parser.h"
using namespace std;
int main()
{
Lexer* l;
l -> getNextToken();
Parser p(l);
p.relOpP();
}
Token (int type, string sBuffer, int rRow, int cCol)
{
this->tType = type;
this->strBuffer = sBuffer;
this->row = rRow;
this->col = cCol;
}
parser.h
#ifndef PARSER_H_INCLUDED
#define PARSER_H_INCLUDED
#include <string>
#include <vector>
#include "lexer.h"
#include "token.h"
using namespace std;
class Parser{
private:
Lexer* lexer;
string tree = "";
public:
Parser (Lexer* l)
{
this -> lexer = l;
}
Token nextToken()
{
Token tk = lexer -> nextToken();
return tk;
}
void relOpP()
{
Token tk = nextToken();
if (tk.getType() == 1)
{
cout << "Ture";
}
}
#endif // PARSER_H_INCLUDED
};
token.h
#ifndef TOKEN_H_INCLUDED
#define TOKEN_H_INCLUDED
#include <iostream>
using namespace std;
class Token
{
private:
int tType; //identifier or reserved by compiler?
string strBuffer; //string found in buffer at that moment
int row;
int col;
public:
enum tokenType
{
tkString
};
Token()
{
}
// The instance of a token with 4 parameters resulting the type, the contents of the string that represents that type
// the row it is found in and the column.
Token (int type, string sBuffer, int rRow, int cCol)
{
this->tType = type;
this->strBuffer = sBuffer;
this->row = rRow;
this->col = cCol;
}
Token (Token* getT)
{
this-> tType = getT -> tType;
this->strBuffer = getT -> strBuffer;
this->row = getT -> row;
this->col = getT -> col;
}
int getType ()
{
return this->tType;
}
//return the string contents
string getBuffer()
{
return this->strBuffer;
}
//return row
int getRow()
{
return row;
}
//return col
int getCol ()
{
return col;
}
};
#endif // TOKEN_H_INCLUDED
Lexer.h
#ifndef LEXER_H_INCLUDED
#define LEXER_H_INCLUDED
#include "token.h"
#include <vector>
using namespace std;
class Lexer
{
private:
Token tk = new Token (1, "", 1,0);
vector<Token>::iterator it;
vector<Token> tokensUsed;
Token itrToken; // used for iterator
public:
Token nextToken()
{
if (it!= tokensUsed.end())
{
// we Assigned what is found in the iterator it (of the vector)
// so we get the data found in that pointer
itrToken = &*it;
//Move Iterator forward
it ++;
return &itrToken;
}
else
{
cout << "ERROR" << endl;
}
return nullptr;
}
void getNextToken()
{
cout << "Test" << endl;
string strBuffer = "test";
int row = 0;
int col = 0;
tk = new Token (1,strBuffer,row,col);
}
};
#endif // LEXER_H_INCLUDED
In nextToken() and prevToken() there is no return for the case the if evaluates to false. The return value in that case is not very likely to be something (it could be anything...) that you can then dereference.
If you want to keep the current design you should return nullptr or (NULL if you don't have C++11 support) in that case. Then you need to change any code that uses the result of those functions to check if the pointer is valid before dereferencing it.
You would probably be better changing your design to not involve so much manual pointer manipulation. But to fix up your current version you should change your prevToken and nextToken to be something along the lines of:
Token* nextToken()
{
if (it!= tokensUsed.end())
{
...
return itrToken;
}
else
{
return nullptr;
}
}
Then if tk is the result of calling one of these functions you must not use tk-> or *tk if it is nullptr. Any code wanting to work with the result will need to check first.
So for example you could change you if statement to be:
if (tk && // Make sure tk is not nullptr
tk -> getType() == Token::ttString)
{
...
There are too many problems with your code for me to address them all in this post. The first, and most obvious one is this.
In the main function:
Lexer* l;
l -> getNextToken();
Here, you did not create a Lexer object. You just created an uninitialized pointer to one. Then you called a member function as if it pointed to an object. This is undefined behavior. You then pass this pointer to your Parser class, which continues to treat it as a valid object, resulting in more undefined behavior.
There are many other problems with your code, but most of them have to do with your mishandling of pointers, indicating a lack of understanding of how they work. The best suggestion for you is to stop using them entirely. There is no reason you need to use any pointers whatsoever to do what you are doing. If you can't figure out how to do what you are trying to do without pointers, it is because of a lack of fundamental understanding of the language. You need to read a C++ book, to completion. Here's a list of some good ones.
The Definitive C++ Book Guide and List

How do I return a Null Pointer in a function C++

I am currently working on a bit of code that will search within a vector of type Person (which I have defined in the code and will show if needed). If it finds the person, it returns their name. This is currently working, but if it does not find the person, it is supposed to return a Null pointer. The problem is, I cannot figure out how to make it return a Null pointer! It just keeps either crashing the program every time.
Code:
Person* lookForName(vector<Person*> names, string input)
{
string searchName = input;
string foundName;
for (int i = 0; i < names.size(); i++) {
Person* p = names[i];
if (p->getName() == input) {
p->getName();
return p; //This works fine. No problems here
break;
} else {
//Not working Person* p = NULL; <---Here is where the error is happening
return p;
}
}
}
You could use std::find_if algorithm:
Person * lookForName(vector<Person*> &names, const std::string& input)
{
auto it = std::find_if(names.begin(), names.end(),
[&input](Person* p){ return p->getName() == input; });
return it != names.end() ? *it : nullptr; // if iterator reaches names.end(), it's not found
}
For C++03 version:
struct isSameName
{
explicit isSameName(const std::string& name)
: name_(name)
{
}
bool operator()(Person* p)
{
return p->getName() == name_;
}
std::string name_;
};
Person * lookForName(vector<Person*> &names, const std::string& input)
{
vector<Person*>::iterator it = std::find_if(names.begin(), names.end(),
isSameName(input));
return it != names.end() ? *it : NULL;
}
If the name you are searching for is not at the first element, then you are not searching in the rest of the elements.
You need to do something like -
for (int i = 0; i<names.size(); i++){
Person* p = names[i];
if (p->getName() == input) {
return p;
// Placing break statement here has no meaning as it won't be executed.
}
}
// Flow reaches here if the name is not found in the vector. So, just return NULL
return NULL;
As Chris suggested, try using std::find_if algorithm.
Looks like you just have to return Null, nullptr, or 0.
codeproject
Just use following code:
return NULL;

Checking if Container has Value (c++)

I have a custom class 'team' and one of its attributes is its 'name.' After each 'team' is created, I add it to a vector teamList.
I would like to implement a function that continuously prompts the user for a team name which is not already taken by a team within the teamList. I have the following code:
while (true) {
string newString;
bool flag = true;
getline(cin, newString);
for (int i = 0; i < teamList.size(); i++) {
if (teamList[i].name.compare(newString) == 0) flag = false;
}
if (flag == true) {
return newString;
} else {
cout << "name already taken." << endl;
}
}
However, this code is really ugly; is there a better way to check? Also, a more general question- faced with an issue of ugly code (like this one), what kinds of steps can I take to find a new, cleaner implementation? Thanks.
I would use std::set, which deals with duplicates for you. As an example, you can see that the class is sorted by the string member, and when three are inserted in main, only two stay because two of the insertions have the same string, so they are treated equal.
#include <iostream>
#include <set>
#include <string>
struct SetThing {
SetThing(int value, const std::string &value2) : i(value), s(value2){}
int i;
std::string s;
bool operator<(const SetThing &other) const {
return s < other.s;
}
};
int main() {
std::set<SetThing> s;
s.insert(SetThing(5, "abc"));
s.insert(SetThing(4, "def"));
s.insert(SetThing(6, "abc"));
std::cout << s.size();
}
Now for inserting, you can just reprompt while the second member of the returned pair is false:
do {
//get input
} while (!teamList.insert(somethingBasedOnInput).second);
define an equality operator in team that can compare a team to a string:
bool team::operator==(string s) const
{
return(s==name);
}
Then you can use find:
vector<team>::const_iterator itr = find(teamList.begin(), teamList.end(),
newString);
if(itr!=league.end())
cout << "name already taken" << endl;