如何正确取消对指针的引用?

时间:2018-10-06 01:26:45

标签: c++ arrays string pointers

我正在处理涉及字符串指针的作业。有两个功能。第一个输入字符串数组,将每个元素的地址放入单独的数组,然后将指针返回到该数组。第二个函数获取返回的指针,并仅使用指针打印出原始数组的元素。但是,当我测试它时,每个指针中被取消引用的字符串** ptrToPtr是不同的。我想知道为什么

这是功能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;
}

这是功能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;
  }

这是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;

我在哪里出错?还是有更好的方法将指针指向字符串指针?

这是一个完全在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--;
}
}

该程序运行完美。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

这是不正确的:

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

ptrArray = &arr[i];替换为*ptrArray = arr[i];。就目前而言,您每次遍历循环都只是覆盖相同的指针,而永远不会做任何有用的事情。

这也不正确:

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

一旦return,它就会晃来晃去。一旦它们超出范围,就不允许使用指向局部(堆栈)变量的指针。

答案 1 :(得分:0)

首先,我发现您的设置中存在一些问题

  1. 出于实际原因,您不需要这样做。如果要获得数组中每个元素的地址,可以通过增加指向第一个元素(实际上是数组)的指针来进行计算。如果您只是出于教育原因而这样做,那就算了
  2. string* ptrArray = new ...现在,您有了一个字符串数组(数组在语义上等同于指向第一个元素的指针)。但是,您需要一个字符串指针数组。因此,您需要string** ptrArray = new ...,并且此错误级联到其余函数。

  3. 您永远不会删除使用 new 分配的数组。这导致内存无法释放。您需要在最后一个代码段中delete[] *strPtrs;释放您在方法中分配的内存。通常,最好是让负责分配内存的人负责地释放它。我在下面为您展示了另一个解决方案。

  4. 复制操作完成后,指针指向数组。然后,您返回一个指向它的指针。在第二个代码段中输出值时,您应用了正确的算法,但我永远不会希望有这样的指针。按照惯例,它应该指向第一个元素。至少在删除数组指针时,它必须指向第一个元素,否则会出现未定义的行为,例如删除另一个数组。

最后:

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

ptrToPtr指向ptrArray,这是一个局部变量。离开该函数时它将变为无效,因此取消引用返回的指针将是不确定的行为。

某些标准库(例如cstdio的snprintf)使用一种通用方法,因此调用方负责分配和释放:

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++;
  }
}

这里发生的是,调用者为函数提供了一个指向指针的指针(它指向第一个指针)。请注意,指针可以与索引运算符等一起用作数组。因此,实际上它是指针数组。然后,通过增加复制的指针使其填充,使其从指针元素跳到指针元素。实际存储数组的位置不是此函数的问题。

像这样使用它:

// 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

因此,在调用函数之前,必须先分配内存(或使用局部变量),然后再将其传递给函数。在双指针中,第一个*用于表示“指向字符串的指针”的数据类型,第二个将其指定为“指针数组”。