Copy information from file to variables - c++

#include <iostream>
#include <stdio.h>
using namespace std;
struct Table{
char fullname [100];
int group;
int firstMarks[5];
int secondMarks[5];
};
void ReadTable (Table *&data, int N);
void ShowTable (Table *data, int N);
int main() {
int N = 5;
Table *data = new Table[N]{
{},
{},
{},
{},
{}
};
ReadTable(data, N);
ShowTable(data, N);
}
void ReadTable (Table *&data, int N){
FILE *fl = fopen("table.txt","r");
if (!fl) {
cout << "Помилка";
exit(1);
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
fscanf(fl, "%[^|] | %d | %d %d %d %d %d | %d %d %d %d %d ", &data[i].fullname, &data[i].group,
&data[i].firstMarks[j], &data[i].firstMarks[j], &data[i].firstMarks[j], &data[i].firstMarks[j], &data[i].firstMarks[j],
&data[i].secondMarks[j], &data[i].secondMarks[j], &data[i].secondMarks[j], &data[i].secondMarks[j], &data[i].secondMarks[j]);
}
fscanf(fl, "\n");
}
fclose(fl);
}
void ShowTable (Table *data, int N){
for (int i = 0; i < N; i++) {
cout << data[i].fullname << " ";
cout << " | ";
cout << data[i].group << " ";
cout << " | ";
for (int j = 0; j < N; j++) {
cout << data[i].firstMarks[j] << " ";
}
cout << " | ";
for (int j = 0; j < N; j++) {
cout << data[i].secondMarks[j] << " ";
}
cout << endl;
}
}
file table.txt:
Новикова Аделина Максимовна | 1151 | 5 2 3 1 2 | 1 2 1 3 2
Воронина Анна Леоновна | 2151 | 2 4 3 2 1 | 5 4 5 5 4
Медведева Елена Михайловна | 4452 | 4 2 1 3 4 | 2 4 5 2 1
Зайцев Пётр Миронович | 1148 | 2 3 4 5 1 | 5 2 1 5 5
Кочергин Алексей Семёнович | 3252 | 4 4 3 4 5 | 2 1 3 4 2
Console output:
Кочергин Алексей Семёнович | 3252 | 2 1 4 1 5 | 2 4 1 5 2
| 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 0 0 0
| 0 | 0 0 0 0 0 | 0 0 0 0 0
Hi all, there is a table, one row of the table corresponds to one student and contains the following information: student's name, group number, exam grades for the first semester, exam grades for the second semester.
How do I read the information from the file into my structure variables? My attempts are unsuccessful, hope for your help!

C++ is an old, mutating language. Thus, it is hard for new users to discern, which language features belong to which state of mutation of the language.
First, you can do everything with <iostream>. Mixing in <stdio> just complicates matters, IMHO.
Second, you declare your Table struct (naming! it is one RECORD in a table, only) in C style (very old mutation) and you could make good use of newer C++ features. Assuming, of course, you do not sit on an ancient tool chain like BorlandC++ 6.0 or something (which would be your first mistake).
Now, with <iostream>, solving such tasks is always following the same pattern, repeatedly:
For input from a stream to a type, write yourself an overloaded operator>>.
For output to a stream for a type, write yourself an overloaded operator<<.
A further complication of your task is, that you use kyrillic names (utf8 file encoding?!). This can be a pitfall, but sometimes, as long as you do not try to dissect the name string, you get away with ignoring this.
See below a modernized (in terms of C++ mutation progress) version of your code, which, at least worked on my machine after copy and pasting your data into emacs and saving it.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <array>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cctype>
#include <locale>
using MarksArray = std::array<int,5>;
struct Data {
std::string fullname;
int group;
MarksArray firstMarks;
MarksArray secondMarks;
};
using DataVector = std::vector<Data>;
// trim functions taken from:
// https://stackoverflow.com/a/217605/2225104
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(),
s.end(),
[](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(),
s.rend(),
[](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
std::istream& operator>> (std::istream& stream, Data& data) {
bool success = true;
auto verify = [&success](const char* step) {
if (!success) {
std::cerr
<< "reading " << step << " failed!" << std::endl;
throw std::runtime_error(step);
}
};
success = success && std::getline(stream, data.fullname, '|');
verify("fullname");
trim(data.fullname);
std::string temp;
success = success && std::getline(stream, temp, '|');
verify("group");
data.group = std::stoi(temp);
success = success && std::getline(stream, temp, '|');
verify("firstMarks");
std::istringstream ss1(temp);
for (size_t i = 0; i < data.firstMarks.size(); i++) {
ss1 >> data.firstMarks[i];
}
success = success && std::getline(stream, temp);
verify("secondMarks");
std::istringstream ss2(temp);
for (size_t i = 0; i < data.secondMarks.size(); i++) {
ss2 >> data.secondMarks[i];
}
return stream;
}
std::ostream& operator<< (std::ostream& stream,
const MarksArray& data) {
bool first = true;
for (const auto& x : data) {
if (first) {
stream << x;
first = false;
} else
stream << " " << x;
}
return stream;
}
std::ostream& operator<< (std::ostream& stream, const Data& data) {
stream << data.fullname << " | "
<< data.group << " | "
<< data.firstMarks << " | "
<< data.secondMarks << std::endl;
return stream;
}
template <class T>
std::ostream& operator<< (std::ostream& stream,
const std::vector<T> & data) {
for (const auto &x : data) {
stream << x;
}
return stream;
}
DataVector ReadTable(const std::string& inPath) {
DataVector result;
std::ifstream stream(inPath);
size_t line = 1;
while (!std::ws(stream).eof()) {
try {
Data d;
stream >> d;
result.push_back(d);
line++;
}
catch (std::runtime_error& ex) {
std::cerr
<< "reading line " << line << " failed." << std::endl;
throw;
}
}
return result;
}
void WriteTable(std::ostream& stream, const DataVector& data) {
stream << data;
}
int main (int argc, const char* argv[]) {
std::string inputFilePath{"./data.txt"};
if (argc > 1) {
inputFilePath = argv[1];
}
std::cout << "reading "
<< inputFilePath << "..." << std::endl;
auto dv = ReadTable(inputFilePath);
std::cout << "... done" << std::endl
<< "number of records: " << dv.size() << std::endl;
//std::cout << dv << std::endl;
WriteTable(std::cout, dv);
return 0;
}

Related

C++ How to store numbers in a text file with contents of characters , numbers , and comma delimited in a 2D matrix

I am creating a C++ program that reading a text file with contents
San Jose, 2, 10 , 1<br/>
Sunnyvale, 2, 5, 4<br/>
Gilroy, 8, 4, 3<br/>
Oakland, 5, 8, 9<br/>
mountain View, 7, 5, 12<br/>
Santa Clara, 6, 4, 6<br/>
Fremont, 1, 2, 0<br/>
Belmont, 4, 9, 5<br/>
My attempt is to store all the numbers in a matrix (8x3). Here is my code
int main () {
vector <vector <string> > data;
ifstream infile( "test.txt" );
int data_row = 0;
while (infile)
{
string s;
if (!getline( infile, s )) break;
data_row++;
istringstream ss( s );
vector <string> record;
while (ss)
{
string s;
if (!getline( ss, s, ',' )) break;
record.push_back( s );
}
data_column = record.size() - 1;
data.push_back( record );
}
if (!infile.eof())
{
cerr << "Fooey!\n";
}
cout << data_row << " " << data_column << "\n";
data_type** m_value;
m_value = new data_type*[data_row];
for(int i=0;i<data_row;i++) {
m_value[i] = new data_type[data_column];
}
vector<string>myvector;
for (int i = 0; i < data.size(); i++) {
for (int j = 0; j < data[i].size(); j++) {
cout << i << "****" << j << " " << data[i][j] << "\n ";
if ( j != 0) {
myvector.push_back(data[i][j]);
}
}
}
for(int i=0;i<data_row;i++) {
for(int j=0;j< data_column;j++) {
for (int k = 0; k < myvector.size(); k++) {
cout << k << " " << myvector[k] << "\n";
m_value[i][j] = myvector[k];
}
}}
The program fails with getline.cpp:57:24: error: cannot convert
'std::basic_string' to 'int' in assignment
m_value[i][j] = myvector[k];
Please help me to resolve the problem
Thank you
std::stoi converts a string to an integer. If you are using decimal numbers use std::stod. That means string to double m_value[i][j] = std::stoi(myvector[k]);
Please go and eat/read a good book on C++
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
#include <vector>
#include <iterator>
template<typename T, std::size_t N>
std::size_t sizeof_array(T(&)[N])
{
return N;
}
struct record
{
std::string name;
int a;
int b;
int c;
};
std::istream& operator>>(std::istream &is, record &r)
{
record tmp;
std::getline(is, tmp.name, ',');
char ch;
int *dst[] = { &tmp.a, &tmp.b, &tmp.c };
for (std::size_t i{}; i < sizeof_array(dst); ++i)
{
if(!( is >> *dst[i] ))
return is;
if (i < sizeof_array(dst) - 1)
is >> ch;
}
while (is.peek() != '\n' && is.peek() != EOF)
is.get();
is.get();
r = tmp;
return is;
}
std::ostream& operator<<(std::ostream &os, record const &r)
{
os << r.name << '\t' << r.a << '\t' << r.b << '\t' << r.c;
return os;
}
int main()
{
constexpr char const *input_file_name{ "input.txt" };
std::ifstream input_file{ input_file_name };
if (!input_file) {
std::cerr << "Failed to open \"" << input_file_name << "\" for reading!\n\n";
return EXIT_FAILURE;
}
std::vector<record> data{ std::istream_iterator<record>{input_file}, std::istream_iterator<record>{} };
for (auto const &d : data)
std::cout << d << '\n';
}

Create the largest possible number from input - implementation issue with cout

I am trying to implement an algorithm that will take a set of numbers and output the largest possible number (without breaking up the individual numbers). So in an example like this where I give 4 numbers:
4
43 12 3 91
The output would be
91-43-3-12 or 9143312.
My attempt is below.
#include <algorithm>
#include <sstream>
#include <iostream>
#include <vector>
#include <string>
using std::vector;
using std::string;
bool compare (int x, int y) {
std::cout << "in func \n";
string a = std::to_string(x);
string b = std::to_string(y);
std::cout << a << " " << b << "\n";
std::cout << std::stoi(a.substr(0, 1)) << " " << std::stoi(b.substr(0, 1)) << "\n" ;
if (std::stoi(a.substr(0, 1)) < std::stoi(b.substr(0, 1))) {
std::cout.flush();
std::cout << "if \n";
return true;
}
else {
std::cout.flush();
std::cout <<"else \n";
return false;
}
}
string largest_number(vector<string> a) {
std::stringstream ret;
while (a.size() > 0) {
int maxNumber =-1;
int index = -1;
std::cout << "going into for " << a.size() << "\n";
for (size_t i = 0; i < a.size(); i++) {
if (! compare (stoi(a[i]), maxNumber ) ) { //stoi(a[i]) >= maxNumber) {
maxNumber = stoi(a[i]);
std::cout << maxNumber << " " << i << "\n";
index = i;
}
std::cout << "here \n";
}
ret << maxNumber;
a.erase(a.begin() + index);
}
string result;
ret >> result;
return result;
}
int main() {
int n;
std::cin >> n;
vector<string> a(n);
for (size_t i = 0; i < a.size(); i++) {
std::cin >> a[i];
}
std::cout << largest_number(a);
}
I do not understand what is wrong with my compare function. When I run it, say with this input:
$ g++ -pipe -O2 -std=c++14 largest_number.cpp -lm -o largest1
$ ./largest1.exe
4
4 23 1 45
going into for 4
in func
4 -1
It doesnt print the cout statements in the conditional if or else. How could this be possible? I even tried flushing. However, if I take the entire conditional out, put a cout statement and the return true or something, then it runs the program in entirety (although this is not the expected output).
I do not mind harsh criticism. What am I doing wrong here? Any advice will be appreciated.
Thanks in advance.
In this statement
std::cout << std::stoi(a.substr(0, 1)) << " " << std::stoi(b.substr(0, 1)) << "\n" ;
when b is equal to -1 the expression b.substr(0, 1) is equal to an object of type std::string that contains one character '-' that is the minus sign.
If to apply the standard function std::stoi to such a string then an exception will be thrown.
Consider the following code snippet
std::string s("-");
try
{
std::stoi(s);
}
catch (const std::exception &e)
{
std::cout << e.what() << std::endl;
}
Its output will be
invalid stoi argument
It seems what you need is just to sort the strings. For example
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main()
{
std::vector<std::string> v { "4", "23", "1", "45" };
auto cmp = [](const std::string &a, const std::string &b)
{
std::string::size_type i = 0, m = a.size();
std::string::size_type j = 0, n = b.size();
int result;
do
{
if (m < n)
{
result = a.compare(i, m, b, j, m);
j += m;
n -= m;
}
else
{
result = a.compare(i, n, b, j, n);
i += n;
m -= n;
}
} while (result == 0 && m && n);
return 0 < result;
};
std::sort(v.begin(), v.end(), cmp);
for (const auto &s : v) std::cout << s;
std::cout << std::endl;
return 0;
}
The output of the program will be
454231
Or for this set of numbers
std::vector<std::string> v{ "43", "12", "3", "91" };
the output will be
9143312
or for one more set of numbers
std::vector<std::string> v{ "93", "938" };
the output will be
93938

Creating/outputing a binary tree(not BST)

My code (below) works unless the required key isn't in the list yet (so if a node doesn't have a reference to its parent). It ignores the nodes and just makes a tree without them. How can I fix it? I'm thinking about just re-looping once all the keys are in and just keep adding and removing accordingly.
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <map>
struct Foo {
int data{0};
int left{-1};
int right{-1};
};
std::istream& operator>>(std::istream& in, Foo& ff) {
in >> ff.data >> ff.left >> ff.right;
return in;
}
struct Del {
template <class T>
void operator()(T* p) {
std::cout << "[deleted #" << (p ? p->data : 0) << "]\n";
delete p;
}
};
struct Bar {
int data{0};
std::unique_ptr<Bar, Del> lef;
std::unique_ptr<Bar, Del> rig;
};
void print(const std::unique_ptr<Bar, Del>& node) {
if (node) {
std::cout << ' ' << node->data;
print(node->lef);
print(node->rig);
}
}
int main() {
std::string input =
"101 1 3 102 2 8 104 6 7 103 -1 5 109 -1 -1 106 4 -1 107 -1 -1 108 -1 "
"-1 105 -1 -1";
std::istringstream IN(input);
std::map<int, std::pair<Bar*, bool>> mlist;
std::unique_ptr<Bar, Del> root;
int row = 0;
Foo entry;
while (IN >> entry) {
if (0 == row) {
root.reset(new Bar);
Bar* node = root.get();
node->data = entry.data;
std::cout << row << " [created #" << entry.data << ']';
if (0 <= entry.left)
mlist.emplace(entry.left, std::make_pair(node, true));
if (0 <= entry.right)
mlist.emplace(entry.right, std::make_pair(node, false));
} else {
auto it = mlist.find(row);
if (mlist.end() != it) {
if (it->second.second) {
it->second.first->lef.reset(new Bar);
Bar* node = it->second.first->lef.get();
node->data = entry.data;
std::cout << row << " [created #" << entry.data << ']';
if (0 <= entry.left)
mlist.emplace(entry.left, std::make_pair(node, true));
if (0 <= entry.right)
mlist.emplace(entry.right, std::make_pair(node, false));
mlist.erase(it);
} else {
it->second.first->rig.reset(new Bar);
Bar* node = it->second.first->rig.get();
node->data = entry.data;
std::cout << row << " [created #" << entry.data << ']';
if (0 <= entry.left)
mlist.emplace(entry.left, std::make_pair(node, true));
if (0 <= entry.right)
mlist.emplace(entry.right, std::make_pair(node, false));
mlist.erase(it);
}
// mlist.erase( it );
}
}
std::cout << " list size " << mlist.size() << '\n';
++row;
}
std::cout << "final list size " << mlist.size() << "\n\n";
print(root);
std::cout << "\n\n";
std::cout << "Lets see whats left in the list:";
return 0;
}
Actually, I just used a vector of nodes and it worked perfectly. Sorry for all the confusion!

copy member variable into byte vector

I want to copy a 64-bit member variable into a vector byte by byte.
Please avoid telling me to use bit operation to extract each byte and then copy them into vector.
I want to do this by one line.
I use memcpy and copy methods, but both of them failed.
Here is the sample code:
#include <iostream>
#include <vector>
#include <cstdint>
#include <cstring>
using namespace std;
class A {
public:
A()
: eight_bytes_data(0x1234567812345678) {
}
void Test() {
vector<uint8_t> data_out;
data_out.reserve(8);
memcpy(data_out.data(),
&eight_bytes_data,
8);
cerr << "[Test]" << data_out.size() << endl;
}
void Test2() {
vector<uint8_t> data_out;
data_out.reserve(8);
copy(&eight_bytes_data,
(&eight_bytes_data) + 8,
back_inserter(data_out));
cerr << "[Test2]" << data_out.size() << endl;
for (auto value : data_out) {
cerr << hex << value << endl;
}
}
private:
uint64_t eight_bytes_data;
};
int main() {
A a;
a.Test();
a.Test2();
return 0;
}
As the others already showed where you were getting wrong, there is a one line solution that is dangeurous.
First you need to make sure that you vector has enough size to receive 8 bytes. Something like this:
data_out.resize(8);
The you can do a reinterpret_cast to force your compiler to interpret those 8 bytes from the vector to be seen as an unique type of 8 bytes, and do the copy
*(reinterpret_cast<uint64_t*>(data_out.data())) = eight_bytes_data;
I can't figure out all the possibilities of something going wrong. So use at your own risk.
If you want to work with the bytes of another type structure, you could use a char* to manipulate each byte:
void Test3()
{
vector<uint8_t> data_out;
char* pbyte = (char*)&eight_bytes_data;
for(int i = 0; i < sizeof(eight_bytes_data); ++i)
{
data_out.push_back(pbyte[i]);
}
cerr << "[Test]" << data_out.size() << endl;
}
Unfortunately, you requested a one-line-solution, which I don't think is viable.
If you are interested in more generic version:
namespace detail
{
template<typename Byte, typename T>
struct Impl
{
static std::vector<Byte> impl(const T& data)
{
std::vector<Byte> bytes;
bytes.resize(sizeof(T)/sizeof(Byte));
*(T*)bytes.data() = data;
return bytes;
}
};
template<typename T>
struct Impl<bool, T>
{
static std::vector<bool> impl(const T& data)
{
std::bitset<sizeof(T)*8> bits(data);
std::string string = bits.to_string();
std::vector<bool> vector;
for(const auto& x : string)
vector.push_back(x - '0');
return vector;
}
};
}
template<typename Byte = uint8_t,
typename T>
std::vector<Byte> data_to_bytes(const T& data)
{
return detail::Impl<Byte,T>::impl(data);
}
int main()
{
uint64_t test = 0x1111222233334444ull;
for(auto x : data_to_bytes<bool>(test))
std::cout << std::hex << uintmax_t(x) << " ";
std::cout << std::endl << std::endl;
for(auto x : data_to_bytes(test))
std::cout << std::hex << uintmax_t(x) << " ";
std::cout << std::endl << std::endl;
for(auto x : data_to_bytes<uint16_t>(test))
std::cout << std::hex << uintmax_t(x) << " ";
std::cout << std::endl << std::endl;
for(auto x : data_to_bytes<uint32_t>(test))
std::cout << std::hex << uintmax_t(x) << " ";
std::cout << std::endl << std::endl;
for(auto x : data_to_bytes<uint64_t>(test))
std::cout << std::hex << uintmax_t(x) << " ";
std::cout << std::endl << std::endl;
}
Output:
0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1
0 0 0 1 0 0 0 1 0 0 0 1 0 0
44 44 33 33 22 22 11 11
4444 3333 2222 1111
33334444 11112222
1111222233334444

how can I find the sequence number (index) of word in such a paragraph c++?

I'm working on a project which needs to find the number of words and the indices of each word in the paragraph ...I have written the code which is counting the number of word in a string but I stuck with finding the indices of words,
such as : Hi John How are you I miss you ..
I need to print the indices like : 0 1 2 3 4 5 6 7
here is the code:
int _tmain(int argc, _TCHAR* argv[])
{
int count_words(std::string);
std::string input_text;
std::cout<< "Enter a text: ";
std::getline(std::cin,input_text);
int number_of_words=1;
int counter []={0};
for(int i = 0; i < input_text.length();i++)
if(input_text[i] == ' ')
number_of_words++;
std::cout << "Number of words: " << number_of_words << std::endl;
//std:: cout << number_of_words << std::endl;
system ("PAUSE");
}
Hopefully this helps. Edited to include use of count_words function.
#include <iostream>
#include <sstream>
void count_words(std::string);
int main(){
std::string input_text, output_text;
std::cout<< "Enter a text: ";
std::getline(std::cin,input_text);
count_words(input_text);
system ("PAUSE");
return 0; //MUST RETURN AN INTEGER VALUE FROM 'INT MAIN'
}
void count_words(std::string inputString){
std::string output_text;
std::stringstream indexes;
int number_of_words=0; //If there are no words, it would be false, make it 0.
//int counter []={0}; //This serves no purpose.
if(!inputString.empty()){// test to make sure it isn't empty.
number_of_words++;
for(int i = 0; i < inputString.length();i++){ // For loops should have curly braces {} containing their statement.
if(inputString[i] == ' '){
number_of_words++;
}
if((isalpha(inputString[i]))&&inputString[i-1]==' '){ //test for following space separated word
indexes << i << " ";
}
}
}
output_text = indexes.str(); //convert stringstream to string
std::cout << "Number of words: " << number_of_words << std::endl;
//std:: cout << number_of_words << std::endl; //duplicate info
std::cout << "Indexes: " << output_text << std::endl;
}
I'm not sure if i understand the question. You only need print the "indices"?? like this? (Using your own code)
#include <iostream>
#include <vector>
#include <string>
void stringTokenizer(const std::string& str, const std::string& delimiter, std::vector<std::string>& tokens) {
size_t prev = 0, next = 0, len;
while ((next = str.find(delimiter, prev)) != std::string::npos) {
len = next - prev;
if (len > 0) {
tokens.push_back(str.substr(prev, len));
}
prev = next + delimiter.size();
}
if (prev < str.size()) {
tokens.push_back(str.substr(prev));
}
}
int main()
{
std::vector <std::string> split;
std::string input_text;
std::cout<< "Enter a text: ";
std::getline(std::cin,input_text);
stringTokenizer(input_text, " ", split);
int number_of_words = 0;
for (std::vector<std::string>::iterator it = split.begin(); it != split.end(); it++, number_of_words++) {
std::cout << *it << " " << number_of_words << std::endl;
}
}