这是函数的原型,sum
,我用来汇总两个任意数组的元素。
double **sum(double **A, double **B, int M, int N);
它们都作为双指针传递(不要问为什么),M
和N
应该分别是数组的维度。
我遇到的麻烦是,在函数的实现中,访问数组的元素。我试过“引用”数组(或者我认为),但无济于事。以下是我尝试过的事情:
> *A; // Gives me an address, 0xf5c28f5c, not a number
> **A; // Error
> &A; // Gives me the address of A
这就是我将数组传递给sum
的方法,如果它有用的话:
double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};
sum( (double **) a, (double **) b, 4, 4);
所以问题是,当我通过指针/双指针传递时,我应该如何获取数组中的元素?
答案 0 :(得分:3)
您的数组通道功能完全不正确。双指针最好被认为是指向指针的指针。以同样的方式,指针是一个变量,它将地址保存到某个地方的内存中,指向指针的指针保存一个类似的地址,它所引用的内存恰好是另一个指针占用的内存。最好通过示例来描述:
include <stdio.h>
int main(int argc, char* argv[])
{
int a = 5;
int *p = &a;
int **pp = &p;
printf("pp=%p, &p=%p, p=%p, &a=%p *p=%d\n", pp, &p, p, &a, *p);
return 0;
}
在我的MBA 64位上,这给了我们:
pp=0x7fff50828bc8, &p=0x7fff50828bc8, p=0x7fff50828bd4, &a=0x7fff50828bd4 *p=5
掌握这一点,我认为你会在你的代码中发现你的问题,其中第一个问题就是强调“a”和“b”的双重指针。也许试试他们的地址。其次,你可能想要重新审视你如何使用这些指针来解释你的函数,因为很可能需要工作。
答案 1 :(得分:2)
问题不在于在函数内部从double**
检索值时,这是微不足道的。问题是你正在创建一个数组而不是一组指针。您的函数不能接受此参数作为参数,当您尝试使用(double**)
进行投射时,A
参数会在**
进行访问时导致访问冲突。
double** sum(double** A, int size)
{
printf("First element: %f", A[0][0]); // Print the first element
printf("Last element: %f", A[size-1][size-1]); // Print the last element.
return A;
}
const unsigned int SIZE = 4;
double** a = new double*[SIZE];
for(int i=0; i<SIZE; i++)
{
a[i] = new double[SIZE];
}
a = sum(a, SIZE);
使用像这样的指针(而不是专门用于处理这些情况的容器)的最大痛苦是你的记忆管理可能会失控。
for(int i=0; i<SIZE; i++)
{
delete [] a[i]; // Free the inner array
}
delete [] a; // Free the outer array.
答案 2 :(得分:1)
如果函数获取指向double
的指针,并且您从实际数组开始,那么您需要复制数组的地址,然后传递对该数据的引用:
double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};
double *aPtr = a;
double *bPtr = b;
sum(&aPtr, &bbtr, 4, 4);
在sum
函数中,取消引用以返回数组:*A[0]
。
答案 3 :(得分:1)
显而易见的解决方案是将数组作为指针传递,而不是作为双指针传递:
double sum(double *A, double *B, int M, int N)
{
double ret = 0.0;
for (int i=0; i<M; i++) ret += A[i];
for (int j=0; j<N; j++) ret += B[j];
return ret;
}
double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};
double s = sum( a, b, 4, 4);
printf("The sum is %f\n", s);
......这样做是最简单的事情。但是,如果您受到使用双指针的函数签名的现有API的限制,那可能是因为API希望允许被调用函数能够修改传递给它的指针。传递指向指针的指针允许被调用的函数在需要时写入指向指针,例如:
double sum_and_change_pointers(double ** A, double ** B, int M, int N)
{
// Compute sum
double ret = 0.0;
for (int i=0; i<M; i++) ret += (*A)[i];
for (int j=0; j<N; j++) ret += (*B)[j];
// And just for fun, modify the caller's pointer-values too
static double some_other_array[5] = {0,0,0,0,0};
*A = some_other_array;
*B = some_other_array;
return ret;
}
在这种情况下,函数将被调用如下:
double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};
double * pa = a; // copy address of arrays into pointers
double * pb = b; // because changing the address of an array itself wouldn't work
printf("Before calling sum_and_change_pointers, pa=%p and pb=%p\n", pa, pb);
double s = sum_and_change_pointers( &pa, &pb, 4, 4);
printf("After calling sum_and_change_pointers, s=%f, pa=%p and pb=%p\n", s, pa, pb);
另一个注意事项:在您发布的代码中,您的函数返回(双**)而不是双精度。我不认为这可以轻松工作;首先,一个名为sum的函数可能会返回一个双精度浮点值,而不是一个指向指针的指针,因此让它返回一个(double **)是没有意义的......但是即使你(由于某种原因)想要这样做,你需要确保你返回的指针指针指向内存中的有效位置(并且该位置指向一个位置)在内存中的有效位置),这在函数内部很难处理,因为函数返回时所有函数的局部变量都会消失。如果您不介意丢失线程安全性,我想您可以使用静态或全局变量来执行此操作:
double ** sub (double ** A, double ** B, int M, int N)
{
// Compute sum
double ret = 0.0;
for (int i=0; i<M; i++) ret += (*A)[i];
for (int j=0; j<N; j++) ret += (*B)[j];
static double result;
result = ret;
static double * pointerToResult;
pointerToResult = &ret;
return &pointerToResult;
}
[...]
double ** s = sum( a, b, 4, 4);
printf("Sum's result was %f\n", **s);
......但同样,这实际上是丑陋,不安全,无益的。为你想做的工作使用正确的类型要好得多。