0

I am trying to write code in C++ that reads from a file, a sequence of points, stores it in a dynamic array and then prints back.

This is the specification I've been given:

"We want to take advantage of the fact that we can use dynamic memory, thus instead of allocating at beginning an amount of memory large enough according to our estimations, we implement the following algorithm:

Initially, very little memory is allocated.

At each iteration of the loop (reading from the file and storing into the dynamic array) we keep track of:

  • The array maximum size (the allocated memory).
  • The number of elements in the array.

When, because of a new insertion, the number of elements would become greater than the array maximum size, memory reallocation needs to take place as follows:

  • Allocate another dynamic array with a greater maximum size.
  • Copy all the elements from the previous array to the new one.
  • Deallocate the memory area allocated for the previous array.
  • Get the pointer to the previous array to point to the new one.
  • Add the new item at the end of the array. This is where my problem is.

From my code below, I think everything else is fine but the last requirement, which is to add the new item at the end of the array.

The code works fine when the array Max_Size exceeds file's number of elements, but when I try extending the num_elements, the result is that the extra digits in the file are just saved as zeros

.

Also to add, the assignment doesn't allow use of vectors just yet. Sorry I forgot to mention this, I'm new to stackoverflow and somewhat to programming.

Any help please

#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;

struct point {  
    double x;
    double y;
};

int main () {

    ifstream inputfile;

    inputfile.open("datainput.txt");

    if(!inputfile.is_open()){
    cout << "could not open file" << endl;
        exit(EXIT_FAILURE);
    }

    //initially very little memory is allocated
    int Max_Size = 10;
    int num_elements = 0;
    point *pp = new point[Max_Size];


    //read from file and store in dynamic array
    for (int i = 0; !inputfile.eof(); i++) {
            inputfile >> pp[i].x >> pp[i].y;
            num_elements++;                 //keep track of number of elements in array
        }


    //detecting when number of elements exeeds max size due to new insertion:
    if (num_elements > Max_Size){

        // allocate another dynamic array with a greater maximum size
        Max_Size *= 2;              // Max_Size = 2*Max_Size to double max size whenever there's memory problem
        point *pp2 = new point[Max_Size];

        //copy all elements from previous array to new one
        for (int j=0; j<(Max_Size/2); j++) {
            pp2[j].x = pp[j].x ;
            pp2[j].y = pp[j].y;
        }


        //deallocate memory area allocated for previous array
        delete [] pp;

        //get pointer to previous array to point to the new one
        pp = pp2;





 **//add new item at end of the array
        for (int k = ((Max_Size/2)-1); k<num_elements; k++) {
                     inputfile.seekg(k, ios::beg) >> pp2[k].x;
                     inputfile.seekg(k, ios::beg) >> pp2[k].y;

                }**


        //print out dynamic array values
        for (int l = 0; l<num_elements; l++) {
            cout << pp2[l].x << ",";    
            cout << pp2[l].y << endl; 
        }

        //delete dynamic array
        delete [] pp2;
    }

    else {
        //print out dynamic array values
        for (int m = 0; m<num_elements; m++) {
            cout << pp[m].x << ","; 
            cout << pp[m].y << endl; 
        }

        //delete dynamic array
        delete [] pp;
    }   

    cout <<"Number of elements = " << num_elements <<endl;




    //close file
    inputfile.close();

    return 0;
}
AlanPoser
  • 147
  • 1
  • 10
  • 4
    See, the thing about C++ is that if you have to care about dynamic memory allocation, you're often doing something wrong. – user123 Aug 19 '14 at 14:10
  • 1
    Whenever you think to yourself "hmm I need an array, but I don't know how big it needs to be, and it might change" you should be using a `std::vector` – Cory Kramer Aug 19 '14 at 14:12
  • 4
    If this is homework and you're not supposed to use the Standard Library, you should say so. Otherwise the only answers you'll get will involve vectors. – Mr Lister Aug 19 '14 at 14:14
  • For safety don't use a dynamic array, use a `vector/deque` instead. – DumbCoder Aug 19 '14 at 14:14
  • So, you write the values into your array **before** you check if they exeed the size of your array? – MatthiasB Aug 19 '14 at 14:22
  • I believe that's the behavior of the `std::vector`. I don't know exactly but I think it doubles it size every time it runs out of memory and copies the elements to the new memory. – aaragon Aug 19 '14 at 14:33
  • As @MatthiasB hints at above, you need to detect the potential overrun *before* reading past the end of the first array - this is a potential crash/Undefined Behaviour. Also, might there be some arithmetic missing in your call to `seekg` to ensure you seek `(MaxSize/2)-1` *integers* into the file, not *bytes*...? – Grimm The Opiner Aug 19 '14 at 14:37
  • @aaragon: That is one feasible implementation. Another is to grow by half its old size (for reasons too complex to explain in a comment). The only requirement is that the growth is at least proportional to the previous size for some unspecified constant `c`. – MSalters Aug 19 '14 at 14:44
  • @MSalters: Or to put it somewhat more succinctly: it grows geometrically. – Jerry Coffin Aug 19 '14 at 14:48
  • @MSalters why don't you try to do it more the _C++ way_? I could create a `Container` class template that has an array pointer and keeps the size. So an `insert` function can be called to add elements to the container (and inside this function you can check if your number array has appropriate size or of you need to reallocate). Again, you would be reimplementing the functionality of the `std::vector`, so unless this is for educational purposes, I wouldn't recommend to do it. – aaragon Aug 19 '14 at 14:53
  • @aaragon: ???? Your response doesn't make sense. You guessed at how `std::vector` worked. That's a standard;-defined class and each compiler has its own implementaiton. I merely pointed out that other implementations can use other growth strategies in their `std::vector` implementations. I never talked about any other class but `std::vector`. – MSalters Aug 19 '14 at 15:00
  • I'm talking about your implementation, you put C++ as a tag but when I read your code is really more C than C++. – aaragon Aug 19 '14 at 15:02
  • @aaragon: You do realize that MSalters isn't the person that posted this question, right? – Blastfurnace Aug 19 '14 at 15:09
  • Now I do, my apologies to @MSalters – aaragon Aug 19 '14 at 15:11
  • Thanks guys!, as @Mr-Lister has rightly suggested, it is an assignment and vectors are not to be used for this. – AlanPoser Aug 20 '14 at 00:30

2 Answers2

5

Others have already pointed out std::vector. Here's roughly how code using it could look:

#include <vector>
#include <iostream>

struct point {
    double x;
    double y;

    friend std::istream &operator>>(std::istream &is, point &p) { 
        return is >> p.x >> p.y;
    }

    friend std::ostream &operator<<(std::ostream &os, point const &p) { 
        return os << p.x << "," << p.y;
    }
};

int main() { 
    // open the file of data
    std::ifstream in("datainput.txt");

    // initialize the vector from the file of data:
    std::vector<point> p {
        std::istream_iterator<point>(in),
        std::istream_iterator<point>() };

    // print out the data:
    std::copy(p.begin(), p.end(), std::ostream_iterator<point>(std::cout, "\n"));
}

On top of being a lot shorter and simpler than the code you posted, getting this to work is likely to be a lot simpler and (as icing on the cake) it will almost certainly run faster1 (especially if you have a lot of data).


1. In fairness, I feel obliged to point out that the big difference in speed will mostly come from using \n instead of endl to terminate each line. This avoids flushing the file buffer as each line is written, which can easily give an order of magnitude speed improvement. See also: https://stackoverflow.com/a/1926432/179910

Community
  • 1
  • 1
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
0

The program logic is flawed. You run the loop until EOF but you don't check to see if you have exeeded your array size. I would add an if statement inside of the first loop to check if you have passed the Max_Size. I would also write a function to reallocate the memory so you can simply call that function inside of your first loop.

Also you have problems with your memory allocation. You should do like this:

point temp = pp;
pp = new Point[...];
// Copy the contents of temp into pp
delete temp;

You need to set your pointer to the old array first so you don't lose it. Then after you have copied the contents of you old array into the new array, you can then delete the old array.

Dan
  • 1,874
  • 1
  • 16
  • 21
  • Thanks for your reply, but I have a few issues: The reason I haven't checked to see if it exceeds is because it only prints out the arrays that have been properly filled (because the print loop condition is m – AlanPoser Aug 20 '14 at 00:18
  • After re-reading your code, I would recommend for you to create a new file and start fresh. You need to use functions and break your program into very small pieces. And test often by compiling and running your code. – Dan Aug 20 '14 at 03:40