I am implementing a String matching algorithm for a username database. My method takes an existing Username database and a new username that the person wants and it checks to see if the username is taken. if it is taken the method is supposed to return the username with a number that isn't taken in the database.
Example:
"Justin","Justin1", "Justin2", "Justin3"
Enter "Justin"
return: "Justin4" since Justin and Justin with the numbers 1 thru 3 are already taken.
I have already written this code in Java, and now I am writing it in C++ for practice. I have a few problems though:
How do you compare two strings? I have tried strcmp and a few others but I always get the error message: cannot convert std::string to const char* for argument 2.
how do you concatenate an int and a string? in java it was as simple as using the + operator.
In my main function, it says there is no matching function call for Username::NewMember(std::string, std::string). why does it not recognize newMember in main?
#include<iostream>
#include<string>
using namespace std;
class Username {
public:
string newMember(string existingNames, string newName){
bool found = false;
bool match = false;
string otherName = NULL;
for(int i = 0; i < sizeof(existingNames);i++){
if(strcmp(existingNames[i], newName) == 0){
found = true;
break;
}
}
if(found){
for(int x = 1; ; x++){
match = false;
for(int i = 0; i < sizeof(existingNames);i++){
if(strcmp(existingNames[i],(newName + x)) == 0){
match = true;
break;
}
}
if(!match){
otherName = newName + x;
break;
}
}
return otherName;
}
else return newName;
}
int main(){
string *userNames = new string[4];
userNames[0] = "Justin";
userNames[1] = "Justin1";
userNames[2] = "Justin2";
userNames[3] = "Justin3";
cout << newMember(userNames, "Justin") << endl;
delete[] userNames;
return 0;
}
}
Ok, there is some mistakes in your code :
If you want to compare two strings, simply use the operator== : string == string2
If you want to append an int to a string in C++ you can use streams :
#include <sstream>
std::ostringstream oss;
oss << "Justin" << 4;
std::cout << oss.str();
You are passing a string* to the function newMember but you prototype doesn't match that :
string *userNames = new string[4];
newMember(userNames, "Justin"); // Call
string newMember(string existingNames, string newName); // Protype
I think it should be : string newMember(string* existingNames, string newName); no ?
In the example, your main function is inside you class Username. It is not correct in C/C++. Unlike Java, the main function as to be in the global scope.
Finally you should use const-reference parameter because you don't need to modify the content of them and you need to copy them either :
string newMember(string* existingNames, const string& newName);
// ^^^^^ ^
Are you sure you need something allocated dynamically in the main function ?
Related
I wrote a program which perform string compression using counts of repeated characters. The program in C++ is :
#include<iostream>
#include<cstring>
std::string compressBad(std::string str)
{
std::string mystr = "";
int count = 1;
char last = str[0];
for (int i = 0; i < str.length();++i)
{
if(str[i] == last)
count++;
else
{
std::string lastS = last+"";
std::string countS = std::to_string(count);
mystr.append(lastS);
mystr.append(countS);
//mystr = mystr + last + count;
count = 1;
last = str[i];
}
}
std::string lastS = last+"";
std::string countS = std::to_string(count);
mystr.append(lastS);
mystr.append(countS);
return mystr;
//return mystr+last+count;
}
int main()
{
std::string str;
std::getline(std::cin, str);
std::string str2 = compressBad(str);
std::cout<<str2;
/*if (str.length() < str2.length())
std::cout<<str;
else
std::cout<<str2;*/
std::cout<<std::endl;
return 0;
}
Few example on running this are :
Input : sssaaddddd
Output : ùÿÿ*425
Output it should print : s3a2d5
Second example:
Input : sssaaddd
Output: ùÿÿ*423
Output it should print : s3a2d3
I also implemented the same concept in Java and there it is working fine. The java implementation is here
Why is this problem happening with above code.
There may be other issues in your code, but I think that this line might be to blame:
std::string lastS = last+"";
Here, you're trying to convert the character last to a string by concatenating the empty string to the end. Unfortunately, in C++ this is interpreted to mean "take the numeric value of the character last, then add that to a pointer that points to the empty string, producing a new pointer to a character." This pointer points into random memory, hence the garbage you're seeing. (Notice that this is quite different from how Java works!)
Try changing this line to read
std::string lastS(1, last);
This will initialize lastS to be a string consisting of just the character stored in last.
Another option would be to use an ostringstream:
std::ostringstream myStr;
myStr << last << count;
// ...
return myStr.str();
This eliminates all the calls to .append() and std::to_string and is probably a lot easier to read.
last + "" doesn't do what you think.
just do
mystr.append(1, last);
I have this assignment at school. A string pointer is passed to the function and returns 2 const strings to a different functions.
The 2 new strings divide the original string into 2 parts based on a space.
Example:
Input
str = 05/12 Hello
Desired output
key = 05/12
satData = Hello
This is the code I wrote but its giving me errors. Please help
void RBapp::processInsert(string &str)
{
string *key = new string();
string *satData = new string();
int i = 0, j =0;
while(str[i]!=" ")
{
key[j] = str[i];
i++;
j++;
}
j = 0;
while(str[i]!='\0')
{
satData[j] = str[i];
i++;
j++;
}
myRBT.rbInsert(key, satData);
}
Using stringstream
void RBapp::processInsert(const std::string &str)
{
std::stringstream ss(str);
std::string key;
std::string satData;
ss >> key;
ss >> satData;
myRBT.rbInsert(key, satData);
}
Your program is subject to undefined behavior since you are accessing memory that is not valid.
When you use:
string *key = new string();
string *satData = new string();
You have two pointers that point to empty strings.
key[j] = str[i];
is wrong if j > 0 since that points to invalid memory.
Based on the description of what you are trying to do, what you need is something along the lines of:
void RBapp::processInsert(string &str)
{
// There is no need to use new string.
// Just use two string objects.
string key;
string satData;
int i = 0;
while(str[i]!=" ")
{
// Add the character to key
key.push_back(str[i]);
i++;
}
// Increment i here if you want the space to be excluded from
// satData. If you want to include the space character in satData,
// then, there is no need to increment i
++i;
while(str[i]!='\0')
{
// Add the character to satData
satData.push_back(str[i]);
i++;
}
myRBT.rbInsert(key, satData);
}
You say you receive a string pointer - what I see is you receive a string. In C++ you would try to avoid hand-written loops as much as possible - std::string has a lot of stuff you need.
void process(const string &str) {
auto firstSpace = str.find_first_of(' ');
auto key = str.substr(0, firstSpace);
auto value = str.substr(firstSpace, string::npos);
myRBT.rbInsert(key, value);
}
I am having a bit of an issue with a current task of mine. Basically, I am given an XML file and am trying to parse it for key information. For example, some lines will be like this:
<IPAddress>123.45.67</IPAddress>
And I am to get the value of 123.45.67, nothing too bad at all. I was told not to use a XML parser and just parse it manually, which was pretty easy. However, I am having issues with the second part of the task. Basically, I am to make a class with certain member variables and declare them based on the values I parse. So let's say the class is called Something and there is a member variable called IPAddress. I am to then update the value of IPAddress to 123.45.67 so when someone calls Something.IPAddress in the main method, it returns 123.45.67. This was my initial attempt at it:
#include <iostream>
#include <fstream>
#include <string>
#include <sys/stat.h>
using namespace std;
class Something
{
public:
string location;
string IPAddress;
string theName;
int aValue;
//loop through the array from the method below
void fillContent(string* array)
{
for(int i = 0; i < array->size(); i++)
{
string line = array[i];
if((line.find("<") != std::string::npos) && (line.find(">")!= std::string::npos))
{
unsigned first = line.find("<");
unsigned last = line.find(">");
string strNew = line.substr (first + 1, last - first - 1); //this line will get the key, in this case, "IPAddress"
unsigned newfirst = line.find(">");
unsigned newlast = line.find_last_of("<");
string strNew2 = line.substr(newfirst + 1, newlast - newfirst - 1); //this line will get the value, in this case, "123.45.67"
if(strNew == "IPAddress")
{
IPAddress = strNew2; //set the member variable to the IP Address
}
}
}
}
//this method will create an array where each element is a line from the xml
void fillVariables()
{
string line;
ifstream myfile ("content.xml");
long num = //function that gets size that I didn't add to make code shorter!;
string *myArray;
myArray = new string[num];
string str1 = "";
string strNew2 = "";
int counter = 0;
if (myfile.is_open())
{
while ( getline (myfile,line) )
{
myArray[counter] = line;
counter++;
}
myfile.close();
}
fillContent(myArray);
}
};
int main(int argc, char* argv[])
{
Something local;
local.fillVariables();
cout << local.IPAddress<< endl; // should return "123.45.67"
return 0;
}
Now this does do what I want it to do, however, you can see I need the if statement. Assuming I have at least 20 of these member variables, having 20 if-statements would be annoying and just frowned upon. Is there any other way I could somehow access the member variables from the class? Sorry if my question was long, I just wanted to make sure everything that is needed to understand the question is provided! Please let me know if anything crucial that may not be there should be added.
Thanks a lot!
This may be considered bad style, but I usually just do:
// at the top of the 'fillContent' function
std::map<string, string*> varmap{
{"IPAddress", &IPAddress},
{"AnotherField", &AnotherField}
};
// If you're not using C++11, you can also try:
// std::map<string, string*> varmap;
// varmap["IPAddress"] = &IPAddress;
// varmap["AnotherField"] = &AnotherField;
// parsing code goes here
*varmap[strNew] = strNew2;
I am a beginner to programming. My current university assignment tells me to read a text from a file and only get "valid" words, ie end instead of end.. I got stuck at the part where I have to put a new detected word into an array of words.
Compiler error is: array must be initialized with a brace-enclosed initializer
int const MAX_WORDS = 100000;
int const MAX_WORDLENGTH = 80;
typedef char Word [MAX_WORDLENGTH];
typedef Word Words [MAX_WORDS];
Words words ;
bool read_file (char filename [80])
{
ifstream file(filename);
if(!file) {
cout << "wrong filename";
return false;
}
char c;
int word_idx = 0;
Word word = words[word_idx++];
int letter_idx = 0;
int connector_count = 0;
while (file.get(c)) {
if ((c>='A' && c<='Z')||(c>='a' && c<='z'))
{
word[letter_idx++] = c;
cout << c << endl;
}
else {
if (c == '-') {
if(connector_count==0) {
word[letter_idx++] = c;
connector_count++;
}
else {
if(connector_count==1) {
word[letter_idx-1] ='\n';
Word word = words[word_idx++];
}
}
}
}
}
this is the line that causes the error (you have two of these):
Word word = words[word_idx++];
array initialization by assignment is illegal in C++, so for instance if you have something like this:
typedef char string[5];
string str = "hello";
and you try doing something like this:
string str2 = str;
you'll get the same error that you got. the way you deal with this, is by including
#include <string.h> and doing this:
memcpy(str2, str, sizeof(string));
so in your case, instead of Word word = words[word_idx++];, you should do this:
Word word; //declare variable
memcpy(word, words[word_idx++], sizeof(Word)); //copy to variable
of course, if you want to avoid future headaches, use std::string.
hope this helps.
Suppose I have the following func and want to compare field as variable and value as value. How can I do it?
bool ReadFile::compareField(string field, string value)
{
if (field == "value")
}
If you're talking about C++, then the answer is: you can't. Variables are a compile-time thing; they don't exist at run-time.
If you want to access parameters as strings, then you might consider using e.g. a std::map:
class MyClass
{
private:
std::map<std::string, int> params;
public:
MyClass()
{
params["height"] = 165;
params["weight"] = 65;
params["legs"] = 2;
}
int getParam(const std::string &str) const
{
return params[str];
}
};
I changed the above func without map to the following func:
bool ReadFile::compareField( string * field, string value){
int i;
string fieldName = *field;
//converting to lower case
for (i = 0; i< strlen(value.c_str());i++)
value[i] = tolower(value[i]);
for (i = 0; i< strlen(fieldName.c_str());i++)
fieldName[i] = tolower(fieldName[i]);
/////
cout << fieldName << endl;
if (strstr(fieldName.c_str(),value.c_str()) != NULL){
return true;
}
return false;
}
At first i convert to lowercase and then search with strstr func, But here is a nice note that i use address of that variable instead of its name.