2

I am new to C++ programming and want to try out manual memory management (I am aware that it is advised not to use manual memory management, but I still want to give it a try).

My goal was to write a function that can append an element to an array by using realloc.

I use this struct:

struct pathToCity{  
  int lengthCities;
  char cities[100];
};

Here is my function:

void appendToPathToCitiesArray(pathToCity **array, int *length, pathToCity newCity) {
  if (*length == 0) {
    *array = (pathToCity*) malloc(sizeof(pathToCity));
  }
  else {
    *array = (pathToCity*) realloc(*array, (*length + 1) * sizeof(pathToCity));
  }
  if (array == NULL) {
    cout << "Error allocating memory." << endl;
    exit(-1);
  }
  (*array)[*length] = newCity;
  (*length)++;
}

Here I define an array:

int lengthQueue = 0;
    pathToCity *queue;

Here I instantiate an instance of my struct:

pathToCity newPath = {0, ""};

Finally I use my function:

appendToPathToCitiesArray(&queue, &lengthQueue, newPath);

This function works fine as it is using double pointers. According to my research (unfortunately I cannot find the stackoverflow post where this was explained) double pointers here are necessary, because once a pointer gets passed to a function, it is impossible to change the pointer inside the function. Therefore double pointers are required once I want to use realloc to update my array.

But I have also tried this in a different file:

#include <iostream>


using namespace std;



struct shortText {
    int lengthText;
    char text[3];
};


void append(shortText *array, int *length, shortText newCity) {
  if (*length == 0) {
    array = (shortText*) malloc(sizeof(shortText));
  }
  else {
    array = (shortText*) realloc(array, (*length + 1) * sizeof(shortText));
  }
  if (array == NULL) {
    cout << "Error allocating memory" << endl;
    exit(-1);
  }
  array[*length] = newCity;
  (*length)++;
}


int main() {

  int length = 3;
  shortText *arr = (shortText*) malloc(sizeof(shortText) * length);
  
  arr[0] = {2, "ab"};
  arr[1] = {2, "ab"};
  arr[2] = {2, "ab"};

  shortText s = {2, "ab"};
  append(arr, &length, s);

  arr[3] = {8, "ji"};

  cout << length << endl;
  cout << arr[3].lengthText << endl;





  free(arr);
}

It also works perfectly and does not use double pointers. Why are double pointers necessary in one case and why not in the other?

If you require any more information, please ask. I have not provided the entire first code, to give a better overview, if I have missed out an important part, I will post the rest of the code.

8
  • I am aware that it is advised not to use manual memory management, but I still want to give it a try Why? It is rarely used (or useful) in real-world code and there are many more interesting things to do. Commented Jul 24, 2023 at 21:51
  • 4
    I am new to C++ The whole code except std::cout is C. Commented Jul 24, 2023 at 21:54
  • 2
    Create your own std::vector class if you want to know how to handle dynamically allocated memory properly in C++. What you have done is as mentioned, just plain old C. Plus none of this even works if you had tried this if pathToCity contained a std::string or another non-trivially-copyable type. Commented Jul 24, 2023 at 21:57
  • struct pathToCity{ int lengthCities; std::string cities; }; -- Now all of those malloc and realloc calls are worthless, as they will invoke undefined behavior. Commented Jul 24, 2023 at 22:03
  • @273K I would say that C wouldn't requre those casts on malloc. but they are definitely in C style Commented Jul 24, 2023 at 22:08

1 Answer 1

3

Using the second function implementation invokes undefined behavior.

It just occurred such a way that the called function realloc did not change the address stored in the pointer arr. That is the function just enlarged the initial extent of memory. But in general it can allocate another extent of memory at a different address. In this case the pointer arr declared in main will be invalid.

You need to pass a pointer to pointer because dereferencing the pointer to pointer you get a direct access to the original pointer arr and thus can change it within the function. Otherwise the function will deal with a copy of the value of the original pointer and changing the copy will not influence on the original pointer.

It is the so-called pass by reference in the C meaning.

Compare these two demonstration program.

#include <iostream>

typedef int T;

void f( T x )
{
    x = T();
}

int main()
{
    T x = 10;

     std::cout << "Before calling f() x = " << x << '\n';

     f( x );

     std::cout << "After  calling f() x = " << x << '\n';
}

and

#include <iostream>

typedef int T;

void f( T *x )
{
    *x = T();
}

int main()
{
    T x = 10;

     std::cout << "Before calling f() x = " << x << '\n';

     f( &x );

     std::cout << "After  calling f() x = " << x << '\n';
}

There is used the typedef intentially

typedef int T;

to show that instead of the type int there can be used also a pointer type as for example int *

typedef int * T;

Only in main you should write

int value;
T x = &value;

and call the function f in the both demonstration programs.

In C++ you could just pass the pointer by reference like

void append(shortText * &array, int &length, shortText newCity);

Pay attention to that this call of realloc

array = (shortText*) realloc(array, (*length + 1) * sizeof(shortText));

is unsafe and can result in a memory leak if the function will be unable to allocate a new extent of memory and will return a null pointer. You should use an intermediate pointer as for example

shortText *tmp = (shortText*) realloc(array, (*length + 1) * sizeof(shortText));

if ( tmp != nullptr ) array = tmp;
Sign up to request clarification or add additional context in comments.

1 Comment

Note length was also changed into a reference. In general you have to work harder to shoot yourself in the foot with a reference than you do with a pointer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.