C++ не является моим предпочтительным языком.
У меня есть файл, который содержит это:
e 225,370 35,75
Я хочу разделить e, 225, 370, 35 и 75 друг от друга в символ и ints, но я испытываю затруднения. Я пытался делать все, что я нашел онлайн и в моей книге C++, и тем не менее она не удается. Помогите.
У меня было бы более легкое время, делая это в Java.
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
ifstream f("a.txt"); // check for errors.
char ch,dummy;
int i1,i2,i3,i4;
f>>ch>>i1>>dummy>>i2>>i3>>dummy>>i4;
cout<<ch<<endl<<i1<<endl<<i2<<endl<<i3<<endl<<i4<<endl;
return 0;
}
Если у вас есть контроль над форматом, то будет (слегка) легче читать, если вы уберёте запятые, и просто введете
e 225 370 35 75
С этим форматом код Пуаты_ для чтения данных будет работать [отредактировать: он с тех пор обновил свой код, чтобы он явно читал и пропускал запятые]. В противном случае, вам нужно будет явно пропустить запятые:
.char ingore1, ignore2;
char ch;
int i[4];
file >> ch >> i[0] >> ignore1 >> i[1] >> i[2] >> ignore2 >> i[3];
[Редактирование: если у вас паранойя или вам действительно необходимо проверить ваш вход, на этом этапе вы можете проверить, что игнорирует1
и игнорирует2
содержат запятые. ]
Однако, в большинстве случаев данные, вероятно, связаны, поэтому Вы захотите прочитать целую строку в одну структуру (или класс):
struct data {
char ch;
int i[4];
std::istream &operator>>(std::istream &is, data &d) {
char ignore1, ignore2;
return is >> ch >> i[0] >> ignore1 >> i[1] >> i[2] >> ignore2 >> i[3];
}
};
Сделав это, Вы можете прочитать весь объект data
одновременно:
std::ifstream infile("my data file.txt");
data d;
infile >> d;
Или, если у Вас есть целый файл, полный этих данных, Вы можете прочитать их все в вектор:
std::vector<data> d;
std::copy(std::istream_iterator<data>(infile),
std::istream_iterator<data>(),
std::back_inserter(d));
Если вы хотите использовать старомодный C Runtime
FILE * pf = fopen(filename, "r");
char e;
int a, b, c, d;
int ii = fscanf(pf, "%c %d,%d %d,%d", &e, &a, &b, &c, &d);
if (ii < 5)
printf("problem in the input file");
fclose (pf);
Редактировать: добавлена проверка ошибок на основе комментариев из DreamLax
Библиотека панели инструментов C ++ (СТРТК) имеет следующее решение вашей проблемы:
int main() { std::string data("e 225,370 35,75"); char c1; int i1,i2,i3,i4; strtk::parse(data,", ",c1,i1,i2,i3,i4); return 0; }
больше примеров можно найти здесь
Если вы делаете это в C++, вы (почти наверняка) не должны использовать что-то вроде:
data *primary = new data[primarypcs]();
Вместо этого вы должны использовать что-то вроде:
struct data {
std::string filename;
std::string size;
};
std::vector<data> primary(primarypcs);
В этом случае вы, как правило, можете управлять памятью гораздо проще: определите вектор в области, где он необходим, и когда он выходит из области, память будет освобождена автоматически.
Использование массива new (например, new x [y]
) в C++ - это то, без чего вам лучше обойтись. Когда-то (15 лет назад или около того) это был почти единственный доступный инструмент, так что его (обиды) использование было почти неизбежным - но этот день уже давно, и это было, наконец, 10 лет, так как был действительно хороший повод использовать его.
Поскольку неизбежно есть комментарий о «кроме как в реализации чего-то вроде вектора», я отмечу, что нет, даже когда вы реализуете вектор, вы не используете новый массив - вы (косвенно, через распределитель) используете :: оператор new
для выделения необработанной памяти, размещение нового для создания объектов в этой памяти, и явные вызовы dtor для уничтожения объектов.
Как говорили другие, в показанном фрагменте есть две явно неправильные вещи:
имени файла
и размера
членов только что выделенных структур, memset ()
использует неправильный размер. Ваш вызов memset ()
может быть упрощен и исправлен с помощью:
memset(primary, 0, primarypcs * sizeof *primary);
Существует еще одна тонкая проблема с вашим кодом: стандарт C не гарантирует, что все биты-ноль является константой нулевого указателя (т.е. NULL), поэтому memset () не является правильным способом установить указатель на NULL
. Портативный способ сделать то, что вы хотите сделать:
size_t i;
for (i=0; i < primarypcs; ++i) {
primary[i].filename = NULL;
primary[i].size = NULL;
}
Чтобы выделить память для имя файла
и размер
, это зависит от того, что вы хотите. Предположим, что имя файла
требует n
байт, а размер
- m
. Затем ваш цикл меняется на что-то подобное:
size_t i;
for (i=0; i < primarypcs; ++i) {
size_t n, m;
/* get the values of n and m */
primary[i].filename = malloc(n * sizeof *primary[i].filename);
primary[i].size = malloc(m * sizeof *primary[i].size);
}
Вы можете опустить умножение на sizeof * primary [i] .filename
и sizeof * primary [i] .size
, если хотите: C гарантирует, что sizeof (char)
будет 1. Я написал выше для полноты и для случая, когда имя файла
и размер
изменить типы.
Также обратите внимание, что если filename
является последовательностью длины k
, то для него необходимы (k + 1)
байт из-за завершения 0
(так что n = = k + 1
выше).
Если бы я предположил, вы хотите, чтобы size
сохранял длину соответствующего имени файла
? В этом случае size
должен быть не char *
, а size _ t
. Но поскольку я не знаю, как вы планируете использовать имя файла
и размер
, я не уверен.
Проверьте возвращаемое значение malloc ()
. Возвращает значение NULL
для ошибки. Я опустил чек из вышеуказанного кода для простоты.
Ваша публикация также помечена как C++, поэтому, если вы хотите использовать C++, также доступно решение на C++.
-121--3909771-Предполагая, что вы прочитали данные в строки...
Что еще нужно?
Используйте повысить токенизатор, чтобы разделить строку. Я предполагаю, что только первый токен является символом, поэтому образец код будет чем-то вроде:
#include <iostream>
#include <boost/tokenizer.hpp>
#include <string>
#include <vector>
using namespace std;
...
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
string teststring("e 225,370 35,75");
boost::char_separator<char> separators(", ");
tokenizer tokens(teststring, separators);
vector<string> substrings;
for (tokenizer::iterator iter = tokens.begin(); iter != tokens.end(); ++iter)
{
substrings.push_back(*iter);
}
и, вуаля, у вас все ваши подстроки в аккуратном векторе. CHAR находится в подставках [0] как std :: string, а следующие значения int находятся в подстрадавших значениях [1], а те, которые следуют, также как std :: string. Вам нужно будет преобразовать их в целочисленные значения. Для этого я предлагаю вам посмотреть на StringStream.
#include <fstream>
/* ... */
ifstream file;
file.open("yourfile.txt");
char c, dummy;
int i[4];
file >> c >> i[0] >> dummy >> i[1] >> i[2] >> dummy >> i[3];
file.close();