Passing an array of pointers to a function - c++

This assignment is called a co-currence problem. The point of my program is to read in sentences from a file and ignore any punctuation. Then, I will read user input where the user will enter words separated by a space only and I have to search for those exact words in all the sentences of the file and return the line number where all the words are found.
My approach now is to create a pointer array to other arrays that contain the words for each sentence.
ifstream read;
string filename;
string **txtPtr = nullptr;
int numLines = 0;
getFileName();
getNumLines(read, fileName); //stores # of lines into numLines
txtPtr = new string*[numLines];
My question is, can I pass the pointer to a function as string *lines or string *lines[]?

I would parse the input file and build an index, and then I would look up user-entered words in that index. The index would be std::map with std::string as a key and with "Entry" struct as a value:
struct Entry {
int line;
int sentence;
};
typedef std::map<std::string, Entry> Index;
This is how insertion would look like:
Index index;
Entry val;
val.line = 1;
val.sentence = 2;
std::string word = "hi";
index.insert(Index::value_type(word, val));
This is how lookup would look like:
Index::iterator it = index.find(word);
if (it != index.end())
std::cout << "found:" << it->second.line;
I know it's not the answer for your question, but it might help anyway..

Related

How to delimit and write file contents to vector?

So let's say I have a vector of ints and a text file which looks like this:
1|2|3|4|5
How can I add the numbers to the vector?
First, you would open the file using std::ifstream. There are a few ways you could then read these out, but one example would be to use std::getline with a custom "end of line" character, being your | in this case:
std::vector<int> myVect;
std::ifstream reader("./file.txt"); //Replace with path to your file
for(int i = 0; i < 5; i++) {
std::string item;
std::getline(reader, item, '|'); //The third argument tells it to read until a '|' char
int item = std::stoi(item); //Convert from string to int
myVect.push_back(number);
}
This example relies on you knowing how many elements you want to get, but can be modified to work with an unknown size.

Truncating and removing characters from char array C++

I basically have a txt file that looks like this...
High Score: 50
Player Name: Sam
Number Of Kills: 5
Map
Time
I want to store everything before the : or whitespace after Map and Time into one array and everything after in another. For both Map and Time, there is nothing after and so I want to store the whitespace as null.
So far, I have managed to read and store all this information into a temp array. However, it is separating that I am having trouble with. This is my code:
istream operator >> (istream &is, Player &player)
{
char **temp;
char **tempNew;
char lineInfo[200]
temp = new char*[5];
tempNew = new char*[5];
for (int i=0; i<5; i++)
{
temp[i] = new char[200];
is.getline(lineInfo, sizeof(lineInfo));
int length = strlen(lineInfo);
for (int z=0; z < length; z++)
{
if(lineInfo[z] == '= ' ){ //HOW DO I CHECK IF THERE IS NOTHING AFTER THE LAST CHAR
lineInfo [length - (z+1)] = lineInfo [length];
cout << lineInfo << endl;
strncpy(temp[i], lineInfo, sizeof(lineInfo));
}
else{
tempNew[i] = new char[200];
strncpy(tempNew[i], lineInfo, sizeof(lineInfo));
}
}
}
If what you need is to find ':'
#include <cstring>
and just
auto occurance = strstr(string, substring);
Documentation here.
if occurance is not a null ptr, then see if occurance is at the end of the line from get line. If not, your value is everything after that :
Much easier with std::string.
// Read high score
int high_score;
my_text_file.ignore(10000, ':');
cin >> high_score;
// Read player name
std::string player_name;
my_text_file.ignore(10000, ':');
std::getline(my_text_file, player_name);
// Remove spaces at beginning of string
std::string::size_type end_position;
end_position = player_name.find_first_not_of(" \t");
if (end_position != std::string::npos)
{
player_name.erase(0, end_position - 1);
}
// Read kills
unsigned int number_of_kills = 0;
my_text_file.ignore(':');
cin >> number_of_kills;
// Read "Map" line
my_text_file.ignore(10000, '\n');
std::string map_line_text;
std::getline(my_text_file, map_line_text);
// Read "Text" line
std::string text_line;
std::getline(my_text_file, text_line);
If you insist on using C-style strings (arrays of char), you will have to use more complex and less safe functionality. Look up the following functions:
fscanf, strchr, strcpy, sscanf

How do I get a list of pointers to chars to place their values into a list of chars

Hello I have been constructing a program that will allow me to parse a text file and return a string of char values corresponding to each word in the file. However, I have not been able to extract the chars from a list of type: const char*. Here is my .cpp and .h files:
.cpp file
list<char> GetTickers::getTickers(string address){
//fstream myfile (address ,std::ios_base::in);
ifstream fin;
fin.open(address); // open a file
if (!fin.bad())
exit; // exit if file not found
// read each line of the file
while (!fin.eof())
{
// read an entire line into memory
char buf[MAX_CHARS_PER_LINE];
fin.getline(buf, MAX_CHARS_PER_LINE);
// parse the line into blank-delimited tokens
int n = 0; // a for-loop index
// array to store memory addresses of the tokens in buf
//const char* token[MAX_TOKENS_PER_LINE] = {}; // initialize to 0
// parse the line
token[0] = strtok(buf, DELIMITER); // first token
if (token[0]) // zero if line is blank
{
for (n = 1; n < MAX_TOKENS_PER_LINE; n++)
{
token[n] = strtok(0, DELIMITER); // subsequent tokens
if (!token[n]) break; // no more tokens
}
}
// process (print) the tokens
for (int i = 0; i < n; i++) // n = #of tokens
// cout << "Token[" << i << "] = " << token[i] << endl;
// cout << endl;
adresses[i]= &token[i];
}
}
.h file
class GetTickers{
//varialbe
private:
const int MAX_CHARS_PER_LINE = 512;
static const int MAX_TOKENS_PER_LINE = 30;
const char* const DELIMITER = " ";
list<char> adresses;
const char* token[MAX_TOKENS_PER_LINE] = {}; // initialize to 0
public:
//methods
private:
list<char> getTickers(const string addreses);
public:
//constructors
GetTickers();
};
Following a build, I get an error, "Type list does not provide a subscript operator" on the last line of the .cpp file.
Does anyone know why this may be the case or how I can resolve this issue?
Thanks.
The const in const char* means that the data will not change. Make it char* instead:
char* token[MAX_TOKENS_PER_LINE] = {}; // initialize to 0
or better yet, make it a std::string:
std::string token;
adresses[i]= &token[i];
There are a few problems with this line.
adresses should be spelt addresses.
addresses is a std::list, which doesn't have operator[]. This is to make it clear that std::list doesn't provide constant time random access. Instead, you have to get an iterator with begin and move it along to the appropriate element:
std::list<char>::iterator it = addresses.begin();
std::advance(it, i);
Now it points at the ith element. If you're doing this often, you're probably using the wrong type.
Since token is an array of const char*, &token[i] gives you a const char**. You can't then assign that to an element of your list, where each element is a char. Exactly what you're trying to do there, I'm not sure. Perhaps you actually want addresses to be a std::list<const char*>?
Another problem is that you're doing file streaming badly. The !fin.eof() condition cannot preemptively tell you that you are going to hit the end of the file. What you'll find is that the getline that removes the last line will reach the final \n (that text files end with) and then stop. It doesn't actually try to read the end of the file. In the next iteration, !fin.eof() will pass, but there will be nothing more to read. Uh oh.
Overall, there's lots of problems with this, and it would be a hell of a lot easier if you used std::strings instead. I would suggest that both tokens and addresses could be std::vector<std::string>s.

How to number input in ascending order?

I have input coming in form a file input.txt as two columns of strings such as:
string1 string2
string3 string4
etc.
I am trying to number the strings in ascending order starting form 0 but in such a way that repeating strings don't get assigned new values but keep the once already assigned to them.
I decided to use a set::find operation to do this, but I am having a hard time making it work. Here's what I have so far:
int main(int argc, char* argv[]) {
std::ifstream myfile ("input.txt");
std::string line;
int num = 0; // num is the total number of input strings
if (myfile.is_open()) {
while(std::getline(myfile, line)) {
++num;
}
}
std::string str1, str1; // strings form input
int str1Num, str2Num; // numbers assigned to strings
int i = 0; // used to assign values to strings
StringInt si;
std::vector<StringInt> saveStringInts(num);
std::set<std::string> alreadyCounted(num, 0);
std::set<std::string>::iterator sit;
std::ifstream myfile2 ("input.txt");
if (myfile2.is_open()) {
while(myfile2.good()) {
// read in input, put it in vars below
myfile2 >> str1 >> str2;
// if strings are not already assigned numbers, assign them
if ((*(sit = alreadyCounted.find(str1)).compare(str1) != 0) { // doesn't work
str1Num = i++;
alreadyCounted.insert(str1);
saveStringInts.push_back(StringInt(str1Num));
}
else {
str1Num = si->getNum(str1);
}
if ((*(sit = alreadyCounted.find(str2)).compare(str2) != 0) {
str2Num = i++;
alreadyCounted.insert(str2);
saveStringInts.push_back(StringInt(str2Num));
}
else {
str2Num = si->getNum(str2);
}
// use str1 and str2 in the functions below before the next iteration
}
}
Unfortunately, I tried other approaches and now completely stuck. If you know how to fix my code or can suggest a better way to accomplish my task, I would greatly appreciate your help.
You need to compare std::set<int>::iterator against the end() iterator of your set, rather than dereferencing the iterator and comparing its value against something! Actually, derferencing the end() iterator is undefined behavior:
if ((*(sit = alreadyCounted.find(str1)).compare(str1) != 0) // WRONG: don't do that!
should really be
if (alreadyCounted.find(str1) != alreadyCounted.end())
... and likewise for the other string. Personally, I would use a different technique, though: when insert()ing into a std::set<T>, you get back a pair of an iterator and an indicator whether the object was inserted. The latter together with the current set's size give the next value, e.g.:
bool result = alreadyCounted.insert(str1).second;
strNum1 = result? alreadyCounted.size() - 1: si->getNum(str1);

Getting weird number when trying to read a number from file

I'm trying to read a number from a text file, and I'm not allowed to use a binary file.
I've tried two methods to do this, and both return a strange result.
The first method:
char *theNumber;
int i = 0;
while(data>>text)
{
theNumber[i] = text;
i++;
}
returns some weird accented characters.
The second
int theNumber;
while(data>>text)
{
theNumber = text; // I tried theNumber<<text; as well
}
When I cout the result of this one it returns some big number when the text file contained 123.
string filename;
char text;
int p; //first prime number
int q; //second prime number
unsigned long long toBeEncrypted;
cout<<"Enter name of file to encrypt: ";
cin>>filename;
ifstream data;
ofstream encryptedData;
encryptedData.open("RSA_cipher.txt");
cout<<"Please enter two prime numbers:"<<endl;
p = getPrime(1);
q = getPrime(2);
//doing stuff with file
int theNumber;
data >> theNumber;
//int i = 0;
/*while(data>>text)
{
theNumber[i] = text;
i++;
}*/cout<<theNumber;
...//other stuff unrelated to the problem
This code:
char *theNumber;
int i = 0;
while(data>>text)
{
theNumber[i] = text;
i++;
}
Has Undefined Behavior, because you are using theNumber[i] to access an array which you haven't even allocated. You should have done:
char theNumber[255]; // Buffer size depends on the particular application
int i = 0;
while(data>>text)
{
theNumber[i] = text;  
i++;
}
The second attempt:
theNumber = text;
May or may not work, depending on how you defined text. This is impossible to answer without knowing the definition of text.
Anyway, if you want to read in a number from an input stream, just do:
int number;
data >> number;
UPDATE:
In the last code snippet you updated, the data stream is constructed, but never open. It is not associated to any file. Therefore, attempting to read from that stream won't succeed, and nothing will be stored into number (which is uninitialized).
ifstream data;
// data is not associated to any file after construction...
int theNumber;
data >> theNumber;
This does not create storage for your number.
char *theNumber;
It's a pointer. It points somewhere arbitrary, since you haven't assigned an address to it.
Try this.
char theNumber[10]; // Whatever size you need.
Or this.
int theNumber;
You didn't allocate any memory for char *theNumber;.
The theNumber points to a random location and you are printing random characters