[英]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
即使&F
在pptest
內。
這種方法可能有什么問題?
類型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()
的情況一樣,但我設法解決了通過將array
和k
分離到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.