0

I have a class defined in a header file, Array.h.

Class Code:

class Array
{
    private:
        int length;
        void **data;

    public:
        Array();
        void push(void *);
};

I also have the Array.cpp file.

Code:

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "Array.h"

Array::Array()
{
    length = 0;
    data = NULL;
}

void Array::push(void *item)
{
    void **temp = new void *[length + 1];
    for (int i = 0; i < length; i++)
        temp[i] = data[i];
    temp[length] = item;
    data = temp;
    length++;
}

And finally, main.cpp.

Code:

#include <stdio.h>
#include "Libs/Array.h"

void loadArray();

int main()
{
    loadArray();
    return 0;
}

void loadArray()
{
    Array ints = Array();

    while (true)
    {
        printf("Array (Size: %d): ", ints.size());
        for (int i = 0; i < ints.size(); i++)
            printf("%d ", *((int *)ints.get(i)));
        printf("\n");
        printf("1] Push\n2] Pop\n3] Set\n4] Get\n5] Clear\n6] Shift\n7] Unshift\n8] Size\n\n9] Exit\n");
        printf("Choice: ");
        int choice;
        scanf("%d", &choice);
        printf("\n\n");

        bool shouldExit = false;

        switch (choice)
        {
        case 1:
        {
            int x;
            printf("Enter a number: ");
            scanf("%d", &x);
            ints.push(&x);
            printf("\n\n");
            break;
        }
        (...)
        }
        if (shouldExit)
            break;
    }
}

When I push the first value, it successfully pushes into the array. But when I push any more values, the initial values are simply replaced by the new push value.

Output (Pastebin):

Output image

Why is this happening? I am really confused about this. Any help is appreciated.

François Andrieux
  • 28,148
  • 6
  • 56
  • 87
  • 1
    First, **why** are you even using a `void**`? Secondly, please provide a [mre] (minimal being the key word). Third, `int x; ... push(&x);` is UB. – ChrisMM May 04 '21 at 15:04
  • 1
    You store reference to local variable so dangling pointer. – Jarod42 May 04 '21 at 15:06
  • 1
    I am assuming this is to learn the language, I have a small suggestion, make it work with a type (int for instance), than learn about templates and the upgrade will be easier than dealing with void* poiters – Alessandro Teruzzi May 04 '21 at 15:07
  • 2
    FYI, you never delete `data`, so you are leaking memory every time you `push`. – 0x5453 May 04 '21 at 15:07
  • 1
    @ChrisMM `int x; ... push(&x);` is not UB. `printf("%d ", *((int *)ints.get(i)));` is UB (dereferencing of dangling pointer). – MikeCAT May 04 '21 at 15:10
  • @ChrisMM I actually want to compile Array.h as a library so I don't want to stick to a certain type of data – Saumitra Topinkatti May 04 '21 at 15:11
  • 1
    Whatever book, tutorial or class you're following, it does a bad job at explaining the basics of C++. Why are you using `scanf` and `printf`? Please invest in [some good books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) to learn proper C++ from the start. – Some programmer dude May 04 '21 at 15:11
  • 1
    @MikeCAT, yes, should have said _using_ that value is UB. Too late to edit now. – ChrisMM May 04 '21 at 15:13
  • @MikeCAT My fault. I forgot that I was passing the address of x. It all makes sense now. Thanks. – Saumitra Topinkatti May 04 '21 at 15:14
  • 2
    @SaumitraTopinkatti Templates is useful to create libraries that works with various types. – MikeCAT May 04 '21 at 15:14
  • @MikeCAT Initially, I made it using templates, but then for some reason extern didn't like templates, so the other alternative for generic data types was this one. – Saumitra Topinkatti May 04 '21 at 15:16
  • 1
    @SaumitraTopinkatti https://stackoverflow.com/questions/6200752/c-header-only-template-library the extern keyword historically never really worked with templates – Alessandro Teruzzi May 04 '21 at 15:20
  • @AlessandroTeruzzi Exactly, that's why I used void**. – Saumitra Topinkatti May 04 '21 at 15:24
  • @0x5453 So before I re-assign the data, I must delete[] it? – Saumitra Topinkatti May 04 '21 at 15:26
  • 2
    @SaumitraTopinkatti well, I would say you should create an header only library. There is no much value in a non-type-safe library in C++, but it is just my humble opinion. – Alessandro Teruzzi May 04 '21 at 15:27
  • @AlessandroTeruzzi Is there any alternative for template? I don't want the array to only store integers, or floats, or whatever, it should be able to store objects as well. – Saumitra Topinkatti May 04 '21 at 15:35
  • @SaumitraTopinkatti "*Initially, I made it using templates, but then for some reason extern didn't like templates*" - why were you trying to use `extern` with a template at all? "*I don't want the array to only store integers, or floats, or whatever, it should be able to store objects as well*" - in the same array? If so, then you need to use [`std::variant`](https://en.cppreference.com/w/cpp/utility/variant) or [`std::any`](https://en.cppreference.com/w/cpp/utility/any) for the array element type. But, if you want to use different types in different arrays, then a simple template will suffice – Remy Lebeau May 04 '21 at 16:30

1 Answers1

1

The local variable int x; will vanish when the execution of its block ends, and after that you must not dereference pointer to that.

Instead of pushing &x, you have to allocate new region to store value and push its pointer.

ints.push(new int(x));

The next step will be defining a copy constructor, an assignment operator, and a destructor to handle the array properly (follow The Rule of Three) and fixing the memory leaks.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • I get it now. I forgot that I was passing the memory address of the int x. Thank you. – Saumitra Topinkatti May 04 '21 at 15:13
  • However, `push()` takes a `void*` and has no concept that a `new`'ed `int*` is being passed in, so the `Array` won't be able to `delete` the `int*` correctly at a later time. – Remy Lebeau May 04 '21 at 16:27