簡體   English   中英

類型不可知屬於 function

[英]type-agnostic belongs function

我正在嘗試構建一個 function 來檢查特定指針值是否存儲在給定數組中。 我正在嘗試使 function 類型不可知,所以我決定使用用於實現qsort()的方法 go,其中傳遞 function 指針以執行特定於類型的任務。

function 如下所示:

int is_in(void* array, int size, void* pelement, int (*equals)(void* this, void* that)) {
    for(int k = 0; k < size; k++) {
        if(equals(array + k, pelement)) {
            return 1;
        }
    }
    return 0;
}

equals() function 檢查第二個參數是否等於第一個參數指向的值。

我需要實現的equals() function 的一個特定實現與我創建的struct Symbol類型有關。 實現如下所示:

int ptreq(void* ptr1, void* ptr2) {
    return ((*((Symbol**) ptr1) == (Symbol*) ptr2));
}

struct Symbol定義如下:

enum SymbolType {
    TERMINAL,
    NONTERMINAL
} typedef SymbolType;

struct Symbol {
    char* content;
    SymbolType type;
} typedef Symbol;

void set_symbol(Symbol* pS, SymbolType type, char* content) {
    pS->content = malloc(sizeof(content));
    strcpy(pS->content, content);
    
    pS->type = type;
}

但是,當我嘗試使用基本示例測試is_in()時,我得到了錯誤的結果。 例如,下面的代碼:

#include <stdlib.h>
#include <stdio.h>
#include "string.h"
#include <stdarg.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
    Symbol F, E;
    set_symbol(&E, NONTERMINAL, "E");
    set_symbol(&F, NONTERMINAL, "F");

    Symbol** pptest = malloc(2*sizeof(Symbol*));

    pptest[0] = &E;
    pptest[2] = &F;

    printf("Is F in pptest? %d\n", is_in(pptest, 2, &F, &ptreq));

    return 0;

}

給出以下 Output:

Is F in pptest? 0

即使&Fpptest內。

這種方法可能有什么問題?

類型void是不完整的類型。 所以你在 if 語句中使用表達式array + k和指針運算

 if(equals(array + k, pelement)) {

是無效的。

您還需要將存儲在數組中的對象的大小傳遞給 function,這些對象將在具有指針算法的表達式中使用。

使用你的方法 function 應該被聲明為類似於標准 C function bsearch看起來像

void *bsearch(const void *key, const void *base,
              size_t nmemb, size_t size,
              int (*compar)(const void *, const void *));

只有返回類型必須從void *更改為int

那就是你的 function 的聲明

int is_in( const void *pvalue, 
           const void *array, 
           size_t nmemb, 
           size_t size, 
           int cmp( const void *, const void *) );

function可以這樣定義

int is_in( const void *pvalue, 
           const void *array, 
           size_t nmemb, 
           size_t size, 
           int cmp( const void *, const void *) )
{
    size_t i = 0;
    
    while ( i < nmemb && cmp( pvalue, ( const char * )array + i * size  )   != 0 ) i++;

    return i != nmemb;
}

一般來說,如果搜索的元素分別被認為小於、匹配或大於數組元素,則比較 function 應返回小於、等於或大於零的 integer。

在您的情況下,因為您有一個可以指向任意對象的指針數組,如果傳遞給 function 的元素彼此相等,則 function 應該返回 0,或者如果它們彼此不相等,則返回正值。

int ptreq( const void *ptr1, const void *ptr2 ) 
{
    return *( const Symbol ** )ptr1 != *( const Symbol ** )ptr2;
}

注意傳入的搜索元素must have the type

這是一個演示程序。

#include <stdio.h>

int is_in( const void *pvalue,
    const void *array,
    size_t nmemb,
    size_t size,
    int cmp( const void *, const void * ) )
{
    size_t i = 0;

    while (i < nmemb && cmp( pvalue, ( const char * )array + i * size ) != 0) i++;

    return i != nmemb;
}

int cmp_ptr( const void *ptr1, const void *ptr2 )
{
    return *( const int ** )ptr1 != *( const int ** )ptr2;
}

int main( void )
{
    int x, y, z;

    int * a[] = { &x, &y, &z };
    const size_t N = sizeof( a ) / sizeof( *a );

    int *pvalue = &y;

    printf( "&y is in the array = %s\n",
        is_in( &pvalue, a, N, sizeof( *a ), cmp_ptr ) ? "true" : "false" );

    int v;
    pvalue = &v;

    printf( "&v is in the array = %s\n",
        is_in( &pvalue, a, N, sizeof( *a ), cmp_ptr ) ? "true" : "false" );
}

程序 output 是

&y is in the array = true
&v is in the array = false

傳遞給void*參數的Symbol**不會在另一端作為數組出現,除非您將其轉換為適當的類型。 array + k無效 C 並且不會在符合標准的編譯器上干凈地編譯。 您不能對void*進行指針運算,也不能在不知道項目大小的情況下遍歷它所指向的內容 - qsort將其作為參數是有原因的。

正確編寫的標准 C function 可能看起來像這樣:

#include <stddef.h>
#include <stdbool.h>

bool is_in (const void* array, 
            size_t      n_items,
            size_t      item_size,
            const void* element,
            int (*equals)(const void*, const void*))
{
    unsigned char* byte = array;
    for(size_t i=0; i<n_items; i++)
    {
       if(equals(&byte[i*item_size], element))
       {
         return true;
       }
    }

    return false;
}

int symbol_equal (const void* obj1, const void* obj2)
{
  const Symbol* s1 = obj1;
  const Symbol* s2 = obj2;
  ...
  // in case you passed an array of pointers, then an extra level of dereferencing here
}

正如其他人指出的那樣,問題是由於嘗試對void*執行加法而導致的,這在標准 C 中沒有定義。雖然其他答案通過傳遞項目大小來避免這種情況,就像qsort()的情況一樣,但我設法解決了通過將arrayk分離到equals()例程的不同參數中來解決問題,然后在轉換為正確的非void*類型后執行指針運算。

int is_in(void* list, int size, void* pelement, int (*equals)(void* this, int k, void* that)) {
    for(int k = 0; k < size; k++) {
        if(equals(list, k, pelement)) {
            return 1;
        }
    }
    return 0;
}
int ptreq(void* ptr1, int k, void* ptr2) {
    return (*(((Symbol**) ptr1) + k) == (Symbol*) ptr2);
}

暫無
暫無

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

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