0

I am trying to write a line reader to populate a string array which is private member of the same class. I want the loader function called by constructor to dynamically resize member array and populate it. This didn't worked. Then I managed to populate a local array in the loader function. But I couldn't copy these values to private member of the class.

I think there must be a way of copying values from local "ReadLines" array to class private member "Lines" array.

I have already read how vector class implemented internally. But I still think dynamically populating a string array must be achievable by some other simple way, similar to which I used to resize local array in Read() function.

I searched the net, but couldn't find any answer without standart or self implemented vector classes. Has old methods before vectors (if any) completely forgotten? Is vector class that magical?

Isn't there any other way than vectors?

linereader.h :

class LineReader
{
    public:
        LineReader();
        void Read();

    private:
        string Lines[];
        int LineCount;
};

linereader.cpp :

#include <string>
#include <iostream>
using namespace std;
#include <fstream>
#include "linereader.h"

LineReader::LineReader()
{
    Read();
    cout << "Line Count : " << LineCount << endl;
    cout << "Lines Size : " << sizeof(Lines) << endl;
    cout << "Lines 0 : ";
    cout << Lines[0] << endl; //Gives segmantation fault
}

void LineReader::Read()
{
    std::ifstream infile("lines.txt");

    string *ReadLines = new string[1];

    string line;
    int linenumber = 0;
    while (infile >> line)
    {
        cout << endl << linenumber << " :: " << line << " ";

        string* temp_Lines = new string[linenumber + 1];
        for(int i = 0; i < linenumber; i++){
            cout << i << ",";
            temp_Lines[i] = ReadLines[i];
        }
        cout << "[" << linenumber << "]";

        delete [] ReadLines;
        ReadLines = temp_Lines;
        ReadLines[linenumber] = line;
        linenumber++;
    }
    infile.close();
    cout << endl << "----------------------------------" << endl;
    cout << "ReadLines Count : " << linenumber << endl;
    LineCount = linenumber;

    for(int i = 0; i < linenumber; i++){
        cout << "ReadLines "<< i + 1 << " " << ReadLines[i] << endl;
    }

    /////////////////////////////////////
    //       HERE IS THE PROBLEM       //
    // how to copy ReadLines to Lines? //
    /////////////////////////////////////
    //string *Lines = new string[linenumber + 1]; //  FLOODING TERMINAL WITH EMPTY LINES
    //   Lines =   ReadLines;   //  not working
    //   Lines =  *ReadLines;   //  error: cannot convert
    //   Lines = **ReadLines;   //  error: no match for ‘operator*’
    //  *Lines =   ReadLines;   //   error: invalid conversion from
    //  *Lines =  *ReadLines;   //  FLOODING TERMINAL WHEN RUN
    //  *Lines = **ReadLines;   //  error: no match for ‘operator*’
    // **Lines =   ReadLines;   //  error: no match for ‘operator*’
    // **Lines =  *ReadLines;   //  error: no match for ‘operator*
    // **Lines = **ReadLines;   //  error: no match for ‘operator*
}

int main(int argc, char* argv[])
{
    LineReader linereader;
    return 0;
}

lines.txt :

AAA
BBB
CCC
DDD
EEE
FFF
GGG

compilation :

g++ linereader.cpp -o linereader 

OUTPUT :

0 :: AAA [0]
1 :: BBB 0,[1]
2 :: CCC 0,1,[2]
3 :: DDD 0,1,2,[3]
4 :: EEE 0,1,2,3,[4]
5 :: FFF 0,1,2,3,4,[5]
6 :: GGG 0,1,2,3,4,5,[6]
----------------------------------
ReadLines Count : 7
ReadLines 1 AAA
ReadLines 2 BBB
ReadLines 3 CCC
ReadLines 4 DDD
ReadLines 5 EEE
ReadLines 6 FFF
ReadLines 7 GGG
Line Count : 7
Lines Size : 0
Segmentation fault
stackion
  • 3
  • 1
  • 2
    I think you need to learn about [`std::vector`](http://en.cppreference.com/w/cpp/container/vector). [A good beginners book](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) would have told you about it. – Some programmer dude Oct 26 '17 at 07:10
  • 1
    C is a different language than C++, please don't tag it on questions about C++. Using both tags is only appropriate for questions about interfacing or comparing both languages. –  Oct 26 '17 at 07:11
  • `string Lines[];` that does compile? That’s nothing you can assign heap allocated memory to. –  Oct 26 '17 at 07:24
  • @manni66 `string Lines[];` compiles without error. – stackion Oct 26 '17 at 07:32
  • @stackion I see no error but I can see a warning for an incomplete type. Warning are not there to clutter compiler output but to say that something is weird. Never ignore them! – Serge Ballesta Oct 26 '17 at 07:50
  • @serge-ballesta I tried with `g++ -v ...` but there is still no warning. Is there a more verbose way of compiling? I am seeing `compiled by GNU C version 5.4.1 20160904, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3` does that makes any difference? – stackion Oct 26 '17 at 07:55

2 Answers2

0

Try to call read from the main function. Then it should have no problems with modifying a private value.

If you also add a print function to the main file, then you can add the following code to your linereader.cpp, note that the constructor is now an empty implementation.

ineReader::print()
{
    cout << "Line Count : " << LineCount << endl;
    cout << "Lines Size : " << sizeof(Lines) << endl;
    cout << "Lines 0 : ";
    cout << Lines[0] << endl; //Gives segmantation fault
}

LineReader::LineReader() { }

int main(int argc, char* argv[])
{
    LineReader linereader;
    linereader.read();
    linereader.print();
    return 0;
}
Guus
  • 53
  • 1
  • 3
  • So I have to always follow "construct than initialize" method in C++. Am I right? – stackion Oct 26 '17 at 07:24
  • I made the changes but `cout << Lines[0] << endl` line floods the terminal with whitespaces (probably space) char. I had to Ctrl-C to stop it. – stackion Oct 26 '17 at 07:39
  • When I remove `cout << "Lines Size : " << sizeof(Lines) << endl;` line it gives "Seg fault" again. – stackion Oct 26 '17 at 07:45
0

The problem lies here:

string Lines[];

You declare an empty array. More exactly, you declare an incomplete array that is commonly implemented as a 0 size array. That is what the line Lines Size : 0 indicates. It used (mainly in C) when you create an object at a place where the memory for the array has already been allocated, and only as last element of a struct or class - in short never use it in your own code. It should at least raise a warning because it is not the last element of the class.

But once you have declared it that way, nothing can be done. The less poor way IMHO is to declare a pointer: as you already know the length in the following member it is enough:

private:
    string *Lines;
    int LineCount;

You can then safely do:

Lines =   ReadLines;

But what you do is close to non sense. You avoid to use a (well optimized and well tested) vector object, to play with allocation, copy and deallocation of arrays. That means that your code will give a much less efficient program than what you would get with a vector. In addition, as C++ has no garbage collection, this kink of code is likely to fragment the heap.

Said differently, there is nothing bad in exploring the low level constructs, but please be aware that this one should never go in production code.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Thanks. It worked. I first tried it as `string Lines[10];` and worked without problem so with dynamic arrays I assumed there would be not much difference. It seems I was too naive. :) – stackion Oct 26 '17 at 08:15