C++ Trouble Modifying A String - c++

So in this program I'm trying to go through word by word and make it only lowercase letters, no whitespace or anything else. However, my string "temp" isn't holding anything in it. Is it because of the way I'm trying to modify it? Maybe I should try using a char * instead? Sorry if this is a stupid question, I'm brand new to c++, but I've been trying to debug it for hours and can't find much searching for this.
#include <string>
#include <iostream>
#include <fstream>
#include <ctype.h>
using namespace std;
int main(int argc, char* argv[]) {
/*if (argc != 3) {
cout << "Error: wrong number of arguments." << endl;
}*/
ifstream infile(argv[1]);
//infile.open(argv[1]);
string content((std::istreambuf_iterator<char>(infile)),
(std::istreambuf_iterator<char>()));
string final;
string temp;
string distinct[5000];
int distinctnum[5000] = { 0 };
int numdist = 0;
int wordcount = 0;
int i = 0;
int j = 0;
int k = 0;
int isdistinct = 0;
int len = content.length();
//cout << "test 1" << endl;
cout << "length of string: " << len << endl;
cout << "content entered: " << content << endl;
while (i < len) {
temp.clear();
//cout << "test 2" << endl;
if (isalpha(content[i])) {
//cout << "test 3" << endl;
if (isupper(content[i])) {
//cout << "test 4" << endl;
temp[j] = tolower(content[i]);
++j;
}
else {
//cout << "test 5" << endl;
temp[j] = content[i];
++j;
}
}
else {
cout << temp << endl;
//cout << "test 6" << endl;
++wordcount;
final = final + temp;
j = 0;
for (k = 0;k < numdist;k++) {
//cout << "test 7" << endl;
if (distinct[k] == temp) {
++distinctnum[k];
isdistinct = 1;
break;
}
}
if (isdistinct == 0) {
//cout << "test 8" << endl;
distinct[numdist] = temp;
++numdist;
}
}
//cout << temp << endl;
++i;
}
cout << wordcount+1 << " words total." << endl << numdist << " distinct words." << endl;
cout << "New output: " << final << endl;
return 0;
}

You can't add to a string with operator[]. You can only modify what's already there. Since temp is created empty and routinely cleared, using [] is undefined. The string length is zero, so any indexing is out of bounds. There may be nothing there at all. Even if the program manages to survive this abuse, the string length is likely to still be zero, and operations on the string will result in nothing happening.
In keeping with what OP currently has, I see two easy options:
Treat the string the same way you would a std::vector and push_back
temp.push_back(tolower(content[i]));
or
Build up a std::stringstream
stream << tolower(content[i])
and convert the result into a string when finished
string temp = stream.str();
Either approach eliminates the need for a j counter as strings know how long they are.
However, OP can pull and endrun around this whole problem and use std::transform
std::transform(content.begin(), content.end(), content.begin(), ::tolower);
to convert the whole string in one shot and then concentrate on splitting the lower case string with substring. The colons in front of ::tolower are there to prevent confusion with other tolowers since proper namespacing of the standard library has been switched off with using namespace std;
Off topic, it looks like OP is performing a frequency count on words. Look into std::map<string, int> distinct;. You can reduce the gathering and comparison testing to
distinct[temp]++;

Related

string equal doesn't work c++

I have been struggling with comparing two strings which I read from files, "one" & "two" both have the same words (e.g. salt) but it doesn't return "Equal". I have also used == but it made no difference.
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
int main (){
string en[100];
string line;
int i=0;
ifstream fileEn ("hey.txt");
if (fileEn.is_open()){
while (!fileEn.eof()){
getline(fileEn,line);
en[i]=line;
i++;
}
}
fileEn.close();
string fa[100];
string line1;
i=0;
ifstream fileFa ("hey1.txt");
if (fileFa.is_open()){
while (!fileFa.eof()){
getline(fileFa,line1);
fa[i]=line1;
i++;
}
}
fileFa.close();
ifstream Matn("matn.txt");
string matn[100];
if(Matn.is_open()){
for(int i = 0; i < 100; ++i){
Matn >> matn[i];
}
}
Matn.close();
string one = en[0];
string two = matn[0];
cout << one << " " << two;
if(one.compare(two) == 0){
cout << "Equal";
}
}
I suggest adding some debugging output to your program:
while (!fileEn.eof()){
getline(fileEn,line);
// Debugging output
std::cout << "en[" << i << "] = '" << line << "'" << std::endl;
en[i]=line;
i++;
}
and
for(int i = 0; i < 100; ++i){
Matn >> matn[i];
// Debugging output
std::cout << "matn[" << i << "] = '" << matn[i] << "'" << std::endl;
}
Hopefully you can see what the problem is by looking at the output.
In addition, please note that use of while (!fileEn.eof()){ ... } is not correct. See Why is iostream::eof inside a loop condition considered wrong?.
I suggest changing that loop to:
while (getline(fileEn,line)) {
// Debugging output
std::cout << "en[" << i << "] = '" << line << "'" << std::endl;
en[i]=line;
i++;
}
Similarly, don't assume that Matn >> matn[i] is successful. I suggest changing that loop to:
for(int i = 0; i < 100; ++i) {
std::string s;
if ( !(Matn >> s) )
{
// Read was not successful. Stop the loop.
break;
}
matn[i] = s;
// Debugging output
std::cout << "matn[" << i << "] = '" << matn[i] << "'" << std::endl;
}

Hangman w/ Functions - Compile Error - No Match for Call To

I've been trying to get this Hangman using functions (from Michael Dawson's book) program to work, but I have this one error that I don't really understand. I realize my code code could have a variety of bad practices, but please go easy on me as I am a newb. I feel like I am almost there but I'm having trouble figuring out this one error. I am using CodeBlocks. The error is:
32|error: no match for call to '(std::__cxx11::string {aka std::__cxx11::basic_string}) (std::__cxx11::basic_string::size_type, char)'|
//Hangman from Michael Dawson's code
//Uses functions to create the program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cctype>
using namespace std;
//FUNCTION DECLARATION
string pickword();
char playerGuess();
void isitinthere();
char guess = 0;
string soFar = "word";
string used = "";
int wrong = 0;
int main()
{
const int MAX_WRONG = 8;
string WORD = pickword();
soFar = WORD;
soFar(WORD.size(), '-');
used = "";
cout << "Welcome to Hangman! Godspeed!" << endl;
while ((wrong < MAX_WRONG) && (soFar != WORD))
{
cout << "\n\nYou have " << (MAX_WRONG - wrong);
cout << " incorrect guesses left.\n";
cout << "\nYou've used the following letters:\n" << used << endl;
cout << "\nSo far, the word is:\n" << soFar << endl;
}
playerGuess();
while (used.find(guess) != string::npos)
{
cout << "\nYou've already guessed " << guess << endl;
cout << "Enter your guess: ";
cin >> guess;
guess = toupper(guess);
}
used += guess;
isitinthere();
if (wrong == MAX_WRONG)
{
cout << "\nYou've been hanged!";
}
else
{
cout << "\nYou guessed it!";
}
cout << "\nThe word was " << WORD << endl;
return 0;
}
//FUNCTION DEFINITION
string pickword()
{
srand(static_cast<unsigned int>(time(0)));
vector<string> words;
words.push_back("INDUBITABLY");
words.push_back("UNDENIABLY");
words.push_back("CRUSTACEAN");
words.push_back("RESPONSIBILITY");
words.push_back("MISDEMEANOR");
words.push_back("FORENSIC");
words.push_back("BALLISTIC");
words.push_back("PARADIGM");
words.push_back("TROUBARDOR");
words.push_back("SUPERCALIFRAGILISTICEXPIALLADOCIOUS")
random_shuffle(words.begin(), words.end());
theword = words[0];
return theword;
}
char playerGuess()
{
cout << "\n\nEnter your guess: ";
cin >> guess;
guess = toupper(guess);
return guess;
}
void isitinthere()
{
if (WORD.find(guess) != string::npos)
{
cout << "That's right! " << guess << " is in the word.\n";
for (int i = 0; i < WORD.length(); ++i)
{
if (WORD[i] == guess)
{
soFar[i] = guess;
}
}
}
else
{
cout << "Sorry, " << guess << "isn't in the word. \n";
++wrong;
}
}
Thanks in advance for your help!
Here is a simple program that should solve your question.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cctype>
// since you must have function here are some
bool removeGuessFromWord(std::string& word, const char guess);
bool isGuessInWord(const std::string& word, const char guess);
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess);
// this is a simple program that should solve your question. It is not optimized for speed or efficency.
int main()
{
std::vector<std::string> wordList = {"dog","cat","rat"}; // vector of words to select from and use as the word in hangman
std::vector<char> guessList; // empty vector of gusses
// Note that I assume a MAX_GUESS_COUNT of 0 means no guesses are allowed
const unsigned int MAX_GUESS_COUNT = 4U; // number of guesses your allowed
std::srand(time(0)); // use current time as seed for random generator
std::string word = wordList.at(std::rand()%wordList.size()); // get a random word in the list
std::string letersLeft = word; // keep track of what letters will still need to remove
std::cout << "Welcome to Hangman! Godspeed!" << std::endl;
char guess = 0;
for(unsigned int numBadGusses=0U; numBadGusses<MAX_GUESS_COUNT && letersLeft.size()>0U; guess = 0)
{
std::cin>>guess;
if(std::isprint(guess) == 0)
{
// may want more error checking
std::cout << "You ented a non-printable charecter" << std::endl;
}
else if(isGuessInWord(word, guess))
{
// this was a good guess because the charecter is still in the word
// so remove all the remaining chars of this type from the word
if( removeGuessFromWord(letersLeft,guess) )
{
std::cout << guess << " was a good guess" << std::endl;
}
else
{
std::cout << guess << " was a good guess, but you already guessed it once" << std::endl;
}
}
else if(hasAlreadyGuessed(guessList, guess))
{
std::cout << "You've already guessed " << guess << std::endl;
}
else
{
// this was a new bad guess
guessList.push_back(guess);
numBadGusses++; // Note that this isn't technicly needed and could use size of vector
std::cout << guess << " was a bad guess" << std::endl;
}
}
if(letersLeft.size() == 0U)
{
std::cout<<"You Win"<<std::endl;
}
else
{
std::cout<<"You Lose"<<std::endl;
}
std::cout << "The word was "<< word << std::endl;
return 0;
}
bool removeGuessFromWord(std::string& word, const char guess)
{
return word.erase(std::remove(word.begin(), word.end(), guess), word.end()) != word.end() ? true : false;
}
bool isGuessInWord(const std::string& word, const char guess)
{
return word.find(guess) != std::string::npos ? true: false;
}
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess)
{
return std::find(gussList.begin(), gussList.end(), guess) != gussList.end() ? true: false;
}

Writing value to c style string in struct

For the life of me I can't figure out why the I can't write to a c style string inside of a struct.
College student - can't use string class, haven't learned pointers.
Help? 2 hours at trying to figure this out.
#include <iostream>
using namespace std;
void strCopy(char from[], char to[])
{
for (int i = 0; i < 255; i++)
{
to[i] = from[i];
}
}
struct card
{
char suit[20];
char rank[20];
int cvalue;
char location[20];
};
void printCard(card card)
{
cout << card.rank << " of " << card.suit << endl;
}
int main()
{
// I don't think strCopy()'s the problem, I've used it with my last project.
cout << "Test strCopy()" << endl;
char str1[14] = "abcdefghijklm";
char str2[14];
strCopy(str1, str2);
cout << " " << str2 << endl << endl;
// Now the negative.
card one;
one.cvalue = 2;
strCopy("Somewhere", one.location);
strCopy("Two", one.rank);
strCopy("Hearts", one.suit);
printCard(one);
}
// I don't think strCopy()'s the problem, I've used it with my last
project.
Wrong
for (int i = 0; i < 255; i++)
{
to[i] = from[i];
}
copies 255 characters, however that's not what you meant.
If here :
strCopy(str1, str2);
cout << " " << str2 << endl << endl;
Your're getting "correct" output, then you're just unlucky, since that invokes an undefined behavior, an you're writing off the end of the array.

Three questions regarding command line arguments / char*

My post is organized in three sections:
1. My code
2. Example input and output
3. My three questions
MY CODE:
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <string>
#include <cstring>
using namespace std;
void deleteTrash(char*, char*);
const int kStr = 2;
const int kStrLen = 3;
int main(int argc, char* argv[])
{
if (argc < 4) {
cout << "Incorrect argument given." << endl;
cout << "Try again." << endl;
return 0;
}
cout << "PRINT argv[2]" << endl;
cout << "-----" << endl;
for (int i = 0; i < sizeof(argv[2]); i++) {
cout << "Iterator: " << i << endl;
cout << argv[2][i] << endl;
}
char* inputString;
deleteTrash(argv[kStr], inputString);
cout << "PRINT inputString" << endl;
cout << "-----" << endl;
for (int i = 0; i < sizeof(inputString); i++) {
cout << i << endl;
cout << inputString[i] << endl;
}
int strLen;
stringstream num;
num << argv[kStrLen];
num >> strLen;
if ( num.fail() ) {
cout << "Incorrect argument given." << endl;
cout << "Try again." << endl;
return 0;
}
if ( strLen < sizeof(inputString) ) {
cout << "Incorrect argument given." << endl;
cout << "Try again." << endl;
return 0;
}
return 0;
}
void deleteTrash(char* tempString, char* inputString)
{
int tempStringLen = sizeof(tempString);
int newSize = 0;
while (tempString[newSize] != '\0')
newSize++;
char newString[newSize + 1];
int iterator = 0;
while (tempString[iterator] != '\0') {
newString[iterator] = tempString[iterator];
iterator++;
}
newString[newSize] = '\0';
cout << "PRINT newString" << endl;
cout << "-----" << endl;
for (int i = 0; i < sizeof(newString); i++) {
cout << newString[i] << endl;
}
inputString = newString;
cout << "PRINT inputString" << endl;
cout << "-----" << endl;
for (int i = 0; i < sizeof(inputString); i++) {
cout << "Iterator: " << i << endl;
cout << inputString[i] << endl;
}
return;
}
EXAMPLE INPUT:
./hw1q5 4 W# 3
OUTPUT:
PRINT argv[2]
-----
Iterator: 0
W
Iterator: 1
#
Iterator: 2
Iterator: 3
3
Iterator: 4
Iterator: 5
T
Iterator: 6
E
Iterator: 7
R
PRINT newString
-----
W
#
PRINT inputString
-----
Iterator: 0
W
Iterator: 1
#
Iterator: 2
Iterator: 3
Iterator: 4
Iterator: 5
Iterator: 6
Iterator: 7
PRINT inputString
-----
0
Segmentation fault: 11
MY QUESTIONS:
Why does argv contain more than 3 elements (M, #, and \0). It prints out 8 elements (print statement iterates 0 - 7), which, after W, #, \0, are garbage. Should it not be printing only the 3 elements (M, #, and \0). Why is this happening? How may I fix it?
Why is it that when I set newString (type char) to inputString (type char*), by doing inputString = newString, inputString iterates 8 time in the print statement, printing blanks after printing M, #, and \0.
Why is the seg fault happening in the third statement?
sizeof() does not return the length of a null-terminated character array string. Instead you need something like strlen().
Let's just take one of the problems here:
// Wrong!
int main(int argc, char* argv[])
...
for (int i = 0; i < sizeof(argv[2]); i++) {
cout << "Iterator: " << i << endl;
cout << argv[2][i] << endl;
}
// Better
int main(int argc, char* argv[])
...
for (int i = 0; i < argc; i++) {
cout << "argv[" << i << "]: " << argv[i] << endl;
}
argv[] is an array of one or more "C" strings.
argc tells you how many strings are in the array.
You want to iterate through the strings in the array (argv[i]), not the characters in the string (for example, "argv[0][0]").
... AND ...
"sizeof(argv)" just gives you the size of a pointer (4 bytes, for a 32-bit CPU). It does NOT give you the #/elements in the array. That's what "argc" is for.
In answer to your first question, I'm going to refer you to another SO article: What does int argc, char *argv[] mean?
The first command line argument is always the command itself. So in your example:
./hw1q5 4 W# 3
There are four command line arguments: hw1q5, 4, W#, and 3.
In regards to your other questions, and the remainder of the first question, the majority of your problems stem from the assumption that sizeof(char*) returns the length of a null terminated string, which it does not (as has been pointed out both in comments and an earlier answer).
A good reference for understanding sizeof can be found here: http://en.cppreference.com/w/cpp/language/sizeof, or as I suspect this is a homework assignment based on your compiled program name, your C++ textbook.

How to search for a string from a text file

Firstly here is my code I have so far:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int arraysize = 35;
int i = 0;
string line;
string searchTerm;
int main()
{
string words[arraysize];
ifstream wordFile;
wordFile.open ("wordFile.txt");
if (wordFile.is_open())
{
while (! wordFile.eof())
{
getline (wordFile, line);
words[i] = line;
i++;
}
wordFile.close();
}
else
{
cout << "Unable to open file" << endl;
}
for (int x = 0; x < arraysize; x++)
{
cout << words[x] << " ";
}
cout << "\n\nEnter in a word you would like to search in the story above:" << endl;
cin >> searchTerm;
for (int y = 0; y < arraysize; y++)
{
if (words[y].compare(searchTerm) !=0)
{
cout << "No match found" << endl;
}
}
}
What I have so far is the program reading from a textfile and then printing those words. What I wanna do next is let the user enter in a word that they would like to search in the textfile, if there is a word like the one they entered print that word if there isn't print out "There isn't a word like that in the textfile"
I just cant get the searching figured out, any suggestions on how to do this?
Here is an example of how you would search for strings within strings
// string::find
#include <iostream> // std::cout
#include <string> // std::string
int main ()
{
std::string str ("There are two needles in this haystack with needles.");
std::string str2 ("needle");
// different member versions of find in the same order as above:
std::size_t found = str.find(str2);
if (found!=std::string::npos)
std::cout << "first 'needle' found at: " << found << '\n';
found=str.find("needles are small",found+1,6);
if (found!=std::string::npos)
std::cout << "second 'needle' found at: " << found << '\n';
found=str.find("haystack");
if (found!=std::string::npos)
std::cout << "'haystack' also found at: " << found << '\n';
found=str.find('.');
if (found!=std::string::npos)
std::cout << "Period found at: " << found << '\n';
// let's replace the first needle:
str.replace(str.find(str2),str2.length(),"preposition");
std::cout << str << '\n';
return 0;
}
This should help you figure out exactly what you need to do
Notice how parameter pos is used to search for a second instance of the same search string. Output:
first 'needle' found at: 14
second 'needle' found at: 44
'haystack' also found at: 30
Period found at: 51
There are two prepositions in this haystack with needles.
How about:
int found = -1;
for (int y = 0; y < arraysize; y++)
{
if (words[y].compare(searchTerm) ==0)
{
found = y;
break;
}
}
if ( found != -1 )
cout << "found!" << endl;
else
cout << "No match found" << endl;
or shorter:
if ( std::find(std::begin(words), std::end(words), searchTerm) == std::end(words) )
cout << "not found";
else
cout << "found";