簡體   English   中英

在 C++ 中調用指針函數

[英]Calling a pointer function in C++

我用 C++ 寫了一段代碼。 我從搜索引擎結果中提取了第一部分。

1) 使用double **filter_2d定義函數是什么意思? 我們可以使用指針定義函數嗎?

2)我對以下行感到困惑:

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

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

#include <iostream>
#include <stddef.h>
#include <cmath>
#include <fftw3.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;

    //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];
                        }
                    }
                }
            }
        }
    }
}

int main()
{
    double ** OutImage = 0;
    OutImage = (double **)malloc(sizeof(double *)*(3 * 3));

    double A[3][3] = { { 1, 2, 3 },
    { 4, 5, 6 },
    { 7, 8, 9 } };
    double *A_ptr[9];
    for (int i = 0; i < 10; i++)
    {
        A_ptr[i] = A[i];
    }
    double B[1][2] = { 1, 2 };
    double *B_ptr[2];
    for (int i = 0; i < 2; i++)
    {
        B_ptr[i] = B[i];
    }
    //Error in the below line
    filter_2d(A_ptr, 3, 3, B_ptr, 2, 1, &OutImage);  //unable to understand
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 4; j++)
            cout << *OutImage << endl;
    }
    system("PAUSE");
    return 0;
}

指針聲明
一般格式:

data_type *pointer_name;

一個指針聲明,例如,

int *numberPtr; 

將 numberPtr 聲明為指向整數變量的變量。 它的內容是一個內存地址

* 表示被聲明的變量是指針變量而不是普通變量。

考慮以下聲明:

int *numberPtr, number = 20;  

在這種情況下,保留了兩個內存地址,與名稱 numberPtr 和 number 相關聯。

變量 number 中的值是整數類型,變量 numberPtr 中的值是另一個內存位置的地址

例子

// create a 2D array dynamically
int rows, columns, i, j;
int **matrix;
cin >> rows >> columns;
matrix = new int*[rows];
for(i=0; i<rows; i++)
   matrix[i] = new int[columns];

您的函數需要double**而您正在傳遞double [3][3] 這些類型沒有隱式轉換。

您需要在main()中將數組創建為double **並將其用作函數調用中的參數。

問題 - 將二維數組轉換為指針到指針應該可以幫助您實現您想要做的事情。

您的cout似乎也不正確。 您正在考慮將filt_out視為二維數組而不是指針。

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

我分析了你的代碼,我想我發現了一些問題。

這是新代碼:

#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堆棧與堆分配的變量之間的比較

下面說說我在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 中進行了哪些數學計算。

將 C++ 指針上下文中的*作為pointer to .

國際*一個;

a 是一個指向 int 的指針。

int** b;

b是一個指向int指針的指針。

b = &a;

a是一個指向int的指針。 &a是指向int的指針的地址。 b是一個指向int指針的指針

*a = 10;

將 10 存儲在a指向的內存中。

**b = 20;

將 20 存儲在b指向的int*所指向的內存中。

#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' 進入您的程序。

您的代碼有兩個問題:

首先,我假設輸出圖像的大小與輸入圖像的大小相同,因此必須按如下方式分配:

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

其次,您定義了一個將返回 2D 指針的函數,但不幸的是,您在函數本身內部聲明了這個 2D 指針,這意味着您定義了一個局部變量指針,在大多數情況下,一旦您返回此值,它將完全錯誤,它是不是在函數本身內部分配的那個。

要解決該問題,您可以選擇以下兩種解決方案之一:

  1. 您可以定義一個全局 2D 指針,並且可以在您的函數內部分配它,因此您不需要定義您的函數來返回 2D 指針。
  2. 第二種解決方案是在調用者函數中定義將存儲結果的二維指針,調用者函數將為該指針分配所需的大小並將其傳遞給被調用者函數(即filter_2d),當它傳遞時,它將通過其地址傳遞,因此在 filter_2d 定義中,我們將添加一個額外的參數作為 3D POINTER 來存儲結果如下:

 //Define these 2 lines in the main function. double ** OutImage = null; OutImage = (double **)malloc(sizeof(double *)*(width_image * height_image));

將 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;

希望這個校准能幫到你。

我用 C++ 寫了一段代碼。 我從搜索引擎結果中提取了第一部分。

你是認真的嗎? 不知道如何理解。 它不是調試站點。 你應該先努力。

無論如何,您的代碼主要是 C。唯一讓我想起 C++ 的代碼是控制台輸出。 如果我能幫上忙,讓我試試吧……因為我喜歡。

1) 使用double **filter_2d定義函數是什么意思? 我們可以使用指針定義函數嗎?

這意味着該函數的結果是一個指向 double 類型指針的指針。 像這樣分解它:

  • **filt_outdouble類型 - 用於訪問 double 值; 在二維數組中普遍用於訪問二維,即二維數組的行和列

  • *filt_outdouble *類型double * - 用於訪問指向 double 值的指針; 在二維數組中普遍用於訪問第一維,即二維數組的行

  • filt_outdouble **類型 - 用於訪問指向 double 值的指針的指針; 二維數組中常用來訪問數組,即為二維數組分配的內存地址

您可以使用簡單的指針定義函數,但它不適用於二維數組。 閱讀以上項目。

2)我對以下行感到困惑:

double **filt_out = filter_2d(A, 3, 3, B, 2, 1); 它不能正常工作,我不明白為什么。

對我來說沒有意義。 filter_2d的返回類型是void ,因此我不明白為什么要將返回分配給指向雙精度指針的指針

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

我也沒有。 但說實話,這聽起來更像是一個調試請求,而不是一個值得投票的問題。 特別是你給我們的印象是,你首先沒有做功課學習C/C++,其次從搜索引擎復制代碼,並要求社區為你解決。


一些缺陷我相信你想仔細看看:

(我將主要使用 C 語法)

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

對我來說這看起來不對。 請核實。

我認為 OutImage 應該是一個二維數組(圖像),因此**OutImage指向二維數組的一個元素(二維,你想訪問行和列)。

此外,由於它是一個二維數組,您需要首先初始化第一維(即行),然后是第二維(即列)。

所以我會建議這樣的事情:

//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:內核第二維的大小 -應與前一維切換
  • &OutImage:過濾后圖像的指針地址(參數實際上是**OutImage的指針)? 我想你想在函數調用后保留指針,不是嗎? 對我來說聽起來不錯。

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

您將 B_ptr 定義為 B 的副本,其維度為 [1][2],但您將 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 的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;
}

PS:我剛剛看到Valy有一個很好的解決方案。

是的,函數可以返回指針,甚至是指向指針的指針。 我相信您的兩個答案都已通過此線程解決

#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 ] );
}

 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM