#c
Вопрос:
У меня есть текстовый файл с номером под названием InputFile.txt. Файл выглядит так:
10.5 73.5 109.5 87 45 108 66 117 34.5 13.5 60 97.5 138 63 130.5 4.5 40.5 43.5 60 18
Я хочу прочитать этот файл и вставить каждое отдельное число в качестве элемента массива arr. Я знаю, что то, что у меня есть, не пытается добавить элементы в массив, но я не уверен, как бы я даже подошел к этому. Любой совет был бы очень признателен.
int main(int argc, char* argv[]) {
float array[20];
ifstream file("InputFile.txt");
}
Комментарии:
1. Я думаю, что ваш следующий шаг-преобразование строки в плавающую.
2. Вы читаете файл, так почему же вы используете выходной поток
ostringstream
? Разве вы не должны использоватьgetline
иistringstream
?3. Я совершенно забыл о преобразовании строки в float, но я думаю, что было бы лучше всего сделать это после того, как она окажется в массиве.
4. Вы уверены, что всегда будет меньше 20 значений?
5. @PaulMcKenzie На данный момент я уверен, что всегда будет 20 ценностей. В будущем я хотел бы иметь возможность делать это без указания количества значений.
Ответ №1:
Вот один из способов сделать это, хотя и немного продвинутый.
Следующие std::copy
способы использования std::istream_iterator<float>
. Обратите внимание на использование вектора для гибкости:
#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
int main(int argc, char* argv[])
{
std::vector<float> values;
std::ifstream file("InputFile.txt");
// read the input
std::copy(std::istream_iterator<float>(file),
std::istream_iterator<float>(), std::back_inserter(values));
// print out the results of the input read
for (auto f : values)
std::cout << f << "n";
}
Ответ №2:
Я дал 2 решения этой проблемы. Приведенная ниже программа читает double
из input.txt и если в файле есть какая-то недопустимая запись string
, допустим, она есть, то она пропустит эту строку и прочитает следующее значение, и только если это значение допустимо ( double
), оно поместит его в массив, как вы хотите.
Решение 1. Использование встроенных массивов
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
int main()
{
std::string line;
std::ifstream inFile("input.txt");
//in case of using array, size must be fixed and predetermined
double arr[20] = {0.0}; //you can choose size according to your needs
if(inFile)
{
double i = 0;//this variable will be used to add element into the array
int count = 0;
while(getline(inFile, line, 'n'))
{
std::istringstream s(line);
//take input(from s to i) and then checks stream's eof flag status
while(s >> i || !s.eof()) {
//check if either failbit or badbit is set
if(s.fail())
{
//clear the error state to allow further operations on s
s.clear();
std::string temp;
s >> temp;
continue;
}
else
{
arr[count] = i;
count;
//break out of the loop so that we don't go out of bounds
if(count >= 20)
{
break;
}
}
}
}
}
else
{
std::cout<<"file could not be read"<<std::endl;
}
inFile.close();
for(double i: arr)
{
std::cout<<"elem: "<<i<<std::endl;
}
return 0;
}
Результаты решения 1 можно проверить здесь.
Решение 2: Использование std::vector
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
int main()
{
std::string line;;
std::ifstream inFile("input.txt");
std::vector<double> vec;
if(inFile)
{
double i = 0;//this variable will be used to add element into the vector
while(getline(inFile, line, 'n'))
{
std::istringstream s(line);
//take input(from s to i) and then checks stream's eof flag status
while(s >> i || !s.eof()) {
if(s.fail())
{
//clear the error state to allow further operations on s
s.clear();
std::string temp;
s >> temp;
continue;
}
else
{
vec.push_back(i);
}
}
}
}
else
{
std::cout<<"file could not be read"<<std::endl;
}
inFile.close();
for(double i: vec)
{
std::cout<<"elem: "<<i<<std::endl;
}
return 0;
}
Результат решения 2 можно увидеть здесь.
Обе эти версии работают, даже если в файле есть недопустимый ввод(например, строка). input.txt файл. Как вы можете видеть здесь, input.txt файл содержит строки между числами. Программа просто пропускает эти неверные данные и читает следующее. И если следующая вещь двойная, она помещает эту вещь/значение в вектор/массив.
Важное Примечание
Преимущество использования std::vector
над встроенным массивом(в данном случае) заключается в том, что вам не нужно заранее знать размер вектора. Так что это предпочтительнее, потому что вы не знаете, сколько целых чисел в input.txt файл. std::vector
может справиться с этим правильно/динамически. Но при использовании встроенных массивов вы должны заранее знать/указывать размер массива. Это, в свою очередь, означает, что вы должны заранее знать, сколько целых чисел в input.txt, что непрактично.
Комментарии:
1. Спасибо за помощь
2. @ДжонБертон, не за что. Можете ли вы отметить этот ответ(или любой другой) как правильный, если он вам помог?
Ответ №3:
Если вам нужно использовать массив поплавков, вы можете использовать менее продвинутый подход, чтобы прочитать строку в строку, создать поток строк из строки, а затем извлечь поплавки из потока строк.
Используя POA (обычный старый массив), вы несете ответственность за то, чтобы не писать за пределами массива. Чтобы убедиться, что вы не пытаетесь записать в массив больше элементов, чем он может вместить, просто сохраните счетчик, который вы можете использовать как для индексации массива, так и для проверки максимального количества элементов, которые может вместить массив.
Коротким примером может быть:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#define MAXF 20 /* if you need a constant, #define one (or more) */
int main (int argc, char **argv) {
std::ifstream file;
std::string str{};
float array[MAXF] = {0};
if (argc < 1) { /* validate filename provided as argument */
std::cout << "usage: ./prog file with space separated floatsn";
return 1;
}
file.open (argv[1]); /* open file */
if (!file.is_open()) { /* validate file is open for reading */
std::cerr << "error: file open failed.n";
return 1;
}
while (getline (file, str)) { /* read each line */
std::istringstream iss (str); /* create stringstream */
float f;
size_t nfloats = 0; /* count of no. of floats */
while (nfloats < MAXF amp;amp; iss >> f) { /* protect bound, get float */
array[nfloats ] = f; /* add float to array */
}
for (size_t i = 0; i < nfloats; i ) { /* output floats from line */
std::cout << array[i] << 'n';
}
}
}
(примечание: при этом будет считано столько строк с плавающими символами, сколько содержится в файле, повторное использование того же массива для хранения плавающих символов из каждой строки, а затем печать плавающих символов перед чтением следующей строки)
Альтернатива 2
Вы также можете прочитать строку и вручную отделить подстроки, используя чередующиеся вызовы .find_first_not_of()
, чтобы пропустить пробелы и сохранить позицию начала значения с плавающей запятой, а затем использовать .find_first_of()
для поиска и сохранения позиции следующего пробела после значения. (вам нужно будет проверить, npos
чтобы определить последнее значение). Затем вы вызовете stof()
преобразование и обработаете любое исключение при неудачном преобразовании.
Все это подчеркивает, почему использование тонкостей, которые предоставляет C , с более «продвинутым методом», показанным @PaulMcKenzie, может сократить размер вашего кода, а также исключить ручные проверки, индексацию и защиту границ, которые вы должны выполнять.
Комментарии:
1. Спасибо за помощь
2. Пожалуйста. Удачи вам с кодированием.