在C ++中调用指针函数

时间:2015-06-16 06:55:20

标签: c++ pointers multidimensional-array

我用C ++编写了一段代码。我从搜索引擎结果中获取了第一部分。

1)使用CREATE TABLE IF NOT EXISTS `sn_follows` ( `id` int(11) NOT NULL, `from` int(11) NOT NULL, `to` int(11) NOT NULL, `date` int(11) NOT NULL ) ENGINE=MyISAM AUTO_INCREMENT=74 DEFAULT CHARSET=utf8; 定义函数的含义是什么?我们可以使用指针定义函数吗?

2)我对以下几行感到困惑:

double **filter_2d

它工作不正常,我不明白为什么。

double **filt_out = filter_2d(A, 3, 3, B, 2, 1);

8 个答案:

答案 0 :(得分:9)

指针声明
一般格式:

\\abc/

指针声明,例如

data_type *pointer_name;

将numberPtr声明为指向整数变量的变量。其内容是内存地址

*表示声明的变量是指针变量而不是普通变量。

考虑以下声明:

int *numberPtr; 

在这种情况下,保留了两个内存地址,与名称numberPtr和number相关联。

变量号中的值是整数类型,变量numberPtr中的值是另一个内存位置的地址。

实施例

int *numberPtr, number = 20;  

答案 1 :(得分:3)

您的功能需要double**,而您正在通过double [3][3]。这些类型没有隐式转换。

您需要在main()中为double **创建数组,并将其用作函数调用中的参数。

问题 - conversion of 2D array to pointer-to-pointer应该可以帮助您实现您想要做的事情。

您的cout似乎也不正确。您正在考虑filt_out作为2D数组而不是指针。

for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 4; j++)
    cout  << **(filt_out + i + j) << endl;   //changed here
}

答案 2 :(得分:2)

我已经分析了您的代码,我认为我发现了一些问题。

这是新代码:

#include <iostream>
#include <stdlib.h>

using namespace std;


double** filter_2d(double** image, int width_image, int height_image, double** kernel, int width_kernel, int height_kernel)
{
    int i, j, p, q;

    //this is the case of 'full' option selected in matlab
    double **output = (double **)malloc(sizeof(double *) * (width_image + width_kernel - 1));
    for (i = 0; i<width_image + width_kernel - 1; i++)
        output[i] = (double *)malloc(sizeof(double) * (height_image + height_kernel - 1));

    //for each point in the output
    for (i = 0; i<width_image + width_kernel - 1; i++)
        for (j = 0; j<height_image + height_kernel - 1; j++)
        {
            output[i][j] = 0;
            //kernel(p,q)*image(i-p, j-q) 
            for (p = 0; p<width_kernel; p++)
            {
                //avoid unnecessary comparisons
                if (i - p < 0)
                {
                    break;
                }
                else if (i - p < width_image)
                {
                    for (q = 0; q<height_kernel; q++)
                    {
                        //idem as above
                        if (j - q < 0)
                            break;
                        else if (j - q < width_image)
                            output[i][j] += kernel[p][q] * image[i - p][j - q];
                    }
                }
            }
        }

    return output;
}


int main()
{
    double A[3][3] = { { 1, 2, 3 },
                       { 4, 5, 6 },
                       { 7, 8, 9 } };
    double *A_ptr[9];

    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j ++)
            A_ptr[i * 3 + j] = &(A[i][j]);


    double B[1][2] = { 1, 2 };
    double *B_ptr[2];

    for (int i = 0; i < 1; i++)
        for (int j = 0; j < 2; j ++)
            B_ptr[i * 1 + j] = &(B[i][j]);

    //no more errors in the function call
    double **OutImage = filter_2d(A_ptr, 3, 3, B_ptr, 2, 1);

    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 3; j++)
            cout << OutImage[i][j] << " ";
        cout << endl;
    }


    return 0;
}

我认为更好的想法是函数filter_2d返回指向输出矩阵的指针。输出矩阵在函数内部使用malloc动态分配,因此如果将地址返回并将其存储回main,它将不会丢失(并且您可以在矩阵中获取计算值)。

你可以在这里看到堆栈内存和函数本地变量与堆内存之间的比较以及用malloc分配的变量stack vs heap

现在我将谈谈我在main函数中发现的一些问题。第一个问题是指针A_ptr和B_ptr数组的初始化。

double *A_ptr[9];
for (int i = 0; i < 10; i++)
{
    A_ptr[i] = A[i];
}

double *B_ptr[2];
for (int i = 0; i < 2; i++)
{
    B_ptr[i] = B[i];
}

根据我在代码中的理解,A_ptr和B_ptr的元素是指向数组A和B的每个元素的指针。

因此,由于A_ptr和B_ptr是线性化矩阵,因此必须小心从数组A和B中提供相应元素的正确地址。

如果你取矩阵M并将其线性化为矩阵N,则元素M [i] [j]将转到N [i * number_of_columns_from_M + j]。

另一个问题是你打印结果的for循环中i和j的限制。

for (int i = 0; i < 5; i++)
{
    for (int j = 0; j < 4; j++)
        cout << *OutImage << endl;
}

根据我的计算,在filter_2d函数中,您可以分配4行和3列的矩阵。在这些周期中,您假设OutImage有5行和4列。

最后一个问题是从OutImage打印元素。

cout << *OutImage << endl;

你在代码中声明的OutImage是一个包含9个指针的数组(不明白为什么你这样做)。使用上面的指令,您将重复打印OutImage数组的第一个元素(这是一个地址,因为OutImage是一个包含9个指针的数组),这就是为什么您只看到打印的地址。

我不确定现在在屏幕上打印的数字是否正确,因为我不知道在filter_2d中进行了什么数学计算。

答案 3 :(得分:1)

将C ++指针上下文中的*读为pointer to会有所帮助。

int * a;

a是指向int的指针。

int ** b;

b是指向int的指针。

b =&amp; a;

a是指向int的指针。 &a是指向int的指针的地址。 b是指向指向 int的指针。

* a = 10;

将10存储在a指向的内存中。

** b = 20;

将{20}存储在int*所指向的b指向的内存中。

#include <iostream>

int main()
{
    int i = 1234;
    int* a;
    int** b;

    std::cout << "i is " << i << ", it's address is " << i << "\n";

    a = &i;

    std::cout << "a = " << a << ", *a = " << *a << ", its address is " << &a << "\n";

    b = &a;
    std::cout << "b = " << b << ", *b = " << *b << ", **b = " << **b << ", its address is " << &b << "\n";
}

现场演示:http://ideone.com/OpCro4

您的函数“filter_2d”返回指针的地址。它还希望第一个参数是指针的地址。

这通常被用作允许函数说“给我指针的地址并且我会为你填充它”的方法,但是C ++也使用指针来传递数组。

int a[100];
f(a);

程序可以将所有100个地址传递给f(),这将要求堆栈上的100个或100个寄存器。

或者,它可以传递a中第一个int的地址。在C和C ++中,通常是数组如何工作 - 它们作为数组和偏移量运行。

int a[100];
int* b = a;  // b points to the first element in a

// these two mean the same thing
a[90];
*(b + 90);

// undefined behavior
*(b + 100); // the 101st element of a, i.e. invalid

缺点:指针只知道它们指向的元素,它们本质上不了解数组长度。

最后,代替SYSTEM("PAUSE")使用“Ctrl + F5”启动而不进行调试(执行后会自动提示您返回)或使用“F11”进入程序。

答案 4 :(得分:1)

您的代码有两个问题:

首先,我假设输出图像与输入图像具有相同的大小,因此必须像这样分配:

(double **)malloc(sizeof(double *)*(width_image * height_image));

其次,你定义了一个将返回一个2D指针的函数,但不幸的是,你在函数本身内部声明了这个2D指针,这意味着你定义了一个局部变量指针。在大多数情况下,一旦你返回这个值,它将完全是错了,它不是在函数本身内分配的那个。

要解决此问题,您可以选择以下两种解决方案之一:

  1. 您可以定义全局2D指针,并且可以在函数内部进行分配,因此您无需定义函数来返回2D指针。
  2. 第二个解决方案是定义将结果存储在调用函数中的2D指针,调用函数将为该指针分配所需的大小并将其传递给被调用函数(即filter_2d),当它通过时,它将通过其地址传递,因此在filter_2d定义中,我们将添加一个额外的参数作为3D POINTER来存储结果,如下所示:
  3. &#13;
    &#13;
    //Define these 2 lines in the main function.
        
        double ** OutImage = null;
        OutImage = (double **)malloc(sizeof(double *)*(width_image * height_image));
    &#13;
    &#13;
    &#13;

    将OutImage传递给filter_2d函数:

    filter_2d(A_ptr, 3, 3, B_ptr, 2, 1, &OutImage);
    

    filter_2d函数的定义应为:

    void filter_2d(double** image, int width_image, int height_image, double** kernel, int width_kernel, int height_kernel, double *** OutImg)
    

    在filter_2d内,您可以按以下方式定义本地变量:

    double **output = *OutImg;
    

    希望这种说法可以帮到你。

答案 5 :(得分:1)

  

我用C ++编写了一段代码。我从第一部分开始   搜索引擎结果。

你是认真的吗?不知道怎么理解。它不是一个调试站点。你应该先做好努力。

无论如何,你的代码主要是C.唯一提醒我C ++的代码就是控制台输出。所以,如果我能提供帮助,请试试......因为我喜欢。

  

1)使用double **filter_2d定义函数的含义是什么?我们可以使用指针定义函数吗?

这意味着函数的结果是指向double类型的指针。像这样分解:

  • **filt_out的类型为double - 用于访问double值; 在2D数组中广泛使用以访问第二维,即2D数组的行和列

  • *filt_out的类型为double * - 用于访问指向double值的指针; 在2D数组中广泛使用以访问第一维,即2D数组的行

  • filt_out的类型为double ** - 用于访问指向double值的指针; 在2D数组中流行使用以访问数组,即为2D数组分配的内存地址

您可以使用简单指针定义函数,但它不适合2D数组。阅读上面的内容。

  

2)我对以下几行感到困惑:

     

double **filt_out = filter_2d(A, 3, 3, B, 2, 1);它不起作用   正确的,我不明白为什么。

对我没有意义。 filter_2d的返回类型为void,因此我不知道为什么要将返回的分配给指向a的指针指向双重

的指针
  

它工作不正常,我不明白为什么。

我也不是。但说实话,这听起来更像是一个调试请求,而不是一个值得投票的问题。特别是你给我们的印象是你首先没有做功课学习C / C ++,其次是从搜索引擎复制代码并要求社区为你解决。

我认为你有一些缺陷需要仔细研究:

(我主要使用C语法)

OutImage = (double **)malloc(sizeof(double *)*(3 * 3));

这对我来说不合适。请验证。

我认为OutImage应该是一个2D数组(图像),因此**OutImage指向2D数组的元素(第二维,你想访问行和列)。

此外,由于它是2D数组,您需要先将第一维(即行)初始化,然后再初始化第二维(即列)。

所以我会建议这样的事情:

//three rows of size for type double*
OutImage = (double **) malloc(sizeof(double *) * 3);

//three columns of size of type double
for (int i=0; i<3; i++)
    OutImage[i] = (double *) malloc(sizeof(double) * 4);

这样您就可以使用OutImage[row][column]进行访问。我相信它不容易出错。我根据函数filter_2d中的计算将列的大小设置为4,该函数计算宽度和高度(宽度与给定的参数保持相同,高度增加一维)。 同样(见下文)函数filter_2d后面我删除了内存分配,因为它已在此处完成。

不确定你想用这个来实现,但我认为......

double *A_ptr[9];
for (int i = 0; i < 10; i++)
    {
        A_ptr[i] = A[i];
    }

在这么多级别上都是错误的。

  • 10没有意义;指数从0到8
  • A [i]的大小为3而A_ptr [i]的大小为9
  • 你在想什么山姆?

考虑到在上面的函数filter_2d中使用A_ptr(以及你访问它的方式),我认为你想要做一些类似于上面2D数组的事情。

double ** A_ptr = (double **) malloc(sizeof (double *) * 3);
for (int i = 0; i < 3; i++)
    A_ptr[i] = (double *) malloc(sizeof (double) * 3);

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        A_ptr[i][j] = A[i][j];
    }
}
double B[1][2] = { 1, 2 };
double *B_ptr[2];
for (int i = 0; i < 2; i++)
{
    B_ptr[i] = B[i];
}

与上述类似。

  • B [i]的大小为1,因此只有索引0才有意义
  • 该死的山姆,你又在想什么?

您使用以下参数调用过滤器:

  • A_ptr:A(图像)的二维数组副本
  • 3:图像第一维尺寸
  • 3:图像的第二维尺寸
  • B_ptr:B(内核)的二维数组副本
  • 2:内核第一维尺寸 - 应与下一个尺寸切换
  • 1:内核第二维的大小 - 应该用前一个切换
  • &amp; OutImage:指向生成的过滤图像的指针的地址(该参数实际上是指向**OutImage的指针)?我想你想在函数调用后保留指针,不是吗?听起来不错。

    filter_2d(A_ptr,3,3,B_ptr,2,1,&amp; OutImage);

您将B_ptr定义为具有尺寸[1] [2]的B的副本,但是您将2作为第一维,将1作为第二维传递给函数。切换B / B_ptr的尺寸或切换两个参数。

在该函数中,我将删除以下代码

for (i = 0; i<width_image + width_kernel - 1; i++)
{
    output[i] = (double *)malloc(sizeof(double)*(height_image + height_kernel - 1));
}

(在为OutImage分配内存时,请参阅上面第一个错误中的上一条评论。)

替换循环以打印结果。看起来像这样:

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++)
        cout << OutImage[i][j] << endl;
}

我保留了C ++风格的打印,但实际上你也可以使用C&#39 {s} printf函数来实现。无需真正包含iostream

这就是它。我编译了你的代码并运行它。不确定会发生什么,但根据你的评论,它应该是

2 5 8 3 8 14 17 6 14 23 26 9
猜猜是什么?我得到了

1 4 7 6 4 13 16 12 7 22 25 18

嗯,我想现在轮到你了。

  

请记住,检查您要在哪里进行内存分配   为了让它考虑到新的尺寸。我很努力   在你的例子中对它进行编码,以使其工作,或多或少。

我可能会分配一个虚拟地址,然后使用realloc根据参数将大小增加到所需的大小。

  

请记住,一般情况下,您需要释放已分配的内存。   我在这里跳过它,因为它是一个简短的程序。

程序看起来像这样:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

void filter_2d(double** image, int width_image, int height_image, double** kernel, int width_kernel, int height_kernel, double *** OutImg) {

    double **output = *OutImg;
    int i, j, p, q;

    int rows = width_image + width_kernel - 1;
    int cols = height_image + height_kernel - 1;

    //rows of size for type double*
    output = (double **) realloc(output, sizeof (double *) * rows);
    //columns of size of type double
    for (int i = 0; i < rows; i++)
        output[i] = (double *) malloc(sizeof (double) * cols);

    //for each point in the output
    for (i = 0; i < width_image + width_kernel - 1; i++) {
        for (j = 0; j < height_image + height_kernel - 1; j++) {
            output[i][j] = 0;
            //kernel(p,q)*image(i-p, j-q) 
            for (p = 0; p < width_kernel; p++) {
                //avoid unnecessary comparisons
                if (i - p < 0) {
                    break;
                } else if (i - p < width_image) {
                    for (q = 0; q < height_kernel; q++) {
                        //idem as above
                        if (j - q < 0) {
                            break;
                        } else if (j - q < width_image) {
                            output[i][j] += kernel[p][q] * image[i - p][j - q];
                        }
                    }
                }
            }
        }
    }
}

int main() {

    //allocate dummy memory of size for type double*
    double ** OutImage = (double **) malloc(sizeof (double *));

    // define image matrix
    double A[3][3] = {
        { 1, 2, 3},
        { 4, 5, 6},
        { 7, 8, 9}
    };
    // copy image matrix
    double ** A_ptr = (double **) malloc(sizeof (double *) * 3);
    for (int i = 0; i < 3; i++)
        A_ptr[i] = (double *) malloc(sizeof (double) * 3);

    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            A_ptr[i][j] = A[i][j];
            printf(" %f ", A_ptr[i][j]);
        }
    }

    printf("\n");

    //define kernel matrix
    double B[1][2] = {
        { 1, 2}
    };
    //copy kernel matrix
    double ** B_ptr = (double **) malloc(sizeof (double *));
    B_ptr[0] = (double *) malloc(sizeof (double)*2);
    for (int i = 0; i < 1; i++) {
        for (int j = 0; j < 2; j++) {
            B_ptr[i][j] = B[i][j];
            printf(" %f ", B_ptr[i][j]);
        }
    }

    printf("\n");

    //call filter
    filter_2d(A_ptr, 3, 3, B_ptr, 1, 2, &OutImage);

    //print result
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++)
            cout << OutImage[i][j] << endl;
    }

    // No idea what that is
    //system("PAUSE");
    return 0;
}

P.S。:我刚看到Valy有一个很好的解决方案。

答案 6 :(得分:0)

是的,函数可以返回指针,甚至是指针指针。我相信this thread解决了你的两个答案。

答案 7 :(得分:0)

#include <stdlib.h>

 int int_sorter( const void *first_arg, const void *second_arg )
{
int first = *(int*)first_arg;
int second = *(int*)second_arg;
if ( first < second )
{
    return -1;
}
else if ( first == second )
{
    return 0;
}
else
{
    return 1;
}
}

int main()
{
int array[10];
int i;
/* fill array */
for ( i = 0; i < 10; ++i )
{
    array[ i ] = 10 - i;
}
qsort( array, 10 , sizeof( int ), int_sorter );
for ( i = 0; i < 10; ++i )
{
    printf ( "%d\n" ,array[ i ] );
}

 }