For-loop with strings not working - c++

Here is the instructions:
Write a program that reads in a text file one word at a time. Store a word into a dynamically created array when it is first encountered. Create a paralle integer array to hold a count of the number of times that each particular word appears in the text file. If the word appears in the text file multiple times, do not add it into your dynamic array, but make sure to increment the corresponding word frequency counter in the parallel integer array. Remove any trailing punctuation from all words before doing any comparisons.
Create and use the following text file containing a quote from Bill Cosby to test your program.
I don't know the key to success, but the key to failure is trying to please everybody.
At the end of your program, generate a report that prints the contents of your two arrays
Here is my Code:
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cctype>
using namespace std;
int main()
{
ifstream inputFile;
int numWords;
string filename;
string *readInArray = 0;
char testArray[300] = {0};
char *realArray = 0;
const char *s1 = 0;
string word;
int j =1;
int k = 0;
int start =0;
int ending = 0;
char wordHolder[20] = {0};
cout << "Enter the number of words the file contains: ";
cin >> numWords;
readInArray = new string[(2*numWords)-1];
cout << "Enter the filename you wish to read in: ";
cin >> filename;
inputFile.open(filename.c_str());
if (inputFile)
{
cout << "\nHere is the text from the file:\n\n";
for (int i=0; i <= ((2*numWords) -1); i +=2)
{
inputFile >> readInArray[i]; // Store word from file to string array
cout << readInArray[i];
strcat(testArray, readInArray[i].c_str()); // Copy c-string conversion of word
// just read in to c-string
readInArray[j] = " ";
cout << readInArray[j];
strcat(testArray, readInArray[j].c_str()); // This part is for adding spaces in arrays
++j;
}
inputFile.close();
}
else
{
cout << "Could not open file, ending program";
return 0;
}
realArray = new char[strlen(testArray)];
cout << "\n\n";
for(int i=0; i < strlen(testArray); ++i)
{
if (isalpha(testArray[i]) || isspace(testArray[i])) // Is makes another char array equal to
{ // the first one but without any
realArray[k]=testArray[i]; // Punctuation
cout << realArray[k] ;
k++;
}
}
cout << "\n\n";
for (int i=0; i < ((2*numWords) -1); i+=2)
{
while (isalpha(realArray[ending])) // Finds space in char array to stop
{
++ending;
}
cout << "ending: " << ending << " ";
for ( ; start < ending; ++start) // saves the array up to stopping point
{ // into a holder c-string
wordHolder[start] = realArray[start];
}
cout << "start: " << start << " ";
readInArray[i] = string(wordHolder); // Converts holder c-string to string and
cout << readInArray[i] << endl; // assigns to element in original string array
start = ending; // Starts reading where left off
++ending; // Increments ending counter
}
return 0;
}
Output:
Enter the number of words the file contains: 17
Enter the filename you wish to read in: D:/Documents/input.txt
Here is the text from the file:
I don't know the key to sucess, but the key to failure is trying to please everybody.
I dont know the key to sucess but the key to failure is trying to please everybody
ending: 1 start: 1 I
ending: 6 start: 6 I dont
ending: 11 start: 11 I dont know
ending: 15 start: 15 I dont know the
ending: 19 start: 19 I dont know the key
ending: 22 start: 22 I dont know the key to>
ending: 29 start: 29 I dont know the key to sucess
ending: 33 start: 33 I dont know the key to sucess but↕>
My Question:
Something is wrong with the last for-loop, it crashes after I run it. I included the ending and starting variables to maybe help see whats going on. I know there are better ways of doing this problem but the instructor wants it done this way. If you know where I went wrong with the last for-loop any help would be very much appreciated!!

You aren't null-terminating your strings as you go along. You copy the characters correctly, but without null terminators, your loops might go off into the weeds.

Related

converting a random line from a text file into numbers and then outputting the numbers, with the user having to guess the original line

I'm creating a piece of code which is supposed to simulate a guessing game in which I pull a random line from a text file, in this example "premier league football teams", then I have to take the random line and have it convert into the corresponding numbers in the alphabet, so in the example of "arsenal" I would have to output "1 18 19 5 14 1 12". as this is a game the user has to guess that the numbers mean "arsenal" and then type that in to gain a point and continue. so far I have been able to code a method of pulling a random line from the file, however I am unsure how I would be able to then convert that code into numbers without outputting the answer, as this is meant to be a guessing game.
this is the relevant section of text, but to keep this short I will not paste the full code
vector<string> lines;
srand(time(NULL));
//ensures random selection on each new code run
ifstream file("Premier_League_Teams.txt");
//pulls the file from the directory
int total_lines = 0;
while (getline(file, line))
//this function counts the number of lines in a text file
{
total_lines++;
lines.push_back(line);
}
int random_number = rand() % total_lines;
//selects a random entry from the text file
//end of adapted code
cout << lines[random_number];
I am assuming that I will have to do a switch statement, but I do not know how to apply that case statement to the randomly selected line, and then have the user input the plain english text
NEW CODE WITH HELP FROM COMMENTS
#include <fstream>
//fstream included to pull answers from category files
#include <string>
#include <vector>
#include <list>
#include <time.h>
#include <stdlib.h>
using namespace std;
int main()
{
cout << "Richard Osman's house of Games: This round is in code.\n\n\n";
cout << "The objective of this round is to unscramble the coded word, you will be given the category as the clue and you have to type out what you belive the answer to be, with a capital letter\n\n";
cout << endl;
string Name;
cout << "But First, Enter your first name.\n";
cin >> Name;
cout << "Welcome contestant " << Name << " Are you ready to begin the quiz?\n";
// this is to add a level of immersion to the game, by allowing the code to recall the players name so that they have a personalised experience
string respond;
cout << "please type Yes or No (case sensitive).\n";
cin >> respond;
if (respond == "Yes")
{
cout << "\nGood luck!";
}
else
{
cout << "Maybe next time!";
return 0;
}
{ cout << "The first category is..." << endl;
cout << "Premier League Football Teams!" << endl;
//code adapted from Ranjeet V, codespeedy
string line;
vector<string> lines;
srand(time(NULL));
//ensures random selection on each new code run
ifstream file("Premier_League_Teams.txt");
//pulls the file from the directory
int total_lines = 0;
while (getline(file, line))
//this function counts the number of lines in a text file
{
total_lines++;
lines.push_back(line);
}
int random_number = rand() % total_lines;
//selects a random entry from the text file
//end of adapted code
int random_number = 0;
vector<string> lines;
lines.push_back("abc arsenal");
string alpha = "abcdefghijklmnopqrstuvwxyz";
string word = lines[random_number];
//line from lines vector for which we will calculate numbers
int* codes;
codes = new int[word.length()];
//array in which we will store codes for letters
for (int i = 0; i < word.length(); i++) {
//iterate over each characte of string word
if (word[i] != ' ')
//as we dont want to replace spaces with numbers or somethings, but it will automatically become 0 as it is default
codes[i] = alpha.find(word[i]) + 1;
//assign codes correspoding element to (index of char)+1
}
for (int i = 0; i < word.length(); i++) {
if (codes[i] == 0) {
continue;
//do not print codes' element if it is zero because it will become zero for spaces
}
cout << codes[i] << " ";
//outputting each codes element with a space in between
}
You can declare a string like
std::string alphabet="abcdefghijklmnopqrstuvwxyz"; and then for particular character if you want to find the equivalent position number you can use str.find(char); to get index of char in str and then add one to get its position number.
For eg;
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
int random_number=0;
vector<string> lines;
lines.push_back("abc arsenal");
string alpha="abcdefghijklmnopqrstuvwxyz";
string word=lines[random_number]; //line from lines vector for which we will calculate numbers
int* codes;
codes=new int[word.length()]; //array in which we will store codes for letters
for(int i=0;i<word.length();i++) { //iterate over each characte of string word
if(word[i]!=' ') //as we dont want to replace spaces with numbers or somethings, but it will automatically become 0 as it is default
codes[i]=alpha.find(word[i])+1; //assign codes correspoding element to (index of char)+1
}
for(int i=0;i<word.length();i++) {
if(codes[i]==0) {
continue; //do not print codes' element if it is zero because it will become zero for spaces
}
cout<<codes[i]<<" "; //outputting each codes element with a space in between
}
}
[Note] : Just for example I have assigned random_number to 0 and made a sample vector lines so that you can have more clarity on how to use this method in your case.
the char datatype have a numerical value and are displayed as a character. We make use of this!
Lowercase a = 97, lowercase b = 98, etc. So if you subtract 96 and then cast it to an interger using (int), you will be all set :)

How to convert the char to string and print out from a string to main function

I am a beginner!
I had to write a code which is similar to caesar cipher, I had a main.cpp which is written below and i wrote my code in a separate ConvertString.cpp also written below.
I am having trouble printing my output from the ConvertString.cpp with the
main.cpp. Can anyone please point out my mistake. Appreciate your help a lot!
The following is the main.cpp:
#include <iostream>
#include <string>
using namespace std;
string ConvertString (string, int);
int main () {
// define the modification intger variable and
//the new modification variable to recover the text
int mod_int, recover_int;
// declare the input string , mod_string, recovered string
string input_string, mod_string, recovered_string;
// top level loop to perform modification
while (1) {
cout << "Please enter modification key (or -1 to exit)" << endl;
// read in the mod_int from user
cin >> mod_int;
// if the user is done (mod_int == -1), then exit
if (mod_int == -1) break;
// read in the text to be modified
cout << "Please enter text to be modified" << endl;
cin >> input_string;
// modify the input text
mod_string = [ConvertString(input_string, mod_int)][1];
// print out the modified text
cout << endl << "The modified text is " << endl << mod_string << endl;
// calculate a new recover_int value to recover original text
// from the modified text -- used for testing only
recover_int = 26 - (mod_int%26);
// recover original text by calling ModifyString with new recover_int value
recovered_string = ConvertString(mod_string, recover_int);
// print out the recovered text -- should match original
cout << endl << "The recovered text is " << endl << recovered_string << endl << endl;
} // end while loop
} // end main function
enter code here
The following is the ConvertString.cpp
string ConvertString (string input_string, int mod_int)
{
// your programming code
int x; //integer x is declared
x= input_string.length();
for(int index=0; index < x ; index++)
{
if(isalpha(input_string[index])) //checks the string for alphabet
{
int start = 65; //if alphabets is present in the string, it is assumed as upper case characters
//starting point is taken as character 'A' with ASCII value of 65
if(islower(input_string[index])) //if lower case character is present in string
start=97; //start is taken as 'a' with ASCII value of 97
ConvertString(input_string, mod_int)=(((int)input_string[index]- start + mod_int)% 26) + start;
//input_string is converted to integer and then modified by the formula
//formula for characters in the string to cycle in the range from a-z and A-Z.
} //closing parenthesis for if
else
cout <<input_string[index]; // if character is not a-z or A-Z, print it without any modification
} //closing parenthesis belong to - for
return input_string; // return the converted string
} //end ConvertString
You forgot a return. Change:
ConvertString(input_string, mod_int)=(((int)input_string[index]- start + mod_int)% 26) + start;
to
return ConvertString(input_string, mod_int)=(((int)input_string[index]- start + mod_int)% 26) + start;
// ^^^ Missing

C++ Issue with cin and CTRL + Z

I'm reading c++ primer 5th and I have a little problem with an exercise:
Read a sequence of words from cin and store the values a vector. After
you’ve read all the words, process the vector and change each word to
uppercase. Print the transformed elements, eight words to a line.
My code is this:
#include <iostream>
#include <vector>
#include <string>
#include <cctype>
using std::vector;
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main(){
vector<string> words;
string wordBuffer;
vector<string> output(1);
while (cin >> wordBuffer){
words.push_back(wordBuffer);
}
for (string &word : words){
for (char &letter : word){
letter = toupper(letter);
}
}
unsigned currentLine = 0;
for (decltype(words.size())index = 0; index < words.size(); ++index){
output[currentLine] += words[index] + " ";
if ((index+1) % 8 == 0){
++currentLine;
output.push_back("");
}
}
for (string s : output){
s[s.size() - 1] = 0; //removing the whitespace
cout << s << endl;
}
system("pause");
return 0;
}
Now, everything works well, but i have an issue with the input of the words by console.
If I write
I am writing a random words ^Z
and press Enter nothing happens. I have to rewrite the ^Z after I have pressed the Enter, like here:
I am writing a random words
^Z
Can you expain me why? Thanks!
PS: I'm saying that because in my previous programs writing ^Z in the same line worked fine. Like in this code:
#include <iostream>;
int main(){
int currval = 0,val = 0;
int count = 1;
while (std::cin >> val){
if (currval == val){
++count;
}
else {
std::cout << "The number " << currval << " appears " << count << " times" << std::endl;
currval = val;
count = 1;
}
}
std::cout << "The number " << currval << " appears " << count << " times" << std::endl;
system("pause");
return 0;
}
I can't figure out why :(
The ^Z has to be first in order for Windows to treat it as Ctrl+Z, otherwise it is just treated as meaningless characters.
If you would like it to work like you wrote i'd suggest:
String wordBuffer("")
while (strcmp(wordBuffer[strlen(wordBuffer)-3], "^Z") != 0){
words.push_back(wordBuffer);
cin >> wordBuffer
}
EDIT: in your second example it works because when you read integers c++ knows to divide the given string of numbers in the space (or ENTER if the numbers are entered separately in every line) to read every number separately so if you'll enter:
123 2323 4545 43 ^Z
It will read 123, then 2323, ... and then ^Z and so it will be as though it got it in a separate line but when you read string, it cant do that because a string contain every symbol and so it separate the input in the ENTER pressed and that why the second one works
As far as I know Ctrl+Z is placed in the keyboard buffer before any other entered symbols. Thus any entered characters before Ctrl+Z will be discarded. You need to do the following
I am writing a random words ENTER
^Z ENTER

c++ for loop with decrement update causing infinite loop?

This is part of a greater code for reading an input file word-for-word, then printing the words in reverse order. It uses a string array called words[] to store, word-by-word, the char strings from an input file earlier in the program:
//print to screen
for (int i = MAXSIZE; i >= 0; i--)
{
cout << words[i] << " ";
}
Test input file contents:
This is my test file. I hope this works.
Output is just "works. " repeating on and on.
Why is the i-- apparently never happening?
EDIT: Everything from my code. I'm on a bit of a time crunch here, to say the least. MAXSIZE=1024 part of lab prompt. Can't use vectors or reverse; seen that all over, but it's off limits for this lab. New to programming, so if you could refrain from being condescending, that'd be great. Just trying to get this to work. The reading input.txt and print to screen bit works fine. Output portion is utter fail and I don't know why. Can someone just tell me why instead of insulting me, thanks?
//Kristen Korz
//CIS 22A
//This program reads an input file and writes the words in reverse order to an output file.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
//create and link input...
ifstream inputFile;
inputFile.open("input.txt");
//...and output files
ofstream outputFile;
outputFile.open("output.txt");
//error message for file open fail
if (inputFile.fail())
cout << "Error opening the file.\n";
//constant for max size
const int MAXSIZE = 1024;
//string array and temporary-use string
string words[MAXSIZE];
string str; //note: variables will be used for output loops too
//read words from input file
for (int i = 0; (inputFile >> str) && (i < MAXSIZE); ++i)
{
words[i] = str;
//for showing in terminal if read correctly
cout << words[i] << " ";
}
inputFile.close();
cout << endl;
//something wrong with for loop resulting in i apparently not updating
for (int i = MAXSIZE; (outputFile << str) && (i >= 0); --i)
{
words[i] = str;
//for showing in terminal if written correctly
cout << words[i] << " ";
}
outputFile.close();
cout << endl;
system("pause");
return 0;
}
For output with i also printed, my cout statements in the for-loops say:
cout << words[i] << " " << i << " ";
Giving terminal output:
This 0 is 1 my 2 test 3 file. 4 I 5 hope 6 this 7 works. 8
works. 1023 works. 1022 works. 1021 (lots of repeats of works. followed by decrementing numbers) works. 3 works. 2 works. 1 works. 0
Your output loop does:
words[i] = str;
for every iteration. str still holds the value of the last string you input, so this sets every member of words to be the same string. Since your last input string was "works", this explains why you output "works" every time.
It should work better if you just remove that line. Also, start from MAXSIZE - 1. The valid indices of the array are 0 through MAXSIZE-1. Your out-of-bounds access causes undefined behaviour, although apparently in this instance it had no effect.
However if your input only has 8 words as you suggest, then outputting 1024 words will give you a lot of blank space. Consider starting the output from where i got up to, instead of MAXSIZE - 1.
At the part marked as not working (the second for loop), str is being read from but it is never changed to anything else in that loop, so it repeats the last word. i is being updated, the problem is that str is not being updated.
The other issue is that you are trying to access an element past the end of the array, as WhozCraig and Velthune discussed in their answers. You need to properly figure out what you want to do with words in your second for loop. This is key. Also, you need to store where the array you read in ends.
Viewing WhozCraig's link, if you have:
const int MAXSIZE = 1024;
string words[MAXSIZE];
for (int i = MAXSIZE; i >= 0; i--) {
cout << words[i] << " ";
}
You have a string that from 0..1023.
Accessing words[1024] is potentially dangerous.
For iterate correctly your string do:
for (int i = MAXSIZE - 1; i >= 0; --i) {
cout << words[i] << " ";
}
By the way, when you fill words, add a control:
for (int i = 0; (inputFile >> str) && (i < MAXSIZE); ++i)) {
if(str.size() <= MAXSIZE) {
words[i] = str;
}
}
update
Be sure that your string in file:
"This is my test file. I hope this works. "
doesn't end with a space. To be sure, test adding "EOF" to your string:
"This is my test file. I hope this works.EOF"
Other, do your loop in this way:
int i = 0;
while(inputFile.good() && i < MAXSIZE) {
std::string word << inputFile;
if(!word.empty())
words[i] = str;
//for showing in terminal if read correctly
cout << words[i] << " ";
}
The problem why you get a lot of "works" here is:
After this piece of codes:
//read words from input file
for (int i = 0; (inputFile >> str) && (i < MAXSIZE); ++i)
{
words[i] = str;
//for showing in terminal if read correctly
cout << words[i] << " ";
}
inputFile.close();
cout << endl;
//str = "works";
The values of variable str is works.
After that, you set every elements in words by str. So every elements in the words now are the same value works.
for (int i = MAXSIZE; (outputFile << str) && (i >= 0); --i)
{
words[i] = str;//=="works"
//for showing in terminal if written correctly
cout << words[i] << " ";
}
outputFile.close();
cout << endl;

How to search array of strings in C++

I want to be able to search an array of strings in C++. I have this data:
"Foo Becky, 924-334-2514",
"Becky Warren, 555-1223",
"Geri Palmer, 555-8787",
"Ron Palmer, 555-2783"
If the user types Bec, the program finds the name Foo Becky, 924-234-2314. If the user types Palmer, then the program should show Geri Palmer, 555-8787 and Ron Palmer, 555-2783
Here is what I have so far:
#include <iostream>
#include <string>
using namespace std;
int main(){
int n;
string search;
while(1){
cout << "How many data you want to input: "<< endl;
cin >> n;
cin.ignore(1000, 10);
if(n > 0 && n < 20){
break;
}
cout << "Number of data can not be negative or more than 20. "<< endl;
}
string* data = new string[n];
for(int i=0; i< n; i++){
cout << "Enter [First Name] [Last Name], [Phone-Number] and then hit "
<< "enter." << endl << "e.g: Foo Becky, 925-245-413"<< endl;
getline(cin,data[i]);
cout << endl;
}
cout << "Enter what you want to search for: "<< endl;
getline(cin, search);
for(int i =0; i< n; i++){
if(search == data[i]){
cout << data[i]<< endl;
}
}
delete [] data;
return 0;
}
How do I search an array of strings in C++?
You have to use the find method of std::string. This function return the start postion of string searched for in the string searched in. If no match was found it returns npos witch is actually just -1.
if(data[i].find(search, 0) != std::string::npos);
{
cout << data[i]<< endl;
}
You should use find, as A4L already mentioned. I just want to add that your use of cin.ignore will not work well if bad value entered. you need
cin.clear()
also. see this link for more details.
How to search an array of strings example in C++:
This is the brute force search method. Brute force means means we step through the entire string array and at each index of the array we search for our matching string.
#include<iostream>
#include<string>
using namespace std;
int main(){
//Create a structure to hold the data:
string data[] = {"pidgeon", "abcd", "1234", "%^*#"};
//Get the length of the array.
int size = 4;
//loop through all the items and print them if they match
string matchString = "bc";
for(int x = 0; x < size; x++){
if (data[x].find(matchString, 0) != std::string::npos){
cout << data[x] << endl;
}
}
}
Above code prints:
abcd
You should be verbalizing the above code from top to bottom in your head like this:
An array of string called data is initialized to contain 4 elements and given four values pidgeon, abcd, 1234 and %^&#. An int variable called size is created which represents the number of elements in the string array. A string variable called matchString is created which contains the string 'bc'.
The for loop index starts at position zero and increments by 1 until it reaches one less than the size of the array. So the for loop goes through: 0, 1, 2, 3. The first value of x is 0. The if statement resolves data[0] to be pidgeon. The find method is applied against that string and two parameters are passed in. The string to be matched, and the position of the first character in the string to be considered in the search (0).
if 'bc' exists within 'pidgeon' then it will return the position of the first character of the first match, otherwise it will print std::string:npos which is the maximum value for size_t designating not found.
bc does not exist in pidgeon so it skips the interior of the for loop. The for loop continues to index position 1. bc is contained in abcd. So that string is printed. When all the items are searched, the for loop ends and the program completes.