How to store variables in a string array in c++ - c++

I am quite in to C++ and have a recent homework assignment which I need to store 1000 most common words into a string array. I was wondering how would I go about this. Here is my example code so far,
if(infile.good() && outfile.good())
{
//save 1000 common words to a string
for (int i=0; i<1000; i++)
{
totalWordsIn1000MostCommon++;
break;
}
while (infile.good())
{
string commonWords[1000];
infile >> commonWords;
}
}
Thanks!

#include <cstdio>
#include <string>
freopen(inputfileName,"r",stdin);
const int words = 1000;
string myArr[words];
for(int i=0;i<words;i++){
string line;
getline(cin,line);
myArr[i] = line;
}

The for loop above does nothing at the beginning, just breaks at first iteration. It would be better if you'll read how to use loops in C++. Also take a look at the scopes of the variables in C++. In your case commonWords declared in while loop, so will be created each time and destroyed after each loop iteration.
What you want is something like this:
int i = 0;
std::string commonWords[1000];
while (i < 1000 && infile.good()) {
infile >> commonWords[i];
++i;
}
I'm living the remaining part for you to complete your homework.

Related

2d array comparing with char

I have an array that reads data from a file, the data is binary digits such as 010011001001 and many others so the data are strings which I read in to my 2d array but I am stuck on comparing each value of the array to 0. Any help would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string myArr[5000][12];
int i = 0, zeroCount = 0, oneCount = 0;
ifstream inFile;
inFile.open("Day3.txt");
while(!inFile.eof())
{
for(int i = 0; i < 5000; i++)
{
for(int j = 0; j < 12; j++)
{
inFile >> myArr[i][j];
j++;
}
i++;
}
}
for(int j = 0; j < 12; j++)
{
for(int i = 0; i < 5000; i++)
{
if(myArr[i][j].compare("0") == 0)
{
zeroCount++;
}
else
{
oneCount++;
}
i++;
}
if(zeroCount > oneCount)
{
cout << "Gamma is zero for column " << i << endl;
}
else
{
cout << "Gamma is One for column " << i << endl;
}
j++;
}
}
some input from the text file:
010110011101
101100111000
100100000011
111000010001
001100010011
010000111100
Thank you for editing you question and providing more information. Now, we can help you. You have 2 major misunderstandings.
How does a for loop work?
What is a std::string in C++
Let us start with the for loop. You find an explanation in the CPP reference here. Or, you could look also at the tutorial shown here.
The for loop has basically 3 parts: for (part1; part2; part3). All are optional, you can use them, but no need to use them.
part1 is the init-statement. Here you can declare/define/initialize a variable. In your case it is int i = 0. You define a variable of data type int and initialize it with a value of 0
part2 is the condition. The loop will run, until the condition becomes false. The condition will be check at the beginning of the loop.
part3 is the so called iteration-expression. The term is a little bit misguiding. It is basically a statement that is executed at the end of the loop, before the next loop run will be executed and before the condition is checked again.
In Pseudo code it is something like this:
{
init-statement
while ( condition ) {
statement
iteration-expression ;
}
}
which means for the part of your code for(int j = 0; j < 12; j++)
{
int j = 0; // init-statement
while ( j < 12 ) { // while ( condition ) {
inFile >> myArr[i][j]; // Your loop statements
j++; // Your loop statements PROBLEM
j++; // iteration-expression from the for loop
}
}
And now you see the problem. You unfortunately increment 'j' twice. You do not need to do that. The last part3 of the for loop does this for you already.
So please delete the duplicated increment statements.
Next, the std::string
A string is, as its names says, a string of characters, or in the context of programming languages, an array of characters.
In C we used to write actually char[42] = "abc";. So using really a array of characters. The problem was always the fixed length of such a string. Here for example 42. In such an array you could store only 41 characters. If the string would be longer, then it could not work.
The inventors of C++ solved this problem. They created a dynamic character array, an array that can grow, if needed. They called this thing std::string. It does not have a predefined length. It will grow as needed.
Therefore, writing string myArr[5000][12]; shows that you did not fully understand this concept. You do not need [12], becuase the string can hold the 12 characters already. So, you can delete it. They characters will implicitely be there. And if you write inFile >> myString then the extractor operator >> will read characters from the stream until the next space and then store it in your myString variable, regardless how long the string is.
Please read this tutorial about strings.
That is a big advantage over the C-Style strings.
Then your code could look like:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main()
{
string myArr[5000];
int zeroCount = 0, oneCount = 0;
ifstream inFile;
inFile.open("Day3.txt");
while (!inFile.eof())
{
for (int i = 0; i < 5000; i++)
{
inFile >> myArr[i];
}
}
for (int i = 0; i < 5000; i++)
{
zeroCount = 0; oneCount = 0;
for (int j = 0; j < 12; j++)
{
if (myArr[i][j]== '0')
{
zeroCount++;
}
else
{
oneCount++;
}
}
if (zeroCount > oneCount)
{
cout << "Gamma is zero for column " << i << endl;
}
else
{
cout << "Gamma is One for column " << i << endl;
}
}
}
But there is more. You use the magic number 5000 for your array of strings. This you do, because you think that 5000 is always big enough to hold all strings. But what, if not? If you have more than 5000 strings in your source file, then your code will crash.
Similar to the string problem for character arrays, we have also a array for any kind of data in C++, that can dynamically grow as needed. It is called std::vector and you can read about it here. A tutorial can be found here.
With that you can get rid of any C-Style array at all. But please continue to study the language C++ further and you will understand more and more.
Ther are more subtle problems in your code like while(!inFile.eof()), but this should be solved later.
I hope I could help

Number of substrings starting and ending with '1' [duplicate]

This question already has answers here:
Getline keeps on getting newline character. How can I avoid this?
(7 answers)
Closed 2 years ago.
I'm trying to find the number of substrings that start and end with '1' where input string are numbers like 1111, 10001 etc. Given code does not show correct output but if I replace getline with cin as the input method the code works fine. It also works if I skip input of n (n is the length of the string to be entered) and use i<str.length() in for loop. Why does this happen?
#include <iostream>
#include <string>
using namespace std;
int main(){
int n;
cin>>n;
string str;
getline(cin,str);
int c=0;
for(int i=0;i<n;i++)
if(str[i]=='1')
c++;
c=c*(c+1)/2;
cout<<c;
return 0;
}
This is because getline reads all characters after n until the end of the line including spaces. So the length of your str will be equal to n+1 because of the space in the beginning.
How to fix (for example): for(int i = 1; i < n + 1; i++)
Possible issues with the shared code are:
Collecting input in variable ‘n’ first and then assigning it to a string variable via getline() seems redundant. The expected work can be done with the usage of single getline() statement : “getline(cin,str);”
The usage of variable ‘n’ in the for loop: the variable ‘n’ is to get the length of the input string (so that the loop can compare all elements of the string with number ‘1’. as per the shared code you are trying to execute the for loop for ‘n’ numbers of time which I believe is not the expectation here.)
e.g: if the string input is “111”, then the loop will get executed for 111 times where it should run for 3 times (please correct if my understanding of the motive of the code is different here 😊)
Present loop condition check will surely give the “string subscript out of range” assertion failure.
int n;
cin >> n;
string str;
getline(cin, str);
int c = 0;
for (int i = 0; i < n; i++)
{ }
As per my understating , above code lines can be replaced by below chunk of code.
string str;
getline(cin, str);
int c = 0;
int n = str.size();
for (int i = 0; i < n; i++)
{}

2d array displaying unwanted characters

I have a problem with displaying the contents of a 2d array, I have searched on here for solutions but as I'm not entirely sure what my problem is, I'm not sure I'm asking the right question.
I am writing a program that lets the user open a .txt file which will always contain 30 by 30 characters all separated by a comma and the first line and row will be 0,1,2,3,,,9,0,1,2,3,,,9 and the end of each line will be a new line. The programme should display the contents of the .txt file on the screen without the commas then go on to allow the user to search the location of characters in the file.
I thought the best way to do this would be to use the getline function with a delimiter to populate a 2d array, this seems to have worked except when I display the content of the array, the last character is repeated and I'm not sure if it's due to the way I am populating the array or the way in which I am displaying the array.
while(!inputFile.eof())
{
for (int i = 0; i < SIZE; ++i) // SIZE is defined 30
{
for (int j = 0; j < SIZE; ++j)
{
getline(inputFile, line,',');
aArray[i][j] = line; // aArray and line are declared as strings
std::cout << aArray[i][j];
}
}
cout << endl;
}
This is my input:
0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9
1,*,!,8,0,;,*,a,b,0,8,0,.,y,Z,c,4,4,8,8,8,8,y,y,y,4,–,6,8,!
2,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,0,0,0,5,5,J,J,J,J,J,J,J,J,j
3,9,8,7,0,8,0,8,0,A,c,4,4,*,F,F,6,F,K,J,H,G,5,s,H,U,P,2,2,0
4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
5,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
6,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,Y,Y,Y,0,0,0,0,0,0,0
7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
9,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,Y,Y,Y,0,0,0,0,0,0,0
0,0,1,1,2,2,D,D,5,5,$,£,!,a,A,a,A,a,A,a,A,a,A,a,A,a,A,a,A,8
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
2,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
3,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,Y,Y,Y,0,0,0,0,0,0,0
4,0,1,1,2,2,D,D,5,5,$,£,!,a,A,a,A,a,A,a,A,a,A,a,A,a,A,a,A,8
5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
6,0,8,0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
7,P,0,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,Y,Y,Y,0,0,0,0,0,0,0
8,0,1,1,2,2,D,D,5,5,$,£,!,a,A,a,A,a,A,a,A,a,A,a,A,a,A,a,A,8
9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
1,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,Y,Y,Y,0,0,0,0,0,0,0
2,0,1,1,2,2,D,D,5,5,$,£,!,a,A,a,A,a,A,a,A,a,A,a,A,a,A,a,A,8
3,0,1,1,2,2,D,D,5,5,$,£,!,a,A,a,A,a,A,a,A,a,A,a,A,a,A,a,A,8
4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
5,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
6,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,Y,Y,Y,0,0,0,0,0,0,0
7,0,1,1,2,2,D,D,5,5,$,£,!,a,A,a,A,a,A,a,A,a,A,a,A,a,A,a,0,8
8,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,P,Y,Y,Y,0,0,0,0,0,8,0
9,0,1,1,2,2,D,D,5,5,$,£,!,a,A,a,A,a,A,a,A,a,A,a,A,a,A,a,0,8
This is my output:
012345678901234567890123456789
1*!80;*ab080.yZc448888yyy4–68!
200000000001112200055JJJJJJJJj
398708080Ac44*FF6FKJHG5sHUP220
400000000000000000000000000000
588888888888888888888888888888
6PPPPPPPPPPPPPPPPPPPYYY0000000
700000000000000000000000000000
888888888888888888888888888888
9PPPPPPPPPPPPPPPPPPPYYY0000000
001122DD55$£!aAaAaAaAaAaAaAaA8
100000000000000000000000000000
288888888888888888888888888888
3PPPPPPPPPPPPPPPPPPPYYY0000000
401122DD55$£!aAaAaAaAaAaAaAaA8
500000000000000000000000000000
608088888888888888888888888888
7P0PPPPPPPPPPPPPPPPPYYY0000000
801122DD55$£!aAaAaAaAaAaAaAaA8
900000000000000000000000000000
088888888888888888888888888888
1PPPPPPPPPPPPPPPPPPPYYY0000000
201122DD55$£!aAaAaAaAaAaAaAaA8
301122DD55$£!aAaAaAaAaAaAaAaA8
400000000000000000000000000000
588888888888888888888888888888
6PPPPPPPPPPPPPPPPPPPYYY0000000
701122DD55$£!aAaAaAaAaAaAaAa08
8PPPPPPPPPPPPPPPPPPPYYY0000080
901122DD55$£!aAaAaAaAaAaAaAa0888888888888888888888888888888
As you can see the last character is repeated which is not what I want. I am new to C++ so I'm not sure if I'm even using the best method, I spent nearly 2 days trying to solve a problem I created by mistakingly putting cout << endl; within my for loop so I am reaching out to the fine members if stack overflow for some much needed guidance.
To expand on the comment by #WhozCraig, you shouldn't use iostream::eof inside the loop condition, since it won't return true until after the end of the file is read. Instead, something like this should suffice (note there are many ways to do this):
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#define SIZE 30
int main() {
std::string line;
std::string aArray[SIZE][SIZE];
std::ifstream inputFile("file2.txt");
for (int i = 0; getline(inputFile, line) && i < SIZE; ++i) {
std::istringstream lineStream(line);
std::string token;
for (int j = 0; getline(lineStream, token, ',') && j < SIZE; ++j) {
aArray[i][j] = token;
std::cout << aArray[i][j];
}
std::cout << std::endl;
}
}
Which will provide the desired output:
012345678901234567890123456789
1*!80;*ab080.yZc448888yyy4–68!
200000000001112200055JJJJJJJJj
398708080Ac44*FF6FKJHG5sHUP220
400000000000000000000000000000
588888888888888888888888888888
6PPPPPPPPPPPPPPPPPPPYYY0000000
700000000000000000000000000000
888888888888888888888888888888
9PPPPPPPPPPPPPPPPPPPYYY0000000
001122DD55$£!aAaAaAaAaAaAaAaA8
100000000000000000000000000000
288888888888888888888888888888
3PPPPPPPPPPPPPPPPPPPYYY0000000
401122DD55$£!aAaAaAaAaAaAaAaA8
500000000000000000000000000000
608088888888888888888888888888
7P0PPPPPPPPPPPPPPPPPYYY0000000
801122DD55$£!aAaAaAaAaAaAaAaA8
900000000000000000000000000000
088888888888888888888888888888
1PPPPPPPPPPPPPPPPPPPYYY0000000
201122DD55$£!aAaAaAaAaAaAaAaA8
301122DD55$£!aAaAaAaAaAaAaAaA8
400000000000000000000000000000
588888888888888888888888888888
6PPPPPPPPPPPPPPPPPPPYYY0000000
701122DD55$£!aAaAaAaAaAaAaAa08
8PPPPPPPPPPPPPPPPPPPYYY0000080
901122DD55$£!aAaAaAaAaAaAaAa08

independent things influence each other (I have no idea what is going on)

Sorry for the title, but I really have no idea what the problem is. The code looks like that (here it has no sense, but in the bigger project is has, so please, do not ask "why do you want to do....")
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
string sort (string slowo){
string litery = slowo;
for (int i=0; i<litery.length()-1; i++)
for (int j=0; j<litery.length()-1; j++)
if (litery[j]>litery[j+1])
swap(litery[j], litery[j+1]); // (3)
return litery;
}
int main()
{
fstream wordlist;
wordlist.open("wordlist_test",ios::in);
vector<string> words;
while (!wordlist.eof()){ // (4)
bool ok = true;
string word;
getline(wordlist,word);
string sorted = sort(word);
if (ok){
cout<<word<<endl; // (1)
words.push_back(word);
}
}
for (int i = 0; i<words.size(); i++){
cout<<words[i]<<endl; // (2)
}
}
There are for words in file "wordlist_tests". Program at the end should just write them to vector and write what's in vector into standard output. The problem is:
however line(1) proves that all words are ok
vector appears to be
empty in line (2)
now iteresting (probably just for me) part:
there are two ways to make it right:
I can just remove line(3) (however, if I am right, as the variable is passed to sort function through the value, it just swap two letters in independent variable; it has nothing to do with my vector), or:
I can change condition in while loop (4).
for example just like this:
int tmp = 0;
while (tmp < 5){
tmp++;
/..../
What is wrong with this code? What should I do write these words down to vector but still sort them and using this while loop? I cannot find the connection between this things (ok, I see that connection is variable word, but I do not know in what way). Any help appreciate.
What happens in swap() if one of the words is the empty sting ""?
If this happens, litery = "".
The condition in the loops will be to iterate from 0 to (unsigned) 0 - 1, which is a very large number.
You'll then execute if (litery[0] > litery[1])
litery[1] will access beyond the end of the empty string, which causes undefined behavior.
Let's fix this:
The common fix for this, is to iterate from 1 to string.length(). Here's an example:
string sort (string litery){
for (int i=1; i<litery.length(); i++)
for (int j=1; j<litery.length(); j++)
if (litery[j-1]>litery[j])
swap(litery[j-1], litery[j]);
return litery;
}

C++ Dynamic Array Inputs

I am using two dynamic arrays to read from a file. They are to keep track of each word and the amount of times it appears. If it has already appeared, I must keep track in one array and not add it into the other array since it already exists. However, I am getting blank spaces in my array when I meet a duplicate. I think its because my pointer continues to advance, but really it shouldn't. I do not know how to combat this. The only way I have was to use a continue; when I print out the results if the array content = ""; if (*(words + i) == "") continue;. This basically ignores those blanks in the array. But I think that is messy. I just want to figure out how to move the pointer back in this method. words and frequency are my dynamic arrays.
I would like guidance in what my problem is, rather than solutions.
I have now changed my outer loop to be a while loop, and only increment when I have found the word. Thank you WhozCraig and poljpocket.
Now this occurs.
Instead of incrementing your loop variable [i] every loop, you need to only increment it when a NEW word is found [i.e. not one already in the words array].
Also, you're wasting time in your inner loop by looping through your entire words array, since words will only exist up to index i.
int idx = 0;
while (file >> hold && idx < count) {
if (!valid_word(hold)) {
continue;
}
// You don't need to check past idx because you
// only have <idx> words so far.
for (int i = 0; i < idx; i++) {
if (toLower(words[i]) == toLower(hold)) {
frequency[i]++;
isFound = true;
break;
}
}
if (!isFound) {
words[idx] = hold;
frequency[idx] = 1;
idx++;
}
isFound = false;
}
First, to address your code, this is what it should probably look like. Note how we only increment i as we add words, and we only ever scan the words we've already added for duplicates. Note also how the first pass will skip the j-loop entirely and simply insert the first word with a frequency of 1.
void addWords(const std::string& fname, int count, string *words, int *frequency)
{
std::ifstream file(fname);
std::string hold;
int i = 0;
while (i < count && (file >> hold))
{
int j = 0;
for (; j<i; ++j)
{
if (toLower(words[j]) == toLower(hold))
{
// found a duplicate at j
++frequency[j];
break;
}
}
if (j == i)
{
// didn't find a duplicate
words[i] = hold;
frequency[i] = 1;
++i;
}
}
}
Second, to really address your code, this is what it should actually look like:
#include <iostream>
#include <fstream>
#include <map>
#include <string>
//
// Your implementation of toLower() goes here.
//
typedef std::map<std::string, unsigned int> WordMap;
WordMap addWords(const std::string& fname)
{
WordMap words;
std::ifstream inf(fname);
std::string word;
while (inf >> word)
++words[toLower(word)];
return words;
}
If it isn't obvious by now how a std::map<> makes this task easier, it never will be.
check out SEEK_CUR(). If you want to set the cursor back
The problem is a logical one, consider several situations:
Your algorithm does not find the current word. It is inserted at position i of your arrays.
Your algorithm does find the word. The frequency of the word is incremented along with i, which leaves you with blank entries in your arrays whenever there's a word which is already present.
To conclude, 1 works as expected but 2 doesn't.
My advice is that you don't rely on for loops to traverse the string but use a "get-next-until-end" approach which uses a while loop. With this, you can track your next insertion point and thus get rid of the blank entries.
int currentCount = 0;
while (file)
{
// your inner for loop
if (!found)
{
*(words + currentCount) = hold;
*(frequency + currentCount) = 1;
currentCount++;
}
}
Why not use a std::map?
void collect( std::string name, std::map<std::string,int> & freq ){
std::ifstream file;
file.open(name.c_str(), std::ifstream::in );
std::string word;
while( true ){
file >> word; // add toLower
if( file.eof() ) break;
freq[word]++;
}
file.close();
}
The problem with your solution is the use of count in the inner loop where you look for duplicates. You'll need another variable, say nocc, initially 0, used as limit in the inner loop and incremented whenever you add another word that hasn't been seen yet.