-1

I'm trying to initialize an array of integers dynamically, since the size of the array changes based on input. The program is as follows:

int main()
{
    int* list = createList("dis.bin");
    for (int i = 0; i < sizeof(list) / sizeof(int); i++)
    {
        printf("%d\n", list[i]);
    }
}

With createList() function as written:

int* createList(const char* file_name)
{
    int counter = 1;
    int* inst{};
    FILE* myFile = fopen(file_name, "rb");
    if (myFile == nullptr)
    {
        printf("\nFile not opened\n");
        return 0;
    }

    int x = 0;
    for (int i = 0; !(feof(myFile)); i++)
    {
        fread(&x, sizeof(int), 1, myFile);
        inst = new int[counter];
        inst[i] = x;
        printf("%08x #%-4d |   Int equiv: %-12d |   Bin equiv: %s\n", x, counter, inst[i], ToBinary(inst[i], 0));
        counter += 1;
        x = 0;
    }

    return inst;
}

createList reads from a .bin file (basically containing an array of bytes) and inserts each pair of 4 bytes to an item in the array inst. I do this by allocating a new amount of space for the array based on the counter variable. (So whatever value counter is becomes the size of the array with inst = new int[counter]) Then I set the contents of the array at the given index i equal to x (the pair of bytes read) I would assume it is working correctly in createList at least, because of the printf statement which is printing each element in inst[].

However, when I call createList("dis.bin") in main and assign it to the variable int* list, I try to iterate through each value. But this just prints out one uninitialized value (-842150451, if you're curious). So I'm not sure what I'm doing wrong here?

I should mention that I am NOT using vectors or really any std container. I am just working with arrays. I also am using printf for specific reasons.

EthanR
  • 139
  • 9
  • Also note that `inst = new int[counter];` will overwrite any previous address stored in `inst` and that memory will be leaked. You won't be 'appending' a new `int` to an old list, just creating a new (mostly uninitialized) list. – Adrian Mole Aug 02 '20 at 23:01
  • @SamVarshavchik so am I supposed to get the counter variable first, and then create the array? Then iterate through the file again to set the values? – EthanR Aug 02 '20 at 23:04
  • You could do that. Or like vector does have a capacity and size and allocate more than needed and when the vector is full reallocate to a larger size perhaps 2 times as big and copy the old data to new location. – drescherjm Aug 02 '20 at 23:05
  • won't `sizeof(list)` always be 4 (or 8 depending on architecture) since `list` is a pointer? – Andy Aug 02 '20 at 23:06
  • 2
    @Andy That is correct. The function will need to somehow return the size of the created array (as a second argument, maybe: `int& size`). – Adrian Mole Aug 02 '20 at 23:07
  • 3
    If this is really C++, then you should try to stick to that language and all the wonderful tools it gives you. – Andy Aug 02 '20 at 23:09
  • @Andy the purpose of not using certain C++ standard tools is to educate myself. I clarified my restrictions so I expected that to suffice. – EthanR Aug 02 '20 at 23:11
  • 1
    Write your code with `std::vector`, then if `std::vector` is not available, roll your own version such that your main code need not be changed. By the way your `for` loop is broken, see [Why is “while ( !feof (file) )” always wrong?](https://stackoverflow.com/questions/5431941/). – n. m. could be an AI Aug 02 '20 at 23:11
  • 1
    @EthanR -- *I am just working with arrays* -- No you're not -- you're working with pointers and dynamically allocated memory, absolutely no different than what `std::vector` is doing. A `vector` is not using magic -- it is using `new` to allocate the memory, but it is already written to behave correctly. That's the real difference. – PaulMcKenzie Aug 03 '20 at 00:29
  • @PaulMcKenzie No need to be pedantic. By “I am just working with arrays”, I thought that clearly outlined my choice to not use vectors. – EthanR Aug 03 '20 at 00:31
  • There is a difference between arrays and pointers. A pointer is not an array, and that is an important difference. Why not attempt to write a vector *class*, instead of having `new[]` and `delete[]` around the codebase like that? You would learn far more doing things that way than having those calls not encapsulated. – PaulMcKenzie Aug 03 '20 at 00:32

2 Answers2

1

This question is tagged as C++, but OP is showing C code and says they need it in C, so I will show this in C... but the pre-req is that it uses new and not malloc

int* createList(const char* file_name, int& count)
{
    // initialize count, so that way if we return early, we don't have invalid information
    count = 0;

    // open the file ad "READ" and "BINARY"
    FILE* myFile = fopen(file_name, "rb");
    if (!myFile)
    {
        printf("\nFile not opened\n");
        return 0;
    }

    // calculate how many 4-byte integers exist in the file using
    // the file length
    fseek(myFile, 0, SEEK_END);
    count = ftell(myFile) / sizeof(int);
    rewind(myFile);
    
    // allocate the memory
    int* returnData = new int[count];

    // read in 4-byte chunks to our array until it can't read anymore
    int i = 0;
    while (fread(&returnData[i++], sizeof(int), 1, myFile) == 1);

    // close the file
    fclose(myFile);

    // return our newly allocated data
    return returnData;
}

int main()
{
    int count;
    int* myInts = createList("c:\\users\\andy\\desktop\\dis.bin", count);
    for (int i = 0; i < count; ++i) {
        printf("%d\n", myInts[i]);
    }
    // don't forget to delete your data. (another reason a vector would be better suited... no one remembers to delete :)
    delete myInts;
}
Andy
  • 12,859
  • 5
  • 41
  • 56
  • Thank you--but the question was specifically asked with `new` in mind, which I believe is only a part of C++. – EthanR Aug 03 '20 at 01:02
  • There is no `realloc` type stuff in C++ because they expect you to use C++ constructs like `vector` for these things. Sure, it's possible to roll your own... but you're missing the point of using C++. – Andy Aug 03 '20 at 01:08
  • No, you simply write the reallocation yourself. You allocate a new array larger than the current. You copy the current to the newly allocated array, and you `delete[]` the old one (the one that was current but no longer is) and keep going. – David C. Rankin Aug 03 '20 at 01:13
  • 1
    fixed it so it uses `new` @EthanR – Andy Aug 03 '20 at 01:20
  • @DavidC.Rankin -- true, but... would *you* do that? :) – Andy Aug 03 '20 at 01:22
  • @Andy Well isn't the vector construct fairly inefficient? As far as I'm aware, there are more efficient alternatives should you choose you make your own. Several companies I know of use their own form of vectors for the sake of efficiency. – EthanR Aug 03 '20 at 01:27
  • @EthanR -- all depends on how you use them. Of course you will take some sort of hit on efficiency, it is a container data structure. But the amount of time it saves you on safety, readability and maintainability is well worth it. – Andy Aug 03 '20 at 01:29
  • @EthanR *Well isn't the vector construct fairly inefficient?* -- No. Where did you get this information? – PaulMcKenzie Aug 03 '20 at 01:45
  • @Andy -- Where is the efficiency hit in vector? The only thing would be that vector initializes its data. With the advent of move semantics, plus vector uses `placement-new`, plus the mere fact that the compiler's implementation of `std::vector` is as fine-tuned as possible (written by very intelligent C++ library writers), the "fairly inefficient" point is really not justified by the OP. If the question is if vector is the best container for the job, that is a different story. – PaulMcKenzie Aug 03 '20 at 01:53
  • @PaulMcKenzie -- I mean on a scale of pico-seconds, something that humans wouldn't notice. When allocating a straight-up array of `int` and filling it vs. creating a `vector` and pushing `int`s on to it. I'm sure the array method will be slightly faster if you had to do fill over a million integers. I am in your camp, though. I would choose `vector` 10 times out of 10 if given a challenge like this. – Andy Aug 03 '20 at 02:00
  • @Andy - yes, there are two decades worth of C++ out there that do just that. STL just didn't magically appear and Ex pos facto rewrite all the C++ that came before. While all new code going forward would be wise to use STL, it is just as important to know how to handle manual memory management. – David C. Rankin Aug 03 '20 at 12:05
0

Two things here:

  1. The usage of new was misinterpreted by me. For whatever reason, I thought that each time I allocated new memory for inst that it would just be appending new memory to the already allocated memory, but this is obviously not the case. If I wanted to simulate this, I would have to copy the contents of the array after each iteration and add that to the newly allocated memory. To solve this, I waited to allocate memory for inst until after the file iteration was complete.

  2. As Andy pointed out, sizeof(list) / sizeof(int) would not give me the number of elements in list, since it is a pointer. To get around this, I created a new parameter int &read for the createList() function in order to pass the number of items created.

With these points, the new function looks like this and works as intended:

int* createList(const char* file_name, int &read)
{
    int counter = 1;
    FILE* myFile = fopen(file_name, "rb");
    if (myFile == nullptr)
    {
        printf("\nFile not opened\n");
        return 0;
    }

    int x = 0;
    for (int i = 0; !(feof(myFile)); i++)
    {
        fread(&x, sizeof(int), 1, myFile);
        printf("%08x #%-4d |   Int equiv: %-12d |   Bin equiv: %s\n", x, counter, x, ToBinary(x, 0));
        counter += 1;
    }

    int* inst = new int[counter];
    read = counter;
    rewind(myFile); // rewind to beginning of file

    for (int i = 0; !(feof(myFile)); i++)
    {
        fread(&x, sizeof(int), 1, myFile);
        inst[i] = x;
        x = 0;
    }
    
    return inst;
}

With main changed a bit as well:

int main()
{
    int read;
    int* list = createList("dis.bin", read);
    for (int i = 0; i < read; i++)
    {
        printf("%d\n", list[i]);
    }
}

As for the comments about the invalidity of !(feof(myFile)), although helpful, this was not a part of my question and thus not of my concern. But I will source the solution to that for the sake of spreading important information: Why is "while ( !feof(file) )" always wrong?

EthanR
  • 139
  • 9
  • @Andy Sorry, I'm not very familiar with the file system using C-style, so I didn't quite know how to grab the number necessary without reading the file twice. I just hacked together the solution quickly. – EthanR Aug 03 '20 at 01:25
  • 1
    You forgot to deallocate the memory, thus leaks memory. Note that in a non-trivial program, this all becomes a maintenance headache. – PaulMcKenzie Aug 03 '20 at 01:42