Search code examples
c++filevectorgetline

not reading the first line


I was using the following code to read information from a file (b.txt) into a vector. every time I execute, the program starts reading from the second line. So vector_b[0] = the second line instead of the first line.

I'm still not used to c++ hope you can help

string line_b;
int idx = -1;
float *vector_b = new float[1];
float element_b;
if (file_b.is_open() && file_b.good()) {
    cout << "File is open. \n";
    while (getline(file_b, line_b)) {
        stringstream stream_b(line_b);
        while(1) {
            stream_b >> element_b;
            if(!stream_b) {
                break; }
            idx = idx+1;
            float *tempArr = new float [idx];
            copy(vector_b, vector_b + idx, tempArr);
            tempArr[idx] = element_b;
            delete [] vector_b;
            vector_b = tempArr;
        }
    }        
    } 
    else {
        cout << "Failed to open file.";
    }

Solution

  • You might try something like the following. You might try a vector as opposed to a dynamic array. they're more flexible and in most cases faster. You don't have to worry about use after frees, double frees, or memory leaks... so Yeah... vectors rule...

    int main() {
        std::ifstream file_b;
        file_b.open("Some-file.cpp");
    
        std::string line_b;
        // vector_b is a vector of doubles
        std::vector<double> vector_b();
        double element_b;
        if (file_b.is_open() && file_b.good()) {
            std::cout << "File is open. \n" << std::endl;
            while(getline(file_b, line_b)) {
                std::stringstream stream_b(line_b);
                // You don't need a second if.
                while(stream_b) {
                    stream_b >> element_b;
                    // append element_b to your vector
                    vector_b.push_back(element_b);
                }
            }
        } else {
            std::cout << "Failed to open file." << std::endl;
        }
    }
    

    However, if you can't use vectors, I'd suggest you look into creating a container class like the class and usage listed below. I don't trust myself to remember to free memory, so sometimes its just best to build a class. I tested the class below under valgrind a few times, so there shouldn't be any leaks, but no promises. I made it very hurried.

    #include <cassert>
    
    // use a templated class so we can use it with different types
    template<typename T>
    class Container {
        private:
            unsigned int m_size;
            unsigned int m_capacity;
            T* m_array;
    
        public:
            // Any time you make a container class make sure you follow the
            // rule of 5 with C++11 or the rule of 3 for prior compilers
            // 1) Copy Constructor
            // 2) Move Constructor (C++11)
            // 3) Copy Assignment Operator
            // 4) Move Assignment Operator (C++11)
            // 5) Destructor
    
            // Default constructor
            Container() { }
    
            // Constructor we'll use
            Container(unsigned sz) :
                m_size(0),
                m_capacity(sz),
                m_array(new T[sz]) { }
    
            // Copy constructor
            Container(const Container& src) :
                m_size(src.m_size),
                m_capacity(src.m_size),
                m_array(new T[src.m_size]) {
                    for(unsigned i = 0; i < m_size; ++i) {
                        // copy values
                        m_array[i] = src.m_array[i];
                    }
                }
    
            // Move constructor
            Container(Container&& src) {
                // "steal" the sources members
                m_capacity = src.m_capacity;
                m_size = src.m_size;
                m_array = src.m_array;
                // "destroy" the sources members
                src.m_size = 0;
                src.m_capacity = 0;
                src.m_array = nullptr;
            }
    
            // Destructor
            ~Container() {
                delete[] m_array;
            }
    
            // Copy assignment operator
            Container& operator=(const Container& src) {
                // check to make sure you're copying a different source
                if(this == &src) {
                    return *this;
                }
                // free your current memory
                delete[] m_array;
                // make a new array and copy the sources values
                m_array = new T[src.m_size];
                for(unsigned i = 0; i < src.m_size; ++i) {
                    m_array[i] = src.m_array[i];
                }
                // copy the size parameters
                m_size = src.m_size;
                m_capacity = src.m_capacity;
                return(*this);
            }
    
            // Move assignment operator
            Container& operator=(Container&& src) {
                // check to make sure you're copying a different source
                if(this == &src) {
                    return *this;
                }
                // free your current memory
                delete[] m_array;
                // "steal" the sources members
                m_array = src.m_array;
                m_size = src.m_size;
                m_capacity = src.m_capacity;
                // "destroy" the sources members
                src.m_array = nullptr;
                src.m_size = 0;
                src.m_capacity = 0;
                return(*this);
            }
    
            void resize(unsigned int sz) {
                // make sure you're not shrinking the container
                if(sz > m_capacity) {
                    // make a temporary array
                    T* tmp = new T[sz];
                    for(unsigned i = 0; i < m_size; ++i) {
                        // copy the values to the temporary array
                        tmp[i] = m_array[i];
                    }
                    // free your current memory
                    delete[] m_array;
                    // "steal" the temporary array
                    m_array = tmp;
                    // release tmp's handle on the memory
                    tmp = nullptr;
                    // inform your object that it has more memory now
                    m_capacity = sz;
                }
            }
    
            void push_back(const T& src) {
                // check if you have enough space to append a value
                if(m_size + 1 > m_capacity) {
                    // if not, double your current size, so you don't have
                    // to do it every time
                    resize((m_capacity + 1) * 2);
                }
                // increment the size member and append the value to your array
                m_array[m_size++] = src;
            }
    
            T& operator[](unsigned index) {
                // make sure the index value is in-bounds
                assert(index < m_size);
                return(m_array[index]);
            }
    
            size_t size() { return(m_size); }
    };
    

    Usage:

    int main(int argc, char *argv[]) {
        Container<std::string> vector_b(1);
        std::ifstream file_b;
        file_b.open("Sleep.cpp");
    
        std::string line_b;
        std::string element_b;
        if (file_b.is_open() && file_b.good()) {
            std::cout << "File is open. \n" << std::endl;
            while(getline(file_b, line_b)) {
                std::stringstream stream_b(line_b);
                    while(stream_b) {
                        stream_b >> element_b;
                        vector_b.push_back(element_b);
                    }
            }
        } else {
            std::cout << "Failed to open file." << std::endl;;
        }
    
        for(unsigned i = 0; i < vector_b.size(); ++i) {
            std::cout << vector_b[i] << std::endl;
        }
    }
    

    As you can see, working with dynamic memory allocations is a pain, and generally should be avoided, or at least handled with extreme care and lots of valgrind.