How to Make an Array with a Dynamic Size? General Usage of Dynamic Arrays (Maybe Pointers Too)

How to make an array with a dynamic size? General usage of dynamic arrays (maybe pointers too)?

For C++:

If you just need a container just use std:vector. It will take care all the memory allocations necessary for you. However if you want to develop your own dynamic container (whatever reasons you have) you have to take care off the memory allocations yourself. That is, when your array grows you have to allocate new memory chunk, copy present array values to the new memory location and add new values to the newly allocated memory. Usually one wraps this kind of logic inside a separate class e.g. GrowingArray(like standard provided vector class)

EDIT

To elaborate more on my answer (given that you are using this for learning purpose):

store it in an array without a starting size (i.e. not -> array[5];)

Here you want to use something like this: int * myDynamicArray;
When a user inputs some values you allocate memory chunk where those values are going to be stored: myDynamicArray = new int[5]; with the size of your initial input. I would as well recommend to save the size of the array in some variable: int arraySize = 5;
If later on you want to append new values to your myDynamicArray first of all you have to allocate new memory chunk for grown array (current array elements + new array elements). Lets say you have 10 new values coming. Then you would do: int* grownArray = new int[arraySize+10]; this allocates new memory chunk for grown array. Then you want to copy items from old memory chunk to the new memory chunk and add user appended values (I take it you are using this for learning purposes thus I provided you simple for cycle for copying elemts. You could use std:copy or c like memcopy as well):

int i = 0;
for (; i < arraySize; ++i)
{
grownArray[i] = myDynamicArray [i];
}
// enlarge newly allocated array:
arraySize+= 10;
for (; i < arraySize; ++i)
{
grownArray[i] = newValues from somewhere
}
// release old memory
delete[] myDynamicArray;
// reassign myDynamicArray pointer to point to expanded array
myDynamicArray = gronwArray;

C dynamically growing array

I can use pointers, but I am a bit afraid of using them.

If you need a dynamic array, you can't escape pointers. Why are you afraid though? They won't bite (as long as you're careful, that is). There's no built-in dynamic array in C, you'll just have to write one yourself. In C++, you can use the built-in std::vector class. C# and just about every other high-level language also have some similar class that manages dynamic arrays for you.

If you do plan to write your own, here's something to get you started: most dynamic array implementations work by starting off with an array of some (small) default size, then whenever you run out of space when adding a new element, double the size of the array. As you can see in the example below, it's not very difficult at all: (I've omitted safety checks for brevity)

typedef struct {
int *array;
size_t used;
size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
a->array = malloc(initialSize * sizeof(int));
a->used = 0;
a->size = initialSize;
}

void insertArray(Array *a, int element) {
// a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
// Therefore a->used can go up to a->size
if (a->used == a->size) {
a->size *= 2;
a->array = realloc(a->array, a->size * sizeof(int));
}
a->array[a->used++] = element;
}

void freeArray(Array *a) {
free(a->array);
a->array = NULL;
a->used = a->size = 0;
}

Using it is just as simple:

Array a;
int i;

initArray(&a, 5); // initially 5 elements
for (i = 0; i < 100; i++)
insertArray(&a, i); // automatically resizes as necessary
printf("%d\n", a.array[9]); // print 10th element
printf("%d\n", a.used); // print number of elements
freeArray(&a);

C++ Reallocating pointer to array in dynamic memory in a different function

Without checking the logic of the implementation, your list doesn't update because you are assigning my_list = new_string_ptr; but your function received void add_name_to_list (string * my_list, size_t *list_size).

As you are newcomer to C++ world, let me explain clearly:
list_size is a pointer to a size_t, so if you modify the pointed memory, the change will persist, but if you modify the pointer itself, it will not.

list_size = new size_t; // This change doesn't persist
list_size++; // This change doesn't persist

*list_size++; // This change persists and the value of pointed memory was increased.

With my_list is happening exactly the same, you are trying to modify the pointer itself, not the pointed memory.

So, you should use:

void add_name_to_list (string * &my_list, size_t *list_size)

Or maybe you are more confortable with

void add_name_to_list (string ** my_list, size_t *list_size)
[...]
*my_list = new_string_ptr;

Hope this helps

c++ dynamic array of pointers

According to the C++ Standard (4.2 Array-to-pointer conversion)

1 An lvalue or rvalue of type “array of N T” or “array of unknown
bound of T” can be converted to a prvalue of type “pointer to T”. The
result is a pointer to the first element of the array.

So for example if you have an array like this

int a[] = { 1, 2, 3, 4, 5 };

then in this declaration

int *p = a;

the array designator used as the initializer is implicitly converted to pointer to its first element.

So in general if you have array

T a[N];

then in expressions with rare exceptions it is converted to pointer to its first element of the type T *.

In this declaration

int **arr = new int*[10]; 

the initializer is an array elements of which has the type int *. You can introduce a typedef or an alias declaration

typedef int * T;

or

using T = int *;

So you can write

T * arr = new T[10]; 

that is the pointer arr points to the first element of the dynamically allocated array. As the elements of the array has the type int * then the type of the pointer to an element of the array is int **.

That is the operator new returns pointer to the first element of the dynamically allocated array.

Dynamic array of Linear search funcion implementation

At very first I join in the std::vector recommendation in the question's comments (pass it as const reference to avoid unnecessary copy!), that solves all of your issues:

std::vector<size_t> linearSearch(std::vector<int> const& array, int value)
{
std::vector<size_t> occurrences;
// to prevent unnecessary re-allocations, which are expensive,
// one should reserve sufficient space in advance
occurrences.reserve(array.size());
// if you expect only few occurrences you might reserve a bit less,
// maybe half or quarter of array's size, then in general you use
// less memory but in few cases you still re-allocate

for(auto i = array.begin(); i != array.end(); ++i)
{
if(*i == value)
{
// as using iterators, need to calculate the distance:
occurrences.push_back(i - array.begin());
}
}
return occurences;
}

Alternatively you could iterate with a size_t i variable from 0 to array.size(), compare array[i] == value and push_back(i); – that's equivalent, so select whichever you like better...

If you cannot use std::vector for whatever reason you need to be aware of a few issues:

You indeed can get the length of an array by sizeof(array)/sizeof(*array) – but that only works as long as you have direct access to that array. In most other cases (including passing them to functions) arrays decay to pointers and these do not retain any size information, thus this trick won't work any more, you'd always get sizeOfPointer/sizeOfUnderlyingType, on typical modern 64-bit hardware that would be 8/4 = 2 for int* – no matter how long the array originally was.

So you need to pass the size of the array in an additional parameter, e.g.:

size_t* linearSearch
(
int* array,
size_t number, // of elements in the array
int value // to search for
);

Similarly you need to return the number of occurrences of the searched value by some means. There are several options for:

  1. Turn num into a reference (size_t& num), then you can modify it inside the function and the change gets visible outside. Usage of the function get's a bit inconvenient, though, as you need to explicitly define a variable for:
size_t num = sizeof(array)/sizeof(*array);
auto occurrences = linearSearch(array, num, 7);

  1. Append a sentinel value to the array, which might be the array size or probably better maximum value for size_t – with all the disadvantages you have with C strings as well (mainly having to iterate over the result array to detect the number of occurences).
  2. Prepend the number of occurrences to the array – somehow ugly as well as you mix different kind of information into one and the same array.
  3. Return result pointer and size in a custom struct of yours or in e.g. a std::pair<size_t, size_t*>. You could even use that in a structured binding expression when calling the function:
auto [num, occurences] = linearSearch(array, sizeof(array)/sizeof(*array), 7);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// here the trick yet works provided the array is declared above the call, too,
// as is in your example

Option 4 would be my personal recommendation out of these.

Side note: I switched to size_t for return values as negative indices into an array are meaningless anyway (unless you intend to use these as sentinel values, e. g. -1 for end of occurrences in option 2).

C++: How to apply changes to dynamic array cross functions?

You have to pass a reference to a pointer to your function:

void addCoffee(Coffee *&c, int &amount){
// ^^ c is input and output
string name;
amount++;
Coffee * temp = new Coffee[amount];

for(int i=0;i<amount-1;i++){
temp[i] = c[i];
}

cout<<"What is the coffee's name?: ";
cin>>name;
temp[amount-1].setName(name);

delete [] c; // delete old array
c = temp; // assign new array pointer to c
}

But I recommend to use std::vector instead of dynamic arrays.

void addCoffee( std::vector<Coffee> &c ){

cout<<"What is the coffee's name?: ";
cin>>name;
c.push_back( Coffee( name ) );
}


Related Topics



Leave a reply



Submit