Reading data into a struct array from a file - c++

I have an input file that looks like this
1 0 3
2 11 5
3 15 1
4 16 11
and a structure that looks like this
struct numb {
int numb1;
int numb2;
int numb3;
}
and I need to create an array of the struct so that each element of the array holds all three numbers. So
numbArray[0].numb1 == 1
numbArray[0].numb2 == 0
numbArray[0].numb3 == 3
numbArray[1].numb1 == 2
numbArray[1].numb2 == 11
and so on. I've gotten the hang of opening and closing files, finding how many lines there are in a file, and reading a single line from a file, but I do not know how to store individual elements from a line.
My program looks like this so far:
#include <iostream>
#include <fstream>
#include <string>
int main(int argc, char* argv[])
{
ifstream inFile(argv[1]);
int fileLength = 0;
std::string line;
while(std::getline(inFile, line))
{
++fileLength;
}
struct numb {
int numb1;
int numb2;
int numb3;
}
if(inFile.is_open())
{
for(unsigned i = 0; i <= fileLength; i++)
{
//What to do here?
}
}
}

Use getline when you don't have regular structure to the input and need to handle variation between lines. When your input file has regular structure (in this case, there are always three values per line), then simply use the stream extraction operators directly:
#include <iostream>
#include <vector>
struct group
{
int n1;
int n2;
int n3;
};
int main()
{
std::vector<group> groups;
while (std::cin)
{
group line;
line.n1 << std::cin;
line.n2 << std::cin;
line.n3 << std::cin;
groups.push_back(group);
}
}
Express your ideas directly in code as much as possible.
Note I've written the code assuming that the file is in the proper form. If there are too many or too few values per line, then the above code will be confused. However, it is best to code the simplest thing that could possibly work and worry about complexity when you need it. In your example you stated that the input file was well-formed, so there's no need to overcomplicate things.

I recommend using a std::stringstream for this:
#include <iostream>
#include <sstream>
#include <string>
#include <stdio.h>
#include <vector>
struct numb {
int numb1;
int numb2;
int numb3;
};
void populate(std::vector<numb>& my_numbs, std::string line) {
std::stringstream ss(line);
numb my_numb;
ss >> my_numb.numb1 >> my_numb.numb2 >> my_numb.numb3;
my_numbs.push_back(my_numb);
}
void output(const numb my_numbs) {
printf("%d %d %d\n", my_numbs.numb1, my_numbs.numb2, my_numbs.numb3);
}
int main(int argc, char* argv[]) {
ifstream inFile(argv[1]);
std::string line;
std::vector<numb> my_vect;
while(std::getline(inFile, line)) {
populate(my_vect, line);
}
for(size_t i = 0; i < my_vect.size(); ++i) {
std::cout << "my_vect[" << i << "]:";
output(my_vect[i]);
}
return 0;
}
std::stringstreams allow you to parse out data types from std::strings, you you just need to parse out 3 ints, which you can use with your struct. You then push the struct into your vector.
Here's the working ideone taking input from stdin.

You should probably be able to do something like this:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
ifstream inFile(argv[1]);
int fileLength = 0;
std::string line;
struct numb {
int numb1;
int numb2;
int numb3;
};
vector<vector<int>> sets;
int n1, n2, n3;
while (std::cin >> n1)
{
cin >> n2;
cin >> n3;
vector<int> vec;
vec.push_back(n1);
vec.push_back(n2);
vec.push_back(n3);
sets.push_back(vec);
}
numb * numbSet = new numb[sets.size()];
//Since the vectors data is continuous in memory just as the array of structs are
//you can just copy the data directly
for (int i = 0; i < sets.size(); i++)
{
std::memcpy(&numbSet[i], &sets[i][0], sizeof(numb));
}
}

Related

C++ how to get output into a file

So I am not sure how to get the output to like a .txt file, the code keeps giving me a .txt file but it is always empty. I know I am supposed to include a line where it outputs the information but I am uncertain of what to put in the line since its a void function and it doesn't return anything, would changing it to a different type of function solve the problem?
Code:
#include <iostream>
#include <string>
#include <fstream>
#include "ArgumentManager.h"
using namespace std;
void permute(string a, int l, int r)
{
if (l == r)
cout<<a<<endl;
else
{
for (int i = l; i <= r; i++)
{
swap(a[l], a[i]);
permute(a, l+1, r);
swap(a[l], a[i]);
}
}
}
int main(int argc, char* argv[])
{
ArgumentManager am(argc, argv);
ifstream input;
ofstream output;
string infileName = am.get("input");
string outfileName = am.get("output");
input.open(infileName);
output.open(outfileName);
string str;
int n = str.size();
permute(str, 0, n-1);
return 0;
}
I havent worked with ArgumentManager before in C++.
But can you use something like:
// basic file operations
#include <iostream>
#include <fstream>
using namespace std;
int main () {
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
return 0;
}
I think instead of passing the output to cout, you should pass it to myfile object.

How to prelevate an imprecision number of element from a file with fstream?

I should read a text file which contain an imprecision number of lines with names of different car, follow by numbers of cars sold in the last 6 month. I don't know how to read the file without know the precise number of element that is content in it.
The file is like this:
Ferrari 3 7 5 4 1 3
Porsche 10 11 12 13 10 11
Lamborghini 1 8 2 3 4 1
...
...
I know that I must use the "fstream" library, but after the file opening, i don't know what i should do.
For example:
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
fstream file;
file.open("nomefile.txt", ios::in);
...
return 0;
}
You can use std::getline() in a loop, using std::istringstream to parse each line, eg:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main()
{
std::ifstream file("nomefile.txt");
std::string line, name;
int sold[6];
while (std::getline(file, line))
{
std::istringstream iss(line);
iss >> name;
for(int i = 0; i < 6; ++i) {
iss >> sold[i];
}
// use name and sold[] as needed...
}
return 0;
}
Or, since each line has a fixed format, you can just use operator>> directly on the file stream, eg:
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream file("nomefile.txt");
std::string name;
int sold[6];
while (iss >> name)
{
for(int i = 0; i < 6; ++i) {
iss >> sold[i];
}
// use name and sold[] as needed...
}
return 0;
}
In this case, I would probably opt for using a std::vector containing elements of a struct type that holds the data for each line, eg:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <limits>
struct SaleInfo
{
std::string carName;
int carsSold[6];
};
std::istream& operator>>(std::istream &in, SaleInfo &sale)
{
in >> sale.carName;
for(int i = 0; i < 6; ++i) {
in >> sale.carsSold[i];
}
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return in;
}
int main()
{
std::ifstream file("nomefile.txt");
std::vector<SaleInfo> sales;
SaleInfo sale;
while (file >> sale) {
sales.push_back(sale);
}
// use sales ss needed...
return 0;
}

How to start reading file from a particular position c++

I am reading a file using fstream and getline functions. I want to give a starting position e.g. my file has 13 lines I want to start reading it from 7th line for example. Here is my code:
#include<iostream>
#include <stdlib.h>
#include <string>
#include <vector>
#include<iterator> // for iterators
#include<map>
using namespace std;
int main()
{
string line;
int start= 7;
unsigned long int index;
For( int z=1; z<=13; z++){
if (f_node.is_open())
{
getline(f_node, line);
if ((line.find("$EndNodes") != string::npos))
{
cout << "$EndNodes found file closed .... " << endl;
f_node.close();
return false;
}
// Point index.
int i = 0;
int j = line.find_first_of(" ", i);
index = strtoul((line.substr(i, j)).c_str(), NULL, 0);//
}
}
I am reading only indexes and I want to start it from 7th index How to do it?
To discard some number of lines, something like:
#include <fstream>
#include <string>
int main() {
std::ifstream infile{"myfile.txt"};
std::string line;
int starting_line = 7;
// Read and discard beginning lines
for (int n = 1; n < starting_line; n += 1) {
if (!std::getline(infile, line)) {
// Error or premature end of file! Handle appropriately.
}
}
while (std::getline(infile, line)) {
// Do something with the lines you care about.
}
return 0;
}
Except with actual error checking and handling and such.
"there is no way to tell code the starting position like seekg and tellg?" No. NL is just like any other character, it does not receive any special treatment.
You simply must scan the stream, counting the new-line character:
std::istream& seek_line(std::istream& is, const int n, std::ios_base::seekdir way = std::ios_base::beg)
{
is.seekg(0, way);
int i = 0;
char c;
while (is.get(c) && i < n)
if (c == '\n')
++i;
is.putback(c);
return is;
}
And this is how you use the above function:
int main()
{
using namespace std;
ifstream is{ "c:\\temp\\test.txt" };
if (!is)
return -1;
if (!seek_line(is, 3))
return -2;
string s;
getline(is, s);
cout << s << endl;
return 0;
}

C++ Array pointer-to-object error

I am having what seems to be a common issue however reading through the replies to the similar questions I can't find the solution to my issue at all as I have already done what they are suggesting such as making the variable an array. I have the following code:
#include "stdafx.h"
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <algorithm>
#include <future>
using namespace std;
string eng2Str[4] = { "money", "politics", "RT", "#"};
int resArr[4];
int main()
{
engine2(eng2Str[4], resArr[4]);
system("Pause");
system("cls");
return 0;
}
void engine2(string &eng2Str, int &resArr)
{
ifstream fin;
fin.open("sampleTweets.csv");
int fcount = 0;
string line;
for (int i = 0; i < 4; i++) {
while (getline(fin, line)) {
if (line.find(eng2Str[i]) != string::npos) {
++fcount;
}
}
resArr[i] = fcount;
}
fin.close();
return;
}
Before you mark as duplicate I have made sure of the following:
The array and variable I am trying to assign are both int
Its an array
The error is:
expression must have pointer-to-object type
The error is occurring at the "resArr[i] = fcount;" line and am not sure why as resArr is an int array and I am trying to assign it a value from another int variable. I am quite new to C++ so any help would be great as I am really stuck!
Thanks!
The problem is that you've declared your function to take a reference to a single string and int, not arrays. It should be:
void engine2(string *eng2Str, int *resArr)
or:
void engine2(string eng2Str[], int resArr[])
Then when you call it, you can give the array names as arguments:
engine2(eng2Str, resArr);
Another problem is the while loop in the function. This will read the entire file during the first iteration of the for() loop. Other iterations will not have anything to read, since it will be at the end of the file already. You could seek back to the beginning of the file, but a better way would be to rearrange the two loops so you just need to read the file once.
while (getline(fin, line)) {
for (int i = 0; i < 4; i++) {
if (line.find(eng2Str[i]) != string::npos) {
resArr[i]++;
}
}
}
I would suggest to use std::vector instead of pure C array.
In your code, there are more issues.
You are passing the fourth element of both arrays to the engine2 function.
From your definition of void engine2(string &eng2Str, int &resArr) you expect reference to a string (not array / vector) and an address / reference of int - you need to pass an pointer to the first element of resArr.
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <future>
using namespace std;
vector<string> eng2Str = { "money", "politics", "RT", "#" };
int resArr[4] = {};
void engine2(const vector<string>& eng2Str, int* resArr)
{
ifstream fin;
fin.open("sampleTweets.csv");
int fcount = 0;
string line;
for (int i = 0; i < 4; i++)
{
while (getline(fin, line))
{
if (line.find(eng2Str[i]) != string::npos)
{
++fcount;
}
}
resArr[i] = fcount;
}
fin.close();
return;
}
int main()
{
engine2(eng2Str, resArr);
system("Pause");
system("cls");
return 0;
}

Searching for an int inside a file

So I am supposed to take all ints in source3.txt and check which of them occur in source.txt. If any of them don't occur, I'm supposed to print a corresponding line from source2.txt to output.txt (source2.txt contains descriptions of the numbers in source 3, in the same order, each description is 1 line). I wrote this code, but it only prints the last line from source2.txt, furthermore it is a wrong line.
I have no idea what might be wrong. Can you help me?
#include <bits/stdc++.h>
using namespace std;
int main()
{
ifstream source ("source.txt");
ifstream source2 ("source2.txt");
ifstream source3 ("source3.txt");
vector<int> tab(1051,0);
vector<string> tab2(857,*new string);
vector<int> tab3(857,0);
ofstream output("output.txt");
for(int i=0;i<1050;++i)
{
source>>tab[i];
}
for(int i=0;i<856;++i)
{
string a;
getline(source2,a);
tab2[i]=a;
source3>>tab3[i];
}
for(int i=0;i<856;++i)
{
if(std::find(tab.begin(), tab.end(), tab3[i]) != tab.end())
{
continue;
}
else
{
output<<tab2[i]<<endl;
}
}
}
I think below modifications to code should work for you . Replace value of SOURCE_COUNT with 1051 and SOURCE2_COUNT with 857
#include <iostream>
#include <fstream>
#include <vector>
#include <vector>
const int SOURCE_COUNT = 4;
const int SOURCE2_COUNT = 3;
//const int SOURCE2_COUNT = 3;
using namespace std;
int main()
{
ifstream source ("source.txt");
ifstream source2 ("source2.txt");
ifstream source3 ("source3.txt");
vector<int> tab(SOURCE_COUNT,0);
vector<string> tab2(SOURCE2_COUNT,"");
vector<int> tab3(SOURCE2_COUNT,0);
ofstream output("output.txt");
for(int i=0;i<SOURCE_COUNT;++i)
{
source>>tab[i];
}
for(int i=0;i<SOURCE2_COUNT;++i)
{
string a;
getline(source2,a);
tab2[i]=a;
source3>>tab3[i];
}
for(int i=0;i<SOURCE2_COUNT;++i)
{
if(std::find(tab.begin(), tab.end(), tab3[i]) != tab.end())
{
continue;
}
else
{
output<<tab2[i]<<endl;
}
}
}
It looks to me like you are printing only in those cases where you have not found the number. In other words, the cases in your if-statement are reversed. It should read:
if(std::find(tab.begin(), tab.end(), tab3[i]) != tab.end())
output<<tab2[i]<<endl;
[EDIT] Oops, I read the question not carefully enough. It should print the line, if the number is NOT contained in source3. So the loop should read:
if(std::find(tab.begin(), tab.end(), tab3[i]) == tab.end())
output<<tab2[i]<<endl;
Also: I would strongly suggest to do away with all those constants like 856 and 1050. Why don't you simply read the file until you reach the end?