0

I'm writing a program which creates vectors [x,y,z] from numbers loaded from my simple file, the numbers are separated just by the space. I have a problem with creating new objets using Strtok() method. Here is the code.

#include "FileStaff.h"
vector<Vector>& FileStaff::readFile(string tekst)
{
    vector<Vector> main;
    string buffor;
    char *text;
    ifstream infile(tekst, ios::in);
    //Checking if file exists
    if (!infile.good()) {
        cout << "cannot open the file!";
        return main;
    }
    while (!infile.eof())
    {
        text = paraseStringToChar(tekst);
        pushingToVector(main, text);
    }
    infile.close();
    return main;
}

Method which creates wektors and pushes them into Vector.

void FileStaff::pushingToVector(vector<Vector>& main, char * tekst)
{
    Vector *wektor = new Vector[1000000];
    char korektor[] = " ";
    float helpTab[3];
    int wordCount=0;
    char * container = strtok(tekst, korektor);
    //counting numbers in our array
    while (container != NULL)
    {
        container = strtok(NULL, " ");
        wordCount++;
    }
    for (int i = 0; i <wordCount;i++ )
    {
        //Creating vectots [x,y,z]
        container = strtok(tekst, korektor);
        helpTab[i % 3] = atof(container);
        container = strtok(NULL, korektor);
        if (i % 3 == 0) {
            Vector wektor(helpTab[0], helpTab[1], helpTab[2]);
            main.push_back(wektor);
        }
    }
}

If anyone could help me, I would be greatful.

LucasPG
  • 423
  • 1
  • 6
  • 22
  • 4
    Why use C functions when you have `std::string`, `std::stringstream`, and `std::getline` that can parse the string? – NathanOliver Mar 28 '16 at 12:50
  • 4
    The best way is simply [not to use `strtok()`](http://stackoverflow.com/questions/2799023/what-exactly-is-a-reentrant-function/2799288#2799288). – πάντα ῥεῖ Mar 28 '16 at 12:54
  • @πάνταῥεῖ I've been using `strtok()` for many years. Excluding the use of the `string` datatype, why not use `strtok()`? It has always seemed to work well for me. I'm interested to know why you are suggesting avoiding it. – Logicrat Mar 28 '16 at 12:58
  • If you are using C and not C++ you should change the tag on your question: you will get germane answers. – nicomp Mar 28 '16 at 12:58
  • @Logicrat Lacking re-entrance as mentioned from my link is one of these reasons. – πάντα ῥεῖ Mar 28 '16 at 13:00
  • does anyone have any ideas? – LucasPG Mar 28 '16 at 20:15

2 Answers2

0

Is this what you're looking for?

#ifndef _STRING_H
#include <string>
#endif
#ifndef _FSTREAM_H
#include <fstream>
#endif
#ifndef _STREAMBUF_H
#include <streambuf>
#endif
#ifndef _VECTOR_H
#include <vector>
#endif

using namespace std;

void writeToFile(string path, string data) {
    ofstream ofs(path,ios::app);
    ofs << data;
    ofs.close();
}
string readFromFile(string path) {
    ifstream ifs(path);
    std::string ret((std::istreambuf_iterator<char>(ifs)),
        std::istreambuf_iterator<char>());
    return ret;
}

enum XYZ { X = 0, Y = 1, Z = 2 };

struct Vector {
    float x, y, z;
    Vector(float _x=0, float _y=0, float _z=0) {
        x = _x;
        y = _y;
        z = _z;
    }
    float& operator[](size_t index) {
        if (index == XYZ::X) return x;
        if (index == XYZ::Y) return y;
        if (index == XYZ::Z) return z;
        throw new exception;
    }
};



#define min(a, b) (((a) < (b)) ? (a) : (b))

bool isCharNumeric(char c) {
    const char* numbers = "0123456789";
    for (size_t index = 0; index < strlen(numbers); index++)
        if (c == numbers[index]) return true; return false;
}

vector<Vector> parseFloatVectors(string str_in) {
    str_in += "  "; //safe, no out of bounds
    vector<Vector> results = {};
    char currentChar;
    char skipChar = ' ';
    bool found_period = false;
    size_t count_len = 0;
    Vector vector_buffer(0,0,0);
    XYZ current_axis = (XYZ)0;
    for (size_t index = 0; index < str_in.length(); index++) {
        currentChar = str_in[index];
        if (currentChar == skipChar || currentChar == '\n' || currentChar == '\t')
            continue;

        else if (isCharNumeric(currentChar)) {
            string word = ""; //word buffer
            size_t word_len = min(min(str_in.find_first_of(' ', index + 1) - (index), str_in.find_first_of('\n', index + 1) - (index)), str_in.find_first_of('\t', index + 1) - (index)); //whatever char comes first; newline, tab or space
                                                                                                                                                              //append chars of following word checking if it is still valid number char
            if (word_len > 0) {
                size_t count_word_len = 0;
                for (count_word_len = 0; count_word_len < word_len; count_word_len++)
                    if (isCharNumeric(str_in[index + count_word_len])) {
                        word += str_in[index + count_word_len];
                    }
                    else if (str_in[index + count_word_len] == '.' && isCharNumeric(str_in[index + count_word_len + 1])) {
                        //Floating-point numbers
                        word += '.';
                        found_period = true;
                        continue;
                    }
                    else {
                        word = "";
                        continue;
                    }

                    vector_buffer[current_axis] = stof(word);


                    if (current_axis == XYZ::Z) {
                        current_axis = XYZ::X;
                        results.push_back(vector_buffer);
                    }
                    else {
                        current_axis = (XYZ)(current_axis + 1);
                    }


                    index += count_word_len;
                    word = "";
                    continue;
            }

        }
    }
    return results;
}

Example usage: string input_floats = readFromFile("myVectors.txt"); vector vectors = parseNumbers(input_floats);

for each(Vector v in vectors) {
     printf("X = %f\n", v.x);
     printf("Y = %f\n", v.y);
     printf("Z = %f\n\n", v.z);
}

It will only parse full vectors (3 floats at a time). In other words, you'll only end up with a set of complete vectors.

SolaGratia
  • 309
  • 4
  • 18
  • Not exactly. I' m looking for, how to create multiple objects: Vector(float x,float y,float z); with strtook, and push them into my Vector. – LucasPG Mar 28 '16 at 14:08
  • I'll delete my answer I completely misread. My fault. I think I know what you want. – SolaGratia Mar 28 '16 at 14:19
  • See new answer. Of course, you can use your own method to read the text file into the string. – SolaGratia Mar 28 '16 at 14:53
0

From your question:

I'm writing a program which creates vectors [x,y,z] from numbers loaded from my simple file, the numbers are separated just by the space.

You are programming in C++ (not C, as claimed by the tag) so I'm sorry, but I don't understand why you are not doing something like this (avoiding strtok at all):

#include <iostream>
#include <vector>
#include <fstream>
#include <string>

struct Vector {
    double x,y,z;

    // ... vector operations stuff...

    // input operator
    friend std::istream &operator>>( std::istream &is, Vector &v ) {        
        return is >> v.x >> v.y >> v.z;
    }
    // output operator
    friend std::ostream &operator<<( std::ostream &os, Vector &v ) {
        return os << v.x << ' ' << v.y << ' ' << v.z;
    }   
};

std::vector<Vector> readFile( const std::string &fname)
{
    std::vector<Vector> main;
    std::string buf;
    Vector vtemp;

    std::ifstream infile{fname, std::ios::in};

    if (!infile.good()) {
        std::cout << "cannot open the file!";
        return main;
    }
    while ( infile >> vtemp ) {
        main.push_back(vtemp);
    }

    return main;
}

int main() {
    std::vector<Vector> data = readFile("input.txt");
    std::cout << "Vectors read: " << data.size() << '\n';
    for ( Vector & i : data ) {
        std::cout << i << '\n';
    }
    return 0;
}
Bob__
  • 12,361
  • 3
  • 28
  • 42
  • I have a problem with ">>" in while loop. No operator ">>" matches these operands. Everything is included – LucasPG Mar 28 '16 at 19:27
  • @LucasPG Are you trying to compile my code or are you just adapting the readFile() function in yours? Because you have to overload operator>> for your Vector class like I did. – Bob__ Mar 28 '16 at 19:33
  • I copied your whole structure, and operator still doesen't work . Can You explain creating operators to me using "friend"? – LucasPG Mar 28 '16 at 19:40
  • @LucasPG Small steps. Copy, compile and run the entire program I posted, after creating a small text file with some space separeted numbers named input.txt and see if it works or if your compiler (which is?) complains about it. – Bob__ Mar 28 '16 at 19:52
  • @LucasPG I used friend keyword because I want that function to access the members of the class without being part of it. It's the usual way to define stream operators in C++. – Bob__ Mar 28 '16 at 19:54
  • @LucasPG BTW you can even avoid that part: `while ( infile >> vtemp.x >> vtemp.y >> vtemp.z ) {...` would read 3 numbers and put them in vtemp members (if defined) till the end of the file or untill a reading fails (for type mismatch). – Bob__ Mar 28 '16 at 20:02