Thread: Problem with Dynamically Increasing Array of Integers

  1. #1
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413

    Problem with Dynamically Increasing Array of Integers

    After I discovered about C++ standard vectors, I've been using them ever since.
    But just today a friend of mine, who is just learning C++, asked me about dynamically increasing the size of arrays.

    Now, I happily went to code an example.
    The program reads a file for a whitespace separated arbitrary length list of integers, saves it into an array, then prints the contents of the array. Simple enough.
    Now, I discovered that for some reason, the first element in the array always became set to 0.
    In particular, it's value is detected to be 0 just after the portion of code that enlarges the array.

    In case I got the array expansion wrong, I checked with another friend, who duly provided me with a template function that pretty much did the same thing as I was doing.
    Consequently, there was no change in result - the first element remained zeroed.

    Here's is the source file in question:
    Code:
    #include <iostream>
    #include <fstream>
    
    using namespace std;
    
    ifstream& readInput(ifstream& ifs, int arr[], int& size, int& max_size);
    
    template<typename T> void enlarge(T* array, int& size) {
    	int init_size = size;
    	T* temp = new T[init_size];
    	for (int i = 0; i < init_size; ++i)
    		temp[i] = array[i];
    	delete[] array;
    	size += size;
    	array = new T[size];
    	for(int i = 0; i < init_size; ++i)
    		array[i] = temp[i];
    	delete[] temp;
    	temp = 0;
    }
    
    int main() {
    	int max_size = 10;
    	int* arr = new int[max_size];
    	int size = 0;
    	ifstream ifs("test.txt");
    	if (ifs.good())
    		readInput(ifs, arr, size, max_size);
    	ifs.close();
    	for (int i = 0; i < size; i++)
    		cout << arr[i] << endl;
    	delete[] arr;
    	arr = 0;
    
    	cin.sync();
    	cin.get();
    	return 0;
    }
    
    ifstream& readInput(ifstream& ifs, int arr[], int& size, int& max_size) {
    	while (ifs.good()) {
    		int temp;
    		if (ifs >> temp) {
    			if (size >= max_size) {
    				enlarge(arr, max_size);
    			}
    			arr[size++] = temp;
    		}
    	}
    	ifs.clear();
    	return ifs;
    }
    Here is the input file, named test.txt
    Code:
    11
    52
    6
    7
    8
    2
    3
    5
    7
    2
    33
    4
    The compiler I used is the MinGW port of GCC 3.4.2 (i.e. g++), under the Dev-C++ IDE (Windows XP, no SP2)
    Running the program produces each integer on its own line, except that "11" is printed as "0".
    My debugging tests show that the value of arr[0] changes to 0 just after enlarge(arr, max_size).
    Within the template function itself I detected no anomaly.

    Does anyone have any idea what is the problem, and how to fix it?
    Thanks.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  2. #2
    Tropical Coder Darryl's Avatar
    Join Date
    Mar 2005
    Location
    Cayman Islands
    Posts
    503
    arr[size++] = temp;

    your increment here "fully" completes within the brackets and thus the first pass through skips arr[0]

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    your increment here "fully" completes within the brackets and thus the first pass through skips arr[0]
    I'm using post-increment, not pre-increment, so that should not be the case.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Code:
    template<typename T> void enlarge(T* array, int& size) {
    //...
    array = new T[size];
    If you want to change the value of a pointer within a function and preserve that value outside the function, what do you have to do?
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    I thought I know, but after trying this out I dont.
    What's your answer?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Pass a pointer to a pointer or return the pointer value.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    hmm... just thought of that, but my implementation gives me a runtime error.
    Code:
    template<typename T> void enlarge(T** array, int& size) {
    	int init_size = size;
    	T* temp = new T[init_size];
    	for (int i = 0; i < init_size; ++i)
    		temp[i] = **(array+i);
    	delete[] *array;
    	size += size;
    	*array = new T[size];
    	for(int i = 0; i < init_size; ++i)
    		**(array+i) = temp[i];
    	delete[] temp;
    	temp = 0;
    }
    Of course I passed the address of arr to the enlarge() call.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  8. #8
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Code:
    template<typename T> void enlarge(T** array, int& size) {
        int init_size = size;
        T* temp = new T[init_size];
        for (int i = 0; i < init_size; ++i)
            temp[i] = **(array+i);
        delete[] *array;
        size += size;
        *array = new T[size];
        for(int i = 0; i < init_size; ++i)
            **(array+i) = temp[i];
        delete[] temp;
        temp = 0;
    }
    Play around with the order of your parenthesis there... you'll get it.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  9. #9
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Yeah, a change to:
    Code:
    template<typename T> void enlarge(T** array, int& size) {
    	int init_size = size;
    	T* temp = new T[init_size];
    	for (int i = 0; i < init_size; ++i)
    		temp[i] = (*array)[i];
    	delete[] *array;
    	size += size;
    	*array = new T[size];
    	for(int i = 0; i < init_size; ++i)
    		(*array)[i] = temp[i];
    	delete[] temp;
    	temp = 0;
    }
    solves the runtime error, but doesnt solve the problem.

    Now my output is:
    Code:
    0
    52
    6
    7
    8
    2
    3
    5
    7
    2
    393220
    524544
    which seems to indicate garbage after the initial max_size number of elements, while the first element remains zeroed.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  10. #10
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Quote Originally Posted by laserlight
    Of course I passed the address of arr to the enlarge() call.
    Do you do the same with readInput so that the change is noted in main, where the values are displayed?
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Okay, now here's the funny part.
    This implementation of the template function gives the correct output:
    Code:
    template<typename T> void enlarge(T* array, int& size) {
    	int init_size = size;
    	T* temp = new T[init_size];
    	for (int i = 0; i < init_size; ++i)
    		temp[i] = array[i];
    	delete[] &array;
    	size += size;
    	array = new T[size];
    	for (int i = 0; i < init_size; ++i)
    		array[i] = temp[i];
    	delete[] temp;
    	temp = 0;
    }
    But I didnt pass a pointer to a pointer, as far as I can see.
    All I did was delete[] based on address.
    Why and how does it work, if it actually works rather than just happen to work?
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Do you do the same with readInput so that the change is noted in main, where the values are displayed?
    Good point.
    Made the fix and that corrected it.

    I understand roughly what's behind passing the pointer to a pointer method, but now I dont understand the delete[]ing by address method, if it is even valid.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  13. #13
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Quote Originally Posted by laserlight
    but now I dont understand the delete[]ing by address method, if it is even valid.
    Slap a couple of these kind of things around key places in the code, such as at each function's entry and exit, to show what the pointer value actually is:
    Code:
    cout << "array = " << array << endl;
    If the value of array does change, and you discard the new value, you will be seeing undefined behavior (which unfortunately sometimes appears to be doing what it should).

    [edit]Only delete[] what was new[]'d exactly once.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  14. #14
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    > if (size >= max_size) {
    > enlarge(arr, max_size);
    > }
    Here you should really have:
    Code:
    			if (size+1 >= max_size) {
    				enlarge(arr, max_size);
    			}
    Otherwise you're overflowing your array before you enlarge it.

  15. #15
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    If the value of array does change, and you discard the new value, you will be seeing undefined behavior (which unfortunately sometimes appears to be doing what it should).
    Yep, it changes right after array = new T[size];
    I'll just use the pointer to pointer method then.

    Otherwise you're overflowing your array size before you enlarge it.
    No, because enlarge() is called before arr[size] is used, i.e. we enlarge first then use.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Integers into array.
    By livestrng in forum C Programming
    Replies: 10
    Last Post: 10-29-2008, 11:35 PM
  2. Replies: 2
    Last Post: 07-11-2008, 07:39 AM
  3. How To Declare and Dynamically Size a Global 2D Array?
    By groberts1980 in forum C Programming
    Replies: 26
    Last Post: 11-15-2006, 09:07 AM
  4. Need desperate help with two dimensional array problem
    By webvigator2k in forum C++ Programming
    Replies: 4
    Last Post: 05-10-2003, 02:28 PM
  5. help w/ array problem
    By rhythm313 in forum C++ Programming
    Replies: 3
    Last Post: 11-12-2002, 12:12 AM