0

I want to create an array whose size I will only know at runtime, and then further increase that size during execution of the program.
This is from an /r/dailyprogrammer challenge which can be found here https://www.reddit.com/r/dailyprogrammer/comments/3twuwf/20151123_challenge_242_easy_funny_plant/
MSVisual gives me the error std::badd_array_new_length which means that it's having trouble instantiating the array?
I'm so tired with oftentimes copying code letter for letter from websites where it works and I constantly get errors. Is Visual a bad platform for learning C++? Should I try QT?

#include <iostream>
#include <string>
void main(int argc, char* argv[]) {

    int currentPlants = std::stoi(argv[2]), targetPeople = std::stoi(argv[1]), currentProduce = 0, week = 0;
    int * plants;
    plants = new int[currentPlants];
    for (int i = 0; i < currentPlants; i++) {
        plants[i] = 0;
    }

    if (plants == nullptr) EXIT_FAILURE;

    while (currentProduce < targetPeople) {
        currentProduce = 0;
        for (int i = 0; i < currentPlants; i++) {
            currentProduce += plants[i];
            plants[i]++;
        }
        if (currentProduce >= targetPeople) break;
        else {
            plants = new int[currentProduce];
            for (; currentPlants < currentProduce; currentPlants++) {
                plants[currentPlants] = 0;
            }
        }

        week++;
    }
    std::cout << week;    
}
Scy
  • 245
  • 1
  • 12
  • 15
    ...by using ``...? – DevSolar Feb 10 '16 at 21:07
  • 4
    What you want is an std::vector – LukeG Feb 10 '16 at 21:08
  • 1
    Besides the leaks, what is your problem? – Amit Feb 10 '16 at 21:08
  • 5
    *"Is Visual a bad platform for learning C++?"* No, but trying to learn C++ by trial and error is a *really* bad idea, you will end up with horrible style such as this `new[]` and (here evidently missing) `delete[]` non-sense. You should learn C++ systematically from a good book or tutorial. – Baum mit Augen Feb 10 '16 at 21:10
  • As a comment, Visual Studio is a great tool to learn C++. If you plan to change your platform (linux for example) try Qt Creator, but if this is not the case, Visual is a good choice. – goe Feb 10 '16 at 21:13

5 Answers5

5

You should use an std::vector.

As a summary :

// Create an array of size 10    
std::vector<int> my_vector(10);

// Add '3' to my_vector
my_vector.push_back(3);

// Remove the last element
my_vector.pop_back();

Explanation and example here : www.cplusplus.com/reference/vector/vector/

Edit : you don't need to specify the array size when you construct your object.

// Create an array    
std::vector<int> my_vector;
Pierre
  • 1,162
  • 12
  • 29
3

You can't increase the size of an array at runtime. You can create a new bigger array, and copy the contents of the old array to the new array.

Artūrs Eimanis
  • 578
  • 3
  • 5
  • 22
1

Outside of using std::vector, you would need to allocate a new array on the heap, copy the contents over, and delete the old one. Then point your int* to the newly allocated array.

This wouldn't technically change the array size, but those accessing the object would see it as though it was changing.

callyalater
  • 3,102
  • 8
  • 20
  • 27
  • What about realloc? It does that doesn't it? – Jerry Jeremiah Feb 10 '16 at 21:20
  • Not really. From cppreference.com: "The reallocation is done by either: a) expanding or contracting the existing area pointed to by ptr, if possible. The contents of the area remain unchanged up to the lesser of the new and old sizes. If the area is expanded, the contents of the new part of the array are undefined. b) allocating a new memory block of size new_size bytes, copying memory area with size equal the lesser of the new and the old sizes, and freeing the old block." – callyalater Feb 10 '16 at 21:24
  • That sounds the same as manually allocating a new array, copying the contents over and then deleting the old one. The new part of the expanded array isn't filled in by your algorithm either and so those values are undefined until set to something. What's the point of doing something manually that there is a library function for? – Jerry Jeremiah Feb 10 '16 at 21:36
  • That is why there are many different implementations of the *alloc functions (first fit, buddy, suballocator, jemalloc, &c.) Choosing which one to use varies on the application (real time system, limited memory, distributed memory, &c.). You could write your own or use a library. Writing your own dynamic array would allow you to control how often the allocating function gets called. – callyalater Feb 10 '16 at 21:47
1

The problem with your code is that on the first pass through plants all of your plants[x] are zero. You add all of these together and get zero => currentProduce == 0. You then try to new plants[currentProduce aka 0] which is illegal.

Your second problem is that each time you new you create a new array discarding the old values; new creates a new array, it doesn't know anything about the old one.

I rewrote your code using std::vector, which fixes the crash but produces an endless loop because on the first pass, currentProduce comes out to zero so the array is truncated.

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

int main(int argc, const char* argv_real[])
{
    const char* argv[] = { "programname", "5", "25" };
    int currentPlants = std::stoi(argv[2]), targetPeople = std::stoi(argv[1]), currentProduce = 0, week = 0;
    std::cout << "targetPeople = " << targetPeople
              << ", currentPlants = " << currentPlants
              << "\n";

    std::vector<int> plants;
    // Option 1:
    // plants.resize(currentPlants);
    // Option 2:
    for (auto i = 0; i < currentPlants; ++i) {
        plants.push_back(0);
    }

    while (currentProduce < targetPeople) {
        std::cout << "cp: " << currentProduce
                  << ", tp: " << targetPeople
                  << "\n";
        currentProduce = 0;

        // plantCount is a reference to plants[i] for each i
        for (auto& plantCount : plants) {
            std::cout << plantCount << ", ";
            currentProduce += plantCount;
            plantCount++;
        }
        std::cout << " cp: " << currentProduce << "\n";

        if (currentProduce >= targetPeople)
            break;

        // Option 1:
            plants.resize(currentProduce);
        // Option 2:
        //  while (currentPlants < currentProduce) {
        //      plants.push_back(0);
        //  }

        week++;
    }
    std::cout << week;    
}

Live demo: http://ideone.com/xGpoF6

kfsone
  • 23,617
  • 2
  • 42
  • 74
0

This is dangerous:

int * plants;
plants = new int[currentPlants];
for (int i = 0; i < currentPlants; i++) {
    plants[i] = 0;
}

if (plants == nullptr) EXIT_FAILURE;

This is what happens (if you are lucky):

  • the program attempts to create some memory and returns nullptr if it can't
  • the program then uses the memory in a loop even if nullptr was returned. (If nullptr was returned this will crash the program, silently corrupt the memory so you get the wrong results or otherwise doing something you don't want)
  • the program then checks to see if nullptr was returned.

If you are unlucky the compiler does time travel and destroys the entire universe. I am not kidding, have a look at:

Community
  • 1
  • 1
Jerry Jeremiah
  • 9,045
  • 2
  • 23
  • 32