So I have a custom decipher program that reads in an input file and deciphers it based on the keys that are input.
Text file:
23
11
Java 2 linux 3 fear 0 pool 2 do 0 red 1 lock. 1 I 0 random 2 computers, 0 not 0 the 0 open 2 car! 2 C, 0 lack 0 of 0 dog 1 green 2 C++ 0 bottle 2 wrong, 2 them. 0
5 1 10 21 9 6 21 11 13 16 20
This file is represented as:
[Number of Words]
[Number of Keys]
[Word] [Jump] [Word] [Jump] ... [Word] [Jump]
[Key] [Key] ... [Key]
I have managed for the program to read in the number of keys and amount of words, however I have having trouble reading in the words and the numbers next to them as well as the last numbers and registering those as keys. This is what I have so far:
#include <iostream>
#include <fstream>
using namespace std;
struct pieces {
char word;
int jump;
} ;
// Main Function
int main ()
{
// declare variables
int keyCount = 1;
int wordCount = 8;
int wordAmount[8];
int keyAmount[8];
pieces cipher[5];
char decoded[20][20];
char filename[10];
int keys[keyCount];
char tArray[20][20];
ifstream inData;
//prompt user for input file
cout << " Enter file name: ";
cin >> filename;
inData.open(filename);
if(inData.is_open());
{
// read list of names into array
for ( int i = 0; i < keyCount; ++i){
inData >> wordAmount[i] >> keyAmount[i];
for(int j = 0; j < wordCount; j++){
inData >> cipher[j].word >> cipher[j].jump;
}
}
cout << " Key Count: " << keyCount << "\n";
// print out
for ( int i = 0; i < keyCount; ++i){
cout << " KeyAmount: ";
cout << keyAmount[i] << "\n";
cout << " WordAmount: ";
cout << wordAmount[i] << "\n";
for(int j = 0; j < wordCount; j++){
cout << cipher[j].word << " " << cipher[j].jump;
}
}
}
inData.close();
return 0;
}
I did try putting the char word as an array but then I got a segmentation file. Any advice would be appreciated!
IMHO, your project would be simpler if you used std::string and overloaded the formatted input operator >>:
struct Word_Jump
{
std::string word; // Using std::string because it has space for more than one character.
int jump;
friend std::istream& operator>>(std::istream& input, Word_Jump& wj);
};
std::istream&
operator>>(std::istream& input, Word_Jump& wj)
{
input >> wj.word;
input >> jump;
return input;
}
Your input could look something like this:
std::vector<Word_Jump> database;
for (unsigned int i = 0; i < number_of_words; ++i)
{
Word_Jump wj;
my_data_file >> wj;
database.push_back(wj);
}
Similarly, you input for reading keys:
std::vector<int> key_database;
for (unsigned int j = 0; j < number_of_keys; ++j)
{
int k = 0;
my_data_file >> k;
key_database.push_back(k);
}
So the above are two possible methods for reading in the word & jump pairs and also the keys.
Related
So I have written a code where I take three strings at each iteration and store all the combinations of length three(maintaining the order) taking each character from those three strings. I use a char array to make those combinations and then I convert that char array to a string and insert in an unordered_set. While doing so, I encountered a problem where I see an extra character being added at the end of some strings.
Here is my code:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
char charArr[3];
string strArr[3];
unordered_set<string> aSet;
cin >> n;
while(n-- > 0) {
cin >> strArr[0] >> strArr[1] >> strArr[2];
for(int x=0; x<strArr[0].size(); x++) {
charArr[0]=strArr[0][x];
for(int y=0; y<strArr[1].size(); y++) {
charArr[1]=strArr[1][y];
for(int z=0; z<strArr[2].size(); z++) {
charArr[2]=strArr[2][z];
string tempStr(charArr);
cout << "Len = " << tempStr.length() << "\n";
aSet.insert(tempStr);
}
}
}
}
cout << "Check aaz = " << aSet.count("aaz") << "\n";
for(auto it=aSet.begin(); it!=aSet.end(); it++) {
cout << *it << "\n";
}
}
Here is a sample input:
2
a a z
c a c
Here is the output:
Len = 4
Len = 3
Check aaz = 0
cac
aaz
Here is a picture of how it looks in my pc:
However when I ran the same code for same input in ideone, it gave me the correct answer. Which is as follows:
Len = 3
Len = 3
Check aaz = 1
cac
aaz
Can anybody please explain what's going on here?
N.B: I'm using CodeBlocks and C++14
I try to read values from a data file. However, it has a different amount of values per column which I need to extract.
The list of values looks like this:
8
11
0 0 -50
1000 0 -50
2000 0 0
0 500 0
500 500 0
0 1000 -50
1000 1000 0
2000 1000 150
With the code below I can store all values in the array but I want to store the 8 and the 11 seperatly. Furthermore should the first column (0 to 2000) be stored in one array, the second one (0 to 1000) in a second array and the third one (-50 to 150) in a third array.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
cout << "PROGRAM PIPE NETWORK" << endl;
//Read input data file
int n;
double *array;
cout << "How many data sets do you have?\nDatasets: ";
cin >> n;
ifstream infile("pipedata.dat");
array = new double[n];
for (int i = 1; i < n; ++i)
infile >> array[i];
return 0;
}
I hope some of you can help me and please try to not write a general answer. I am quiet new in this topic.
Greetings.
EDIT 1:
An other attempt is the following, however it works sometimes but I also get erros with data adresses or heap difficulties. Sometimes it works but most of the time my program just stops working.
int main()
{
cout << "PROGRAM PIPE NETWORK" << endl;
// Read input all data files
int n; double *input;
int limit_x, x; double *array_x;
int limit_y, y; double *array_y;
int limit_q, q; double *array_q;
int n_nodes, n_tubes;
cout << "How many data sets do you have?\nDatasets: ";
cin >> n;
ifstream infile("pipedata.dat");
input = new double[n];
for (int i = 0; i<n; ++i) infile >> input[i];
// Assign input values to their variables
// Number of nodes and number of tubes
n_nodes = input[0];
n_tubes = input[1];
cout << "Input values" << endl;
for (int i = 0; i < n; ++i)
{
cout << input[i] << endl;
}
cout << "---------------------------------------" << endl;
cout << "X-Values" << endl;
// Node data x-values
x = n_nodes;
limit_x = n_nodes * 3;
array_x = new double[x];
for (int i = 0; i < limit_x; i += 3) array_x[i] = 0;
for (int i = 0; i < limit_x; i+=3) array_x[i] = input[i+2];
for (int i = 0; i < limit_x; i+=3) cout << array_x[i] << endl;
return 0;
}
Everything works fine with "input" but not with array_x. Also I want to do the exact same thing with 5 other variables. I know it isnt the best solution but I realy dont understand why it does not work.
I don't know what the complications are, but here is an example:
std::vector<int> array_1;
std::vector<int> left;
std::vector<int> middle;
std::vector<int> right;
int temp;
// Read two numbers into an array
data_file >> temp;
array_1.push_back(temp);
data_file >> temp;
array_1.push_back(temp);
// Read columns of data into separate arrays
int left_value, middle_value, right_value;
while (data_file >> left >> middle >> right)
{
left.push_back(left_value);
middle.push_back(middle_value);
right.push_back(right_value);
}
The above is one example of many. It is not optimized.
Another example uses std::getline and std::istringstream, which would comply better with the alignment of the rows.
Edit1: Line by line processing
std::string text_line;
std::istringstream parser;
// Read a line from the file
std::getline(data_file, text_line);
// Extract the numbers from the line:
parser.str(text_line); // Initialize the std::istringstream with the text line.
int value_1 = 0;
parser >> value_1; // Extract the first number of the first line.
// Read the second line from the file
std::getline(data_file, text_line);
// Extract the numbers from the line:
parser.str(text_line); // Initialize the std::istringstream with the text line.
int value_2 = 0;
parser >> value_2; // Extract the first number of the second line.
// After reading 2 lines, the file pointer should be pointing
// at the 3rd line.
// The data format changes at the 3rd line with 3 numbers per line.
// Let's use an array this time, one per column.
const unsigned int ARRAY_CAPACITY = 256;
int column_1[ARRAY_CAPACITY];
int column_2[ARRAY_CAPACITY];
int column_3[ARRAY_CAPACITY];
unsigned int row = 0;
// Read until the data stream fails, usually at EOF.
while (std::getline(data_file, text_line))
{
// ** Very important, check for overflow before using array**
if (row >= ARRAY_CAPACITY)
{
// Either reallocate and copy old array or ...
// Crash the program.
std::cerr << "Array capacity is too small.\n";
exit(1);
}
// Initialize the parser
parser.str(text_line);
// Extract the first value and place into array, directly.
parser >> column_1[row];
// Likewise, the next columns.
parser >> column_2[row];
parser >> column_3[row];
// Advance the column index to the next row (line)
++row;
}
I solved a problem in Hacker Rank.
Input Format. The first line of the input contains an integer N.The next line contains N space separated integers.The third line contains a single integer x,denoting the position of an element that should be removed from the vector.The fourth line contains two integers a and b denoting the range that should be erased from the vector inclusive of a and exclusive of b.
Output Format. Print the size of the vector in the first line and the elements of the vector after the two erase operations in the second line separated by space.
CODE:
#include <vector>
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main() {
int n = 0, x = 0, value = 0;
vector<int> vk, vm;
vk.reserve(100000);
string k, m;
cin >> n;
cin.ignore();
getline(cin, k);
cin >> x;
cin.ignore();
getline(cin, m);
stringstream sk(k);
while (sk >> value)
vk.push_back(value);
stringstream sm(m);
while (sm >> value)
vm.push_back(value);
vk.erase(vk.begin() + x-1);
vk.erase(vk.begin() + vm[0]-1, vk.begin() + vm[1]-1);
cout << vk.size() << endl;
for (int i = 0; i < vk.size(); i++)
cout << vk[i] << " ";
cout << endl;
return 0;
}
But with this test case produce a "Segmentation Fault":
6
1 4 6 2 8 9
2
2 4
Can you help me to review my code and provide some feedback on what is the problem?
EDIT
Thanks to #john for the answer. Here is how it looks without the seg fault:
#include <vector>
#include <iostream>
#include <string>
using namespace std;
int main() {
int n = 0, x = 0, y = 0, z = 0, value = 0;
vector<int> vk;
vk.reserve(100000);
cin >> n;
for (int i = 0; i < n; ++i) {
cin >> value;
vk.push_back(value);
}
cin >> x >> y >> z;
vk.erase(vk.begin() + x-1);
vk.erase(vk.begin() + y-1, vk.begin() + z-1);
cout << vk.size() << endl;
for (int i = 0; i < vk.size(); i++)
cout << vk[i] << " ";
cout << endl;
return 0;
}
You're trying too hard with the your input code. It isn't correct because you seem to be assuming that cin.ignore() will skip the rest of the line, when it only skips the next character (which could be a space). I would guess this is the reason for the seg fault. You can tell how many numbers you have to read after you've read the first one. There is no need to use getline or stringsteam at all.
You don't need the vm vector. It will always contain two values, so just declare two variables. You could also pick much better names for all your variables.
cin >> n;
for (int i = 0; i < n; ++i)
{
cin >> value;
vk.push_back(value);
}
cin >> x >> vm0 >> vm1;
I need help from you about getline validation. I've created 2D Matrix using vector and I would like to fill that 2D Matrix with values from console.
The problem is with validation of the single values in input (one row). When I type for example "d" or any other character, my code converts it to 0 and put the value in the matrix.. however thats not what I want. I want the user to type the values again (until they are valid) and put the new values in the matrix. This is the code:
string number, line;
cin.ignore();
double value = 0;
for(unsigned int i = 0; i < n; i++)
{
while((getline(cin, number, '\n'))) {
cout << "-> ";
stringstream iss(number);
for (unsigned int j = 0; j <= n; j++)
{
if ( !(iss >> value) )
{
cout << "[ERROR] Invalid input. Type a valid number:" << endl;
cin.clear();
cin.ignore(256, '\n');
} else {
A[i][j] = value;
}
}
break;
}
}
//Edit:
What I want to accomplish is to check, if the value in the line which is inputted is a valid number. For example (input)
1 1 1 1
2 2 2 2
3 char 3 3
[ERROR] Invalid input. Type a valid number:
3 3 3 3
And the output of that should be as it was inputted without the error line with random char other than number.
Right now with my code above, it says Invalid input, but it outputs the last line with error as 0 and the followed numbers after that 0 are zeroes too, because it ignores the new inputted fixed lines with valid numbers.
Output looks like this (with the error):
1 1 1 1
2 2 2 2
3 0 0 0
I don't think the values are put into the matrix with a value of 0. Instead, they merely stay in the matrix with the value 0! Essentially, you break out out of the while-loop processing lines independent on whether the values have been read successfully. I'd probably move some of the conditions around and avoid the intermediate stream: it doesn't seem helpful as you don't really do line-oriented input.
double value;
for (unsigned int i{0}; i != n && std::cin; ++i) {
for (unsigned int j{0}; std::cin; ) {
if (std::cin >> value) {
A[i][j] = value;
if (++j == n) {
++i;
break;
}
else if (!std::cin.eof()) {
std::cin.clear();
std::string line;
std::getline(std::cin, line); // !std::cin.eof() => this shall be successful!
std::cout << "ERROR invalid number input: ignoring '" << line << "'\n";
}
}
}
I think you need to move the getline out of the while to make it works.
Here an example. I didn't compiled it but it should give you a general idea.
// To be tested
string number, line;
cin.ignore();
double value = 0;
bool validInput;
for(unsigned int i = 0; i < n; i++)
{
validInput = false;
while(!validInput) {
getline(cin, number, '\n');
std::istringstream iss(number);
iss >> value;
if (!iss.fail() && iss.eof())
{
cout << "[ERROR] Invalid input. Type a valid number:" << endl;
cin.clear();
cin.ignore(256, '\n');
continue;
}
validInput = true;
for (unsigned int j = 0; j <= n; j++)
{
A[i][j] = value;
}
}
}
I am trying to tackle this condition where the user has to input a number n. and then entering n numbers after it on the same line. Therefore my program needs to know this number n before the user continues to input so that the programs knows how large of a dynamic array it needs to save these numbers inputted after n. (It is crucial that all of this happens on one line).
I tried the following but it doesn't seem to work.
int r;
cin >> r;
//CL is a member function of a certain class
CL.R = r;
CL.create(r); //this is a member function creates the needed dynamic arrays E and F used bellow
int u, v;
for (int j = 0; j < r; j++)
{
cin >> u >> v;
CL.E[j] = u;
CL.F[j] = v;
}
You can do that as usual on a single line:
#include <string>
#include <sstream>
#include <iostream>
#include <limits>
using namespace std;
int main()
{
int *array;
string line;
getline(cin,line); //read the entire line
int size;
istringstream iss(line);
if (!(iss >> size))
{
//error, user did not input a proper size
}
else
{
//be sure to check that size > 0
array = new int[size];
for (int count = 0 ; count < size ; count++)
{
//we put each input in the array
if (!(iss >> array[count]))
{
//this input was not an integer, we reset the stream to a good state and ignore the input
iss.clear();
iss.ignore(numeric_limits<streamsize>::max(),' ');
}
}
cout << "Array contains:" << endl;
for (int i = 0 ; i < size ; i++)
{
cout << array[i] << ' ' << flush;
}
delete[] (array);
}
}
And here is the demonstration, you can see that the input is one line 6 1 2 3 4 5 6.
Once again, I did not check everything, so take care of that the way you need.
Edit: added reset of the stream after a bad read.