Вот готовая к использованию функция, если вам нужно всего лишь загрузить файл данных с удвоением (целые числа, текст).
#include <sstream>
#include <fstream>
#include <iterator>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
/**
* Parse a CSV data file and fill the 2d STL vector "data".
* Limits: only "pure datas" of doubles, not encapsulated by " and without \n inside.
* Further no formatting in the data (e.g. scientific notation)
* It however handles both dots and commas as decimal separators and removes thousand separator.
*
* returnCodes[0]: file access 0-> ok 1-> not able to read; 2-> decimal separator equal to comma separator
* returnCodes[1]: number of records
* returnCodes[2]: number of fields. -1 If rows have different field size
*
*/
vector<int>
readCsvData (vector <vector <double>>& data, const string& filename, const string& delimiter, const string& decseparator){
int vv[3] = { 0,0,0 };
vector<int> returnCodes(&vv[0], &vv[0]+3);
string rowstring, stringtoken;
double doubletoken;
int rowcount=0;
int fieldcount=0;
data.clear();
ifstream iFile(filename, ios_base::in);
if (!iFile.is_open()){
returnCodes[0] = 1;
return returnCodes;
}
while (getline(iFile, rowstring)) {
if (rowstring=="") continue; // empty line
rowcount ++; //let's start with 1
if(delimiter == decseparator){
returnCodes[0] = 2;
return returnCodes;
}
if(decseparator != "."){
// remove dots (used as thousand separators)
string::iterator end_pos = remove(rowstring.begin(), rowstring.end(), '.');
rowstring.erase(end_pos, rowstring.end());
// replace decimal separator with dots.
replace(rowstring.begin(), rowstring.end(),decseparator.c_str()[0], '.');
} else {
// remove commas (used as thousand separators)
string::iterator end_pos = remove(rowstring.begin(), rowstring.end(), ',');
rowstring.erase(end_pos, rowstring.end());
}
// tokenize..
vector<double> tokens;
// Skip delimiters at beginning.
string::size_type lastPos = rowstring.find_first_not_of(delimiter, 0);
// Find first "non-delimiter".
string::size_type pos = rowstring.find_first_of(delimiter, lastPos);
while (string::npos != pos || string::npos != lastPos){
// Found a token, convert it to double add it to the vector.
stringtoken = rowstring.substr(lastPos, pos - lastPos);
if (stringtoken == "") {
tokens.push_back(0.0);
} else {
istringstream totalSString(stringtoken);
totalSString >> doubletoken;
tokens.push_back(doubletoken);
}
// Skip delimiters. Note the "not_of"
lastPos = rowstring.find_first_not_of(delimiter, pos);
// Find next "non-delimiter"
pos = rowstring.find_first_of(delimiter, lastPos);
}
if(rowcount == 1){
fieldcount = tokens.size();
returnCodes[2] = tokens.size();
} else {
if ( tokens.size() != fieldcount){
returnCodes[2] = -1;
}
}
data.push_back(tokens);
}
iFile.close();
returnCodes[1] = rowcount;
return returnCodes;
}
Вы объявили свою структуру между (или, возможно, после) ваших объявлений f2
и f1
. Переместите объявление структуры так, чтобы оно стоит перед обоими объявлениями.
То есть:
struct user_data_s
{
int L;
};
void f2(struct user_data_s* data) {
printf("Number %i\n", data->L);
}
void f1(struct user_data_s* data) {
printf("Number %i\n", data->L);
f2(data);
}
компилируется без ошибок, но
void f2(struct user_data_s* data) {
printf("Number %i\n", data->L);
}
struct user_data_s
{
int L;
};
void f1(struct user_data_s* data) {
printf("Number %i\n", data->L);
f2(data);
}
не компилируется, потому что f2
не может узнать, что такое struct user_data_s
является.
Возможно, вы привыкли к программированию на языке более высокого уровня, который позволяет размещать ваши объявления / определения практически где угодно (например, C # или Python), но, к сожалению, C компилируется строго сверху вниз.
Компилятор уже дал вам довольно хорошее объяснение того, что происходит.
Вы не объявили struct user_data_s
заранее. Компилятор впервые видит struct user_data_s
в приведенных выше определениях функций. В каждом случае объявление struct user_data_s
имеет область видимости блока, т. Е. Локально для соответствующей функции. Это означает, что первое объявление struct user_data_s
в определении f1
полностью не связано со вторым объявлением struct user_data_s
в определении f2
. Эти объявления объявляют два совершенно разных локальных (для каждой функции) типа struct user_data_s
. Вы можете' t вызовите f2
из f1
, как в вашем примере, поскольку их типы параметров совершенно не связаны.
Обычно вы должны иметь struct user_data_s
, объявленную в области файла в заранее, вместо того, чтобы объявлять это в определении функции. Вы случайно не забыли включить заголовок в объявление struct user_data_s
?