I have data file of 36MB(each value in file is double type) residing on hard disk. My question is, when I read this file via c++ in RAM putting content in matrix (provided by boost library), does it going to occupy only 36MB of RAM or different? Am I running out of memory?
The reason is that I am on 64-bit ubuntu platform with 8 GB RAM and I am getting bad allocation error. The same file reading program works fine for small data files.
Below is snippet to load the (data real-sim )[https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary.html] . x and y are boost matrix and vector respectively declared as extern in .h file.
void load_data(const char* filename)
{
ifstream in(filename);
string line;
int line_num = 0;
if (in.is_open()) {
while (in.good()) {
getline(in, line);
if (line.empty()) continue;
int cat = 0;
if (!parse_line(line, cat, line_num)) {
cout << "parse line: " << line << ", failed.." << endl;
continue;
}
y(line_num) = cat;
line_num += 1;
}
in.close();
}
}
bool debug = false;
using namespace boost::numeric::ublas;
vector<double> y(no_records);
matrix<double> x(no_records,no_features);
using namespace std;
template < class T>
void convert_from_string(T& value, const string& s)
{
stringstream ss(s);
ss >> value;
}
int get_cat(const string& data) {
int c;
convert_from_string(c, data);
return c;
}
bool get_features(const string& data, int& index, double& value) {
int pos = data.find(":");
if (pos == -1) return false;
convert_from_string(index, data.substr(0, pos));
convert_from_string(value, data.substr(pos + 1));
return true;
}
bool parse_line(const string& line, int& cat, const int line_num) {
if (line.empty()) return false;
size_t start_pos = 0;
char space = ' ';
while (true) {
size_t pos = line.find(space, start_pos);
if ((int)pos != -1) {
string data = line.substr(start_pos, pos - start_pos);
if (!data.empty()) {
if (start_pos == 0) {
cat = get_cat(data);
}
else {
int index = -1;
double v = 0;
get_features(data, index, v);
if (debug)
cout << "index: " << index << "," << "value: " << v << endl;
if (index != -1) {
index -= 1; // index from 0
x(line_num, index) = v;
}
}
}
start_pos = pos + 1;
}
else {
string data = line.substr(start_pos, pos - start_pos);
if (!data.empty()) {
cout << "read data: " << data << endl;
int index = -1;
double v = 0;
get_features(data, index, v);
if (debug)
cout << "index: " << index << "," << "value: " << v << endl;
if (index != -1) {
index -= 1; // index from 0
x(line_num, index) = v;
}
}
break;
}
}
return true;
}
I found the culprit. The reason for bad allocation error was that I was running out of memory. The thing is that I was using dense matrix representation (as provided by boost library). As such, storing a matrix of size 20000x40000 as dense matrix in boost matrix representation will require RAM of size 6.4GB. Now, if one don't have that much space in RAM, bad allocation is going to pop-up.
Related
I am trying to print out the correct number of clock ticks and seconds after extracting data from a CVS file and then sorting the bid vector using the Selection Sort algorithm. Whenever I select option 1 to call the loadBids function, it prints:
12023 bids read
time: 1836 clock ticks
time: 1.836 seconds
Whenever I select option 3 to call the sortSelection function, it prints:
12023 bids sorted
time: 2520 clock ticks
time: 2.52 seconds
Option 1 should be printing numbers close to:
12023 bids read
time: 12023 clock ticks
time: 0.173945 seconds
Option 3 should be printing numbers close to:
12023 bids sorted
time: 10623604 clock ticks
time: 10.6236 seconds
Can someone help me with this? Here is my code:
VectorSorting.cpp
#include <algorithm>
#include <iostream>
#include <time.h>
#include "CSVparser.hpp"
using namespace std;
//============================================================================
// Global definitions visible to all methods and classes
//============================================================================
// forward declarations
double strToDouble(string str, char ch);
// define a structure to hold bid information
struct Bid {
string bidId; // unique identifier
string title;
string fund;
double amount;
Bid() {
amount = 0.0;
}
};
//============================================================================
// Static methods used for testing
//============================================================================
/**
* Display the bid information to the console (std::out)
*
* #param bid struct containing the bid info
*/
void displayBid(Bid bid) {
cout << bid.bidId << ": " << bid.title << " | " << bid.amount << " | "
<< bid.fund << endl;
return;
}
/**
* Prompt user for bid information using console (std::in)
*
* #return Bid struct containing the bid info
*/
Bid getBid() {
Bid bid;
cout << "Enter Id: ";
cin.ignore();
getline(cin, bid.bidId);
cout << "Enter title: ";
getline(cin, bid.title);
cout << "Enter fund: ";
cin >> bid.fund;
cout << "Enter amount: ";
cin.ignore();
string strAmount;
getline(cin, strAmount);
bid.amount = strToDouble(strAmount, '$');
return bid;
}
/**
* Load a CSV file containing bids into a container
*
* #param csvPath the path to the CSV file to load
* #return a container holding all the bids read
*/
vector<Bid> loadBids(string csvPath) {
cout << "Loading CSV file " << csvPath << endl;
// Define a vector data structure to hold a collection of bids.
vector<Bid> bids;
// initialize the CSV Parser using the given path
csv::Parser file = csv::Parser(csvPath);
try {
// loop to read rows of a CSV file
for (int i = 0; i < file.rowCount(); i++) {
// Create a data structure and add to the collection of bids
Bid bid;
bid.bidId = file[i][1];
bid.title = file[i][0];
bid.fund = file[i][8];
bid.amount = strToDouble(file[i][4], '$');
//cout << "Item: " << bid.title << ", Fund: " << bid.fund << ", Amount: " <<
bid.amount << endl;
// push this bid to the end
bids.push_back(bid);
}
} catch (csv::Error &e) {
std::cerr << e.what() << std::endl;
}
return bids;
}
// FIXME (2a): Implement the quick sort logic over bid.title
/**
* Partition the vector of bids into two parts, low and high
*
* #param bids Address of the vector<Bid> instance to be partitioned
* #param begin Beginning index to partition
* #param end Ending index to partition
*/
int partition(vector<Bid>& bids, int begin, int end) {
//set low and high equal to begin and end
int low = begin;
int high = end;
// pick the middle element as pivot point
int pivot = (begin + (end - begin) / 2);
// while not done
bool done = false;
while (bids[low].title.compare(bids[pivot].title) < 0) {
// keep incrementing low index while bids[low] < bids[pivot]
++low;
}
// keep decrementing high index while bids[pivot] < bids[high]
while (bids[pivot].title.compare(bids[high].title) < 0) {
--high;
}
/* If there are zero or one elements remaining,
all bids are partitioned. Return high */
// else swap the low and high bids (built in vector method)
// move low and high closer ++low, --high
//return high;
if (low >= high) {
done = true;
}
else {
swap(bids[low], bids[high]);
++low;
--high;
}
return high;
}
/**
* Perform a quick sort on bid title
* Average performance: O(n log(n))
* Worst case performance O(n^2))
*
* #param bids address of the vector<Bid> instance to be sorted
* #param begin the beginning index to sort on
* #param end the ending index to sort on
*/
void quickSort(vector<Bid>& bids, int begin, int end) {
//set mid equal to 0
/* Base case: If there are 1 or zero bids to sort,
partition is already sorted otherwise if begin is greater
than or equal to end then return*/
/* Partition bids into low and high such that
midpoint is location of last element in low */
// recursively sort low partition (begin to mid)
// recursively sort high partition (mid+1 to end)
}
// FIXME (1a): Implement the selection sort logic over bid.title
/**
* Perform a selection sort on bid title
* Average performance: O(n^2))
* Worst case performance O(n^2))
*
* #param bid address of the vector<Bid>
* instance to be sorted
*/
void selectionSort(vector<Bid>& bids) {
//define min as int (index of the current minimum bid)
int i, min;
// check size of bids vector
// set size_t platform-neutral result equal to bid.size()
size_t platform = bids.size();
// pos is the position within bids that divides sorted/unsorted
// for size_t pos = 0 and less than size -1
for (size_t pos = 0;pos < platform - 1; pos++) {
// set min = pos
min = pos;
// loop over remaining elements to the right of position
for (i=pos+1;i < platform; i++) {
// if this element's title is less than minimum title
if (&bids[i] < &bids[min]) {
// this element becomes the minimum
min = i;
}
}
if (min != pos) {
// swap the current minimum with smaller one found
// swap is a built in vector method
swap(bids[pos], bids[min]);
}
}
}
/**
* Simple C function to convert a string to a double
* after stripping out unwanted char
*
* credit: http://stackoverflow.com/a/24875936
*
* #param ch The character to strip out
*/
double strToDouble(string str, char ch) {
str.erase(remove(str.begin(), str.end(), ch), str.end());
return atof(str.c_str());
}
/**
* The one and only main() method
*/
int main(int argc, char* argv[]) {
// process command line arguments
string csvPath;
switch (argc) {
case 2:
csvPath = argv[1];
break;
default:
csvPath = "eBid_Monthly_Sales.csv";
}
// Define a vector to hold all the bids
vector<Bid> bids;
// Define a timer variable
clock_t ticks;
int choice = 0;
while (choice != 9) {
cout << "Menu:" << endl;
cout << " 1. Load Bids" << endl;
cout << " 2. Display All Bids" << endl;
cout << " 3. Selection Sort All Bids" << endl;
cout << " 4. Quick Sort All Bids" << endl;
cout << " 9. Exit" << endl;
cout << "Enter choice: ";
cin >> choice;
switch (choice) {
case 1:
// Initialize a timer variable before loading bids
ticks = clock();
// Complete the method call to load the bids
bids = loadBids(csvPath);
cout << bids.size() << " bids read" << endl;
// Calculate elapsed time and display result
ticks = clock() - ticks; // current clock ticks minus starting clock ticks
cout << "time: " << ticks << " clock ticks" << endl;
cout << "time: " << ticks * 1.0 / CLOCKS_PER_SEC << " seconds" << endl;
break;
case 2:
// Loop and display the bids read
for (int i = 0; i < bids.size(); ++i) {
displayBid(bids[i]);
}
cout << endl;
break;
case 3:
// Initialize a timer variable before loading bids
ticks = clock();
bids = loadBids(csvPath);
// FIXME (1b): Invoke the selection sort and report timing results
selectionSort(bids);
cout << bids.size() << " bids sorted" << endl;
// Calculate elapsed time and display result
ticks = clock() - ticks; // current clock ticks minus starting clock ticks
cout << "time: " << ticks << " clock ticks" << endl;
cout << "time: " << (ticks * 1.0) / CLOCKS_PER_SEC << " seconds" << endl;
break;
// FIXME (2b): Invoke the quick sort and report timing results
}
}
cout << "Good bye." << endl;
return 0;
}
CSVparser.cpp
#include <fstream>
#include <sstream>
#include <iomanip>
#include "CSVparser.hpp"
namespace csv {
Parser::Parser(const std::string &data, const DataType &type, char
sep)
: _type(type), _sep(sep)
{
std::string line;
if (type == eFILE)
{
_file = data;
std::ifstream ifile(_file.c_str());
if (ifile.is_open())
{
while (ifile.good())
{
getline(ifile, line);
if (line != "")
_originalFile.push_back(line);
}
ifile.close();
if (_originalFile.size() == 0)
throw Error(std::string("No Data in ").append(_file));
parseHeader();
parseContent();
}
else
throw Error(std::string("Failed to open ").append(_file));
}
else
{
std::istringstream stream(data);
while (std::getline(stream, line))
if (line != "")
_originalFile.push_back(line);
if (_originalFile.size() == 0)
throw Error(std::string("No Data in pure content"));
parseHeader();
parseContent();
}
}
Parser::~Parser(void)
{
std::vector<Row *>::iterator it;
for (it = _content.begin(); it != _content.end(); it++)
delete *it;
}
void Parser::parseHeader(void)
{
std::stringstream ss(_originalFile[0]);
std::string item;
while (std::getline(ss, item, _sep))
_header.push_back(item);
}
void Parser::parseContent(void)
{
std::vector<std::string>::iterator it;
it = _originalFile.begin();
it++; // skip header
for (; it != _originalFile.end(); it++)
{
bool quoted = false;
int tokenStart = 0;
unsigned int i = 0;
Row *row = new Row(_header);
for (; i != it->length(); i++)
{
if (it->at(i) == '"')
quoted = ((quoted) ? (false) : (true));
else if (it->at(i) == ',' && !quoted)
{
row->push(it->substr(tokenStart, i - tokenStart));
tokenStart = i + 1;
}
}
//end
row->push(it->substr(tokenStart, it->length() - tokenStart));
// if value(s) missing
if (row->size() != _header.size())
throw Error("corrupted data !");
_content.push_back(row);
}
}
Row &Parser::getRow(unsigned int rowPosition) const
{
if (rowPosition < _content.size())
return *(_content[rowPosition]);
throw Error("can't return this row (doesn't exist)");
}
Row &Parser::operator[](unsigned int rowPosition) const
{
return Parser::getRow(rowPosition);
}
unsigned int Parser::rowCount(void) const
{
return _content.size();
}
unsigned int Parser::columnCount(void) const
{
return _header.size();
}
std::vector<std::string> Parser::getHeader(void) const
{
return _header;
}
const std::string Parser::getHeaderElement(unsigned int pos) const
{
if (pos >= _header.size())
throw Error("can't return this header (doesn't exist)");
return _header[pos];
}
bool Parser::deleteRow(unsigned int pos)
{
if (pos < _content.size())
{
delete *(_content.begin() + pos);
_content.erase(_content.begin() + pos);
return true;
}
return false;
}
bool Parser::addRow(unsigned int pos, const
std::vector<std::string> &r)
{
Row *row = new Row(_header);
for (auto it = r.begin(); it != r.end(); it++)
row->push(*it);
if (pos <= _content.size())
{
_content.insert(_content.begin() + pos, row);
return true;
}
return false;
}
void Parser::sync(void) const
{
if (_type == DataType::eFILE)
{
std::ofstream f;
f.open(_file, std::ios::out | std::ios::trunc);
// header
unsigned int i = 0;
for (auto it = _header.begin(); it != _header.end(); it++)
{
f << *it;
if (i < _header.size() - 1)
f << ",";
else
f << std::endl;
i++;
}
for (auto it = _content.begin(); it != _content.end(); it++)
f << **it << std::endl;
f.close();
}
}
const std::string &Parser::getFileName(void) const
{
return _file;
}
/*
** ROW
*/
Row::Row(const std::vector<std::string> &header)
: _header(header) {}
Row::~Row(void) {}
unsigned int Row::size(void) const
{
return _values.size();
}
void Row::push(const std::string &value)
{
_values.push_back(value);
}
bool Row::set(const std::string &key, const std::string &value)
{
std::vector<std::string>::const_iterator it;
int pos = 0;
for (it = _header.begin(); it != _header.end(); it++)
{
if (key == *it)
{
_values[pos] = value;
return true;
}
pos++;
}
return false;
}
const std::string Row::operator[](unsigned int valuePosition) const
{
if (valuePosition < _values.size())
return _values[valuePosition];
throw Error("can't return this value (doesn't exist)");
}
const std::string Row::operator[](const std::string &key) const
{
std::vector<std::string>::const_iterator it;
int pos = 0;
for (it = _header.begin(); it != _header.end(); it++)
{
if (key == *it)
return _values[pos];
pos++;
}
throw Error("can't return this value (doesn't exist)");
}
std::ostream &operator<<(std::ostream &os, const Row &row)
{
for (unsigned int i = 0; i != row._values.size(); i++)
os << row._values[i] << " | ";
return os;
}
std::ofstream &operator<<(std::ofstream &os, const Row &row)
{
for (unsigned int i = 0; i != row._values.size(); i++)
{
os << row._values[i];
if (i < row._values.size() - 1)
os << ",";
}
return os;
}
}
CSVparser.hpp
#ifndef _CSVPARSER_HPP_
# define _CSVPARSER_HPP_
# include <stdexcept>
# include <string>
# include <vector>
# include <list>
# include <sstream>
namespace csv
{
class Error : public std::runtime_error
{
public:
Error(const std::string &msg):
std::runtime_error(std::string("CSVparser : ").append(msg))
{
}
};
class Row
{
public:
Row(const std::vector<std::string> &);
~Row(void);
public:
unsigned int size(void) const;
void push(const std::string &);
bool set(const std::string &, const std::string &);
private:
const std::vector<std::string> _header;
std::vector<std::string> _values;
public:
template<typename T>
const T getValue(unsigned int pos) const
{
if (pos < _values.size())
{
T res;
std::stringstream ss;
ss << _values[pos];
ss >> res;
return res;
}
throw Error("can't return this value (doesn't exist)");
}
const std::string operator[](unsigned int) const;
const std::string operator[](const std::string &valueName)
const;
friend std::ostream& operator<<(std::ostream& os, const Row
&row);
friend std::ofstream& operator<<(std::ofstream& os, const
Row &row);
};
enum DataType {
eFILE = 0,
ePURE = 1
};
class Parser
{
public:
Parser(const std::string &, const DataType &type = eFILE, char
sep = ',');
~Parser(void);
public:
Row &getRow(unsigned int row) const;
unsigned int rowCount(void) const;
unsigned int columnCount(void) const;
std::vector<std::string> getHeader(void) const;
const std::string getHeaderElement(unsigned int pos) const;
const std::string &getFileName(void) const;
public:
bool deleteRow(unsigned int row);
bool addRow(unsigned int pos, const std::vector<std::string>
&);
void sync(void) const;
protected:
void parseHeader(void);
void parseContent(void);
private:
std::string _file;
const DataType _type;
const char _sep;
std::vector<std::string> _originalFile;
std::vector<std::string> _header;
std::vector<Row *> _content;
public:
Row &operator[](unsigned int row) const;
};
}
#endif /*!_CSVPARSER_HPP_*/
I am getting an error in Visual Studio 2019 in my C++ program. I have a function prototype defined in a header file called "Header.h" with a return type of class myMatrix. I have the function definition in a file called "Fuctions.cpp". My problem is that I get a compile error stating "cannot overload functions distinguished by return type alone". However, the return type is the exact same in both the function prototype as well as in the function definition. Below are my complete "Header.h" and "Functions.cpp" files in case my mistake lies elsewhere in my code. I tried looking for hours for similar problems to mine here in stack overflow but I could not find any relevant answers. I also copied the function prototype and pasted that at the top of my function definition, so I know that it's not a silly typo that's causing the problem. I looked at potential problems like missing semicolons and stuff like that and I could not find the source of the problem. Any help would be greatly appreciated.
Header.h file
#pragma once
#include <iostream>
#include <Eigen/Dense>
#include <fstream>
#include <sstream>
#include <vector>
using namespace Eigen;
// utilities
bool is_number(const std::string& str);
unsigned int countWords(const std::string& str);
// functions for reading data in
void readGeneral(const std::string& filename, std::vector<std::string>& vec);
myMatrix read2Mat(const std::string& filename, unsigned int mode);
// class used to be able to store strings alongside doubles in a quasi-matrix data structure
class myMatrix {
// values stores the values, while ids0 and ids1 give us the possibility to store any string id columns
// NOTE: vectors "ids0" and "ids1" are not mandatory
private:
MatrixXd values;
std::vector<std::string> ids0, ids1;
public:
// class constructor
// if no third parameter is passed, only values is given a size
// if third parameter is 1, values and ids0 are given a size
// if third parameter is 2, values; ids0; and ids1 are given a size
myMatrix(const unsigned int& n, const unsigned int& m, unsigned int mode = 0) {
if (mode == 0) {
values.resize(n, m);
}
else if (mode == 1) {
values.resize(n, m);
ids0.resize(n);
}
else if (mode == 2) {
values.resize(n, m);
ids0.resize(n);
ids1.resize(n);
}
}
// copy constructor (shallow copy of class)
// could make it a deep copy but unnecessary because my class values are not pointers
myMatrix(const myMatrix& other)
: values(other.values), ids0(other.ids0), ids1(other.ids1)
{
}
// allows access to the values inside "MatrixXd values" by simply using the parenthesis operator
double& operator()(const unsigned int& row, const unsigned int& col); // for normal objects
double operator()(const unsigned int& row, const unsigned int& col) const; // for const objects
// allows access to the string vector id0
std::string& ref0(const unsigned int& i) {
return ids0[i];
}
std::string ref0(const unsigned int& i) const{
return ids0[i];
}
// allows access to the string vector id1
std::string& ref1(const unsigned int& i) {
return ids0[i];
}
std::string ref1(const unsigned int& i) const{
return ids0[i];
}
// member function that prints out the existing variables within the class
void print() {
if (ids0.empty()) {
std::cout << "myMatrix values: " << std::endl << values << "\n\n";
}
else if (ids1.empty()) {
std::cout << "myMatrix values: " << std::endl << values << "\n\n";
for (auto& str : ids0)
std::cout << "myMatrix idos0: " << str << " ";
std::cout << "\n\n";
}
else {
std::cout << "myMatrix values: " << std::endl << values << "\n\n";
for (auto& str : ids0)
std::cout << "myMatrix idos0: " << str << " ";
std::cout << "\n\n";
for (auto& str : ids1)
std::cout << "myMatrix idos1: " << str << " ";
std::cout << "\n\n";
}
return;
}
};
Functions.cpp file
#include "Header.h"
// reads string data from a file into a vector of strings passed by reference
// each line from the file is a string in the resulting vector
void readGeneral(const std::string& filename, std::vector<std::string>& vec) {
// variables needed
std::string line;
// opening filestream
std::fstream file_in(filename, std::ios_base::in);
// checking if file opened correctly
if (file_in.is_open()) {
// read all values in file
while (std::getline(file_in, line)) {
vec.push_back(line);
}
// close the file
file_in.close();
return;
}
// error handling if file was not opened correctly
else {
throw "Error Opening File in readCoords2D\n";
}
}
// reads string data from a file into a MatrixXd and returns it
// converts any non-numerical data into its ASCII equivalent value
myMatrix read2Mat(const std::string& filename, unsigned int mode) {
// if mode is set to 0, we are reading information from a matrix with no ids
if (mode == 0) {
// read data from file into vector
std::vector<std::string> vec;
readGeneral(filename, vec);
// read data from vector into MatrixXd
// rows - size of vec
// cols - # of words in the first string of vector vec
myMatrix mat(vec.size(), countWords(vec[0]));
std::string word;
unsigned int j = 0;
for (unsigned int i = 0; i < vec.size(); i++) {
j = 0;
std::stringstream stream(vec[i]);
while (stream >> word) {
if (is_number(word)) {
mat(i, j) = stod(word);
}
else {
throw "Error in read2Mat function mode 0. A value in the file is not of numerical type";
}
j++;
}
}
return mat;
}
// if mode is set to 1, we are reading information from a matrix where the first column is a column of ids
else if (mode == 1) {
// read data from file into vector
std::vector<std::string> vec;
readGeneral(filename, vec);
// read data from vector into MatrixXd
// rows - size of vec
// cols - # of words in the first string of vector vec
myMatrix mat(vec.size(), countWords(vec[0]) - 1, 1);
std::string word;
unsigned int j = 0;
for (unsigned int i = 0; i < vec.size(); i++) {
j = 0;
std::stringstream stream(vec[i]);
while (stream >> word) {
if (j == 0) {
mat.ref0(i) = word;
}
else if (j != 0 && is_number(word)) {
mat(i, j - 1) = stod(word);
}
else {
throw "Error in read2Mat function mode 1. A value not in the first column is of string type";
}
j++;
}
}
return mat;
}
// if mode is set to 1, we are reading information from a matrix where the first column is a column of ids
else if (mode == 2) {
// read data from file into vector
std::vector<std::string> vec;
readGeneral(filename, vec);
// read data from vector into MatrixXd
// rows - size of vec
// cols - # of words in the first string of vector vec
myMatrix mat(vec.size(), countWords(vec[0]) - 2, 1);
std::string word;
unsigned int j = 0;
for (unsigned int i = 0; i < vec.size(); i++) {
j = 0;
std::stringstream stream(vec[i]);
while (stream >> word) {
if (j == 0) {
mat.ref0(i) = word;
}
else if (j == 1) {
mat.ref1(i) = word;
}
else if (j != 0 && is_number(word)) {
mat(i, j - 1) = stod(word);
}
else {
throw "Error in read2Mat function mode 1. A value not in the first column is of string type";
}
j++;
}
}
return mat;
}
}
// checks if a string is a valid double
// (fails if there is a single character that is not 0-9, ., or +-)
// (passes if there is whitespace at the front, but fails if it is at the end)
bool is_number(const std::string& str) {
char* end = nullptr;
double val = strtod(str.data(), &end);
return end != str.c_str() && *end == '\0' && val != HUGE_VAL;
}
// counts how many words there are in a string
unsigned int countWords(const std::string& str) {
std::stringstream stream(str);
std::string word;
unsigned int counter = 0;
while (stream >> word) {
counter++;
}
return counter;
}
// returns the value at row i and column j in "MatrixXd values" by using the parenthesis operator
// overloaded for normal and const objects
double& myMatrix::operator()(const unsigned int& i, const unsigned int& j) {
return values(i, j);
}
double myMatrix::operator()(const unsigned int& i, const unsigned int& j) const {
return values(i, j);
}
I got a task in which I receive babies' firstname and weight in kilogram in a character array (for example: Johnny, 2 kg). I must store them in an array that can hold maximum 1000 elements and must be a struct type, storing the baby's firstname and weight.
Every actions must be done in functions - however, when I tried to get the name until the comma, str.copy() didn't work for me. Its specific problem was something with the last parameter, the position. Could someone help me out with that? Also, I'm kinda new to C++ and imagining how to separately, in two functions ask in the char arrays until empty line and do the copying in the other... if someone could help me out, I'd be grateful for that ^^'
Thanks for the help in advance!
#include<iostream>
#include<string>
#define M 1000
struct baby{
std::string baby_name;
float weight;
};
int readIn(baby* baby_datapair, int max);
// int maxWeight(baby* baby_datapair);
// int minWeight(baby* baby_datapair);
// void descendingOrder(baby* baby_datapair, int num);
int main(){
baby baby_array[M];
int n = readIn(baby_array, M);
return 0;
}
int readIn(baby* baby_datapair, int max){
int n = 0;
char name[12];
while (n < max){
std::cout << "Baby" << n+1 << "'s datas (Nickname, weight in kg): ";
std::getline(std::cin, name);
//~ std::cin.ignore(1);
if (neve == ""){
std::cout << "Wrong input!\n";
break;
}else{
std::size_t pos = name.find(',');
std::size_t until = name.copy(baby_datapair[n].baby_name, 0, pos);
}
n++;
}
return n;
}
// int maxWeight(baby* baby_datapair){
// }
// int minWeight(baby* baby_datapair){
// }
// void descendingOrder(baby* baby_datapair, int num){
// }
You must use std::string name; instead of char name[12]; as std::getline 's parameter. BTW, It make better for memory management. After input data, check pos value for valid value.
#include<iostream>
#include<string>
#define M 1000
struct baby {
std::string baby_name;
float weight;
};
int readIn(baby* baby_datapair, int max);
// int maxWeight(baby* baby_datapair);
// int minWeight(baby* baby_datapair);
// void descendingOrder(baby* baby_datapair, int num);
int main() {
baby baby_array[M];
int n = readIn(baby_array, M);
return 0;
}
int readIn(baby* baby_datapair, int max) {
int n = 0;
//char name[12];
std::string name;
while (n < max) {
std::cout << "Baby" << n + 1 << "'s datas (Nickname, weight in kg): ";
std::getline(std::cin, name);
//~ std::cin.ignore(1);
if (name == "") {
std::cout << "Wrong input!\n";
break;
}
else {
std::size_t pos = name.find(',');
if (pos <= 0) {
std::cout << "Invalid input structure!\n";
continue;
}
//std::size_t until = name.copy(baby_datapair[n].baby_name, 0, pos);
baby_datapair[n].baby_name = name.substr(0, pos);
baby_datapair[n].weight =(float)atof(name.substr(pos+1).c_str());
//std::cout << std::endl;
//std::cout << baby_datapair[n].baby_name;
//std::cout << ", " << baby_datapair[n].weight;
}
n++;
}
return n;
}
// int maxWeight(baby* baby_datapair){
// }
// int minWeight(baby* baby_datapair){
// }
// void descendingOrder(baby* baby_datapair, int num){
// }
You are taking it the wrong size. You should not try to copy to, but just copy from. BTW, name must be a std::string for you program to compile, and you should check for possible end of file. So a minally fixed version could be:
std::string name;
while (n < max) {
std::cout << "Baby" << n + 1 << "'s datas (Nickname, weight in kg): ";
std::getline(std::cin, name);
//~ std::cin.ignore(1);
if ((! std::cin) || name == "") {
std::cout << "Wrong input!\n";
break;
}
else {
std::size_t pos = name.find(',');
baby_datapair[n].baby_name = std::string(name.c_str(), pos);
baby_datapair[n].weight = strtof(name.c_str() + pos + 1, nullptr);
}
But using a std::stringstream would be more idiomatic in C++. Above code is rather C-ish...
I'm reading a file into a vector, to read bytes off of it. The standalone function works fine, but I don't want to open and close a file and create a vector every time i access, since im going to be grabbing lots of bytes. So I opted to put it in a file class. However, this has lead to me getting entirely different results when I use the file class.
This is a working standalone function:
template<class T>
T readFromNewFile(std::string path, size_t size = 0, uint offset = 0)
{
std::ifstream in(path.c_str(), std::ios::binary | std::ios::ate);
if (in.is_open())
{
std::streamoff max = in.tellg();
size_t _size = size == 0 ? (size_t)max : size;
in.seekg(offset, std::ios::beg);
std::vector<uint> v(_size);
in.read((char*)v.data(), _size);
uint temp = 0;
std::stringstream ss;
for (uint it = 0; it < v.size(); it++)
{
std::cout << "readFromNewFile: Adding offset: " << offset + it << ", with value: " << v[it] << "\n";
temp += v[it];
}
ss << temp;
T myVar;
ss >> myVar;
return myVar;
}
return T();
}
The file class in question:
class File
{
public:
File() {}
File(std::string path)
{
LOAD(path);
}
~File() {}
void LOAD(std::string path)
{
std::ifstream in(path.c_str(), std::ios::binary | std::ios::ate);
if (in.is_open())
{
std::streamoff max = in.tellg();
size_t _size = (size_t)max;
in.seekg(0, std::ios::beg);
data.clear();
data.resize(_size);
in.read((char*)data.data(), _size);
}
}
template<class T>
T readFromVector(size_t size = 0, uint offset = 0)
{
uint temp = 0;
std::stringstream ss;
for (uint it = offset; it < (offset + size) && it < data.size(); it++)
{
std::cout << "readFromVector: reading offset: " << it << ", with value: " << data[it] << "\n";
temp += data[it];
}
ss << temp;
T myVar;
ss >> myVar;
return myVar;
}
private:
std::vector<uint> data;
};
The code is all called in this block:
bool ArmourManager::init()
{
std::string armourFile = "resources\\armor.am_dat";
Offsets::ArmourOffsets offsets;
data.LOAD(armourFile); // data is a File object in ArmourManager class
uint armourOffset = 0x0A;
uint textOffset = 0x41C06;
// armours start at offset 0x0A, increase by 0x3C for every armour in file
// appears to end at 187390 ? 0x2DBFE
//std::cout << "[OFFSET]\t[IDX]\t[RAR]\t[SLOT]\t[DEF]\t[SLOTS]\n";
while (armourOffset < 0x2DBFE)
{
uint ind = SetMaker::readFromNewFile<uint>(armourFile, 4, armourOffset + offsets.Index);
uint x = data.readFromVector<uint>(4, armourOffset + offsets.Index);
std::cout << ind << " / " << x << "\n";
Console Output Here
From what i can tell with debugging, the data vector isn't being populated correctly, it's being filled with weird data.
Checking first index of both vectors
Even when I tried something like this,
std::vector<uint> x(_size);
in.read((char*)x.data(), _size);
std::cout << "x byte 0: " << x[0] << "\n";
the result is still the exact same.
So now looking at line 2, Cow- DNA Sequence; this continues on line 13 and 24 and ... I want to get this long sequence for each sequences ignoring the white space and new line in between.
This is the format of the file: 1
This is the code, which reads the first 10 sequences only
ifstream file ("txt");
string line;
vector <string> vec;
stringstream s;
string name;
string strip(string & s)
{
size_t b = s.find_first_not_of(' ');
size_t e = s.find_last_not_of(' ');
if (b == string::npos) {
return "";
} else {
return s.substr(b, e - b + 1);
}
}
void getSequence(){
int i;
int row;
int col;
if (file.is_open())
{
file >> row >> col;
for (i = 0; i < row; i++) {
vec.push_back("");
}
i = 0;
while (getline(file, line))
{
file >> name;
if (line == " ")
{
continue;
}
vec[i % row] += strip(line);
i++;
}
}
else {
cerr << "Error: file did not open!" << endl;
}
for (const string & v : vec) {
cout << v << endl;
}
}
Thank you in advance for your help.
Perhaps this will help a bit. The idea is to read the row & col then read the header line for the number of rows. After that repeatedly read the next chunk of lines and append each to the correct item assuming the lines are interleaved.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
struct Sequence
{
std::string name;
std::string data;
};
using SeqVec = std::vector<Sequence>;
bool readHeader(std::ifstream& f, SeqVec& v)
{
for (size_t i = 0; i < v.size(); ++i)
{
if (!(f >> v[i].name >> v[i].data))
{
return false;
}
}
return true;
}
int readChunk(std::ifstream& f, SeqVec& v)
{
int linesRead = 0;
std::string chunk;
for (size_t i = 0; i < v.size(); ++i)
{
if(!(f >> chunk))
{
break;
}
v[i].data += chunk;
++linesRead;
}
return linesRead;
}
int main()
{
std::vector<Sequence> v;
const std::string filename = "test.txt";
std::ifstream f(filename);
if (!f)
{
return -1;
}
int row;
int col;
if (f >> row >> col)
{
v.resize(row);
if (!readHeader(f, v))
{
return -1;
}
for (;;)
{
int linesRead = readChunk(f, v);
if (linesRead == 0 && v[0].data.size() == col)
{
//If we read nothing and the lines are the correct length we're done.
break;
}
else if (linesRead < v.size())
{
//partial read is an error.
return -1;
}
}
}
for (auto& seq : v)
{
std::cout << seq.name << " : " << seq.data << "\n";
}
return 0;
}