简体   繁体   中英

How to I Properly Dereference a pointer to a pointer array?

I'm working on an assignment involving string pointers. There are two functions. The first takes in an array of strings, places the address of each element into a separate array, and then returns the pointer to that array. The second function takes the pointer that was returned and prints out the elements of the original array with just the pointer. But when I test it, the dereferenced string** ptrToPtr is different in each pointer. I want to know why

Here is Function 1:

string** arrayOfPtrs(string arr[], int size)
{
  string* ptrArray; //The array of string pointers
  string** ptrToPtr; //A pointer to the array of string pointers
  ptrArray = new string[size];
  //ptrArray = arr;
  int i = 0;

  while (i < size)
  {
    ptrArray = &arr[i];
    i++;
    ptrArray++;
  }

ptrToPtr = &ptrArray;
return ptrToPtr;
}

Here is Function 2:

void outputArray(string** arr, int size)
{
   int count = size; //An int variable that stores the size of array
   string* ptr = *arr; //A pointer that stores the address to the last    element
                   //in the string pointer array

    while (count > 0)
    {
       cout << *(ptr - count) << " ";
       count--;
    }
   cout << endl;
  }

And here is part of main():

string strArr[] = { "echo", "charlie", "delta", "bravo", "delta" };
string** strPtrs;

strPtrs = arrayOfPtrs(strArr, 5);
cout << "Actual results: ";
outputArray(arrayOfPtrs(strArr, 5), 5);
cout << endl << endl;

I'm I going wrong anywhere? Or is there a better way to deference a pointer to a string pointer?

Here is a similar program ran completely in main:

int main()
{
string words[30];
string* s;
s = new string[30];
string** t;
createArray(30, words); 
int num = 0;
t = &s;
while (num < 30)
{
    s = &words[num];
    num++;
    s++;
}
string* u = *t;
int j = 30;
for (int i = 0; i < 30; i++)
{
    cout << "*(s - " << j << ") - " << *(s - j) << endl;
    cout << "words[ " << i << " ] - " << words[i] << endl;
    cout << "*(u - " << j << " ) - " << *(u - j) << endl << endl;
    j--;
}
}

And this program works perfectly. Any ideas?

This is incorrect:

while (i < size)
{
  ptrArray = &arr[i];
  i++;
  ptrArray++;
}

Replace ptrArray = &arr[i]; with *ptrArray = arr[i]; . As it stands now, you're just overwriting the same pointer each time through the loop and never doing anything useful with it.

This is also incorrect:

string* ptrArray; //The array of string pointers
// ...
ptrToPtr = &ptrArray;
return ptrToPtr;

As soon as you return that, it becomes dangling. You're not allowed to use pointers to local (stack) variables once they're out of scope.

Firstly, I see a few problems in your setup

  1. You don't need this for practical reasons. If you want to have the address of each element in the array, you can calculate it by incrementing the pointer to the first element (which is the array in fact). If you only do that for educational reasons forget about this
  2. string* ptrArray = new ... Now you have an array of strings (array is semantically equaivalent to pointer to first element). But you want an array of string pointers. So you need string** ptrArray = new ... and this cascades to the rest of the function being incorrect.

  3. You never delete the array allocated with new . This results in the memory not being free'd. You need to delete[] *strPtrs; in your last code snippet to free the memory you allocated in your method. In general it is a good idea to let the one who allocates the memory be responsibly for freeing it. I show you another idea below to handle this.

  4. After your copy operations the pointer points past your array. Then you return a pointer to it. You applied the correct arithmetics when outputting the values in you second snippet, but I would never want to have such a pointer going around. Conventionally it should point to the first element. At least when deleting the array-pointer it has to point to the first element, otherwise you get undefined behavior eg deleting another array.

Lastly:

string* ptrArray; //The array of string pointers
string** ptrToPtr; //A pointer to the array of string pointers

ptrToPtr points to ptrArray, which is a local variable. It becomes invalid when leaving the function and thus it will be undefined behavior to dereference the returned pointer.

There is a common approach used by some standard libraries (eg snprintf from cstdio), so the caller is responsible for allocation and deallocation:

void arrayOfPtrs(string arr[], int size,/*new param*/ string** outArray)
{
  string** iter = outArray; // Iterator pointer

  int i = 0;

  while (i < size)
  {
    *iter = &arr[i];
    i++;
    iter++;
  }
}

What happens here, is that the caller gives the function a pointer to the pointers (it points to the first pointer). Note that a pointer can be used as an array with index operators etc. So it is in fact an array of pointers. You then fill it by incrementing the copied pointer so it jumps from pointer element to pointer element. Where the array actually is stored is not the problem of this function.

Use it like this:

// Variant 1: Use local variable if size is constant
string* arr[5];
arrayOfPtrs(strArr, 5, arr);
std::cout << *arr[0]; // Dereferences a pointer in arr to get the string which is actually in strArr

// Variant 2: Allocate heap memory (if you need dynamic size)
int size ...; // From somewhere
string** arr = new string[size];
arrayOfPtrs(strArr, size, arr);
std::cout << *arr[0]; // Same again
... // Do further work
delete[] arr; // Free memory

So you have to allocate memory (or use a local variable) before you call the function and then pass it to the function. In the double pointer, the first * is meant for the data type which is "pointer to string" and the second designates it as a "pointer-array".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM