簡體   English   中英

聲明,分配和賦值函數指針的數組

[英]Declaration, allocation and assignment of an array of pointers to function pointers

這是我的第一篇文章,所以請保持溫和。

我過去一直在玩C語言。 現在我已經開始了我開始一個真正的項目(使用SDL的2D圖形引擎,但這與問題無關),能夠說我有一些真正的C體驗。 昨天,在處理事件系統時,我遇到了一個我無法解決的問題。

有這種typedef,


//the void parameter is really an SDL_Event*.  
//but that  is irrelevant for this question.  
typedef void (*event_callback)(void);  

它指定要在引擎事件上調用的函數的簽名。

我希望能夠支持多個event_callbacks,所以這些回調的數組是一個想法,但不想限制回調量,所以我需要某種動態分配。 這就是問題出現的地方。 我的第一次嘗試是這樣的:


//initial size of callback vector  
static const int initial_vecsize = 32;  
//our event callback vector  
static event_callback* vec = 0;  
//size  
static unsigned int vecsize = 0;  

void register_event_callback(event_callback func) {  
    if (!vec)  
        __engine_allocate_vec(vec);  
    vec[vecsize++] = func; //error here!  
}  

static void __engine_allocate_vec(engine_callback* vec) {  
    vec = (engine_callback*) malloc(sizeof(engine_callback*) * initial_vecsize);  
}  

首先,我省略了一些錯誤檢查以及當回調數超過矢量大小時重新分配回調向量的代碼。

但是,當我運行此代碼時,程序崩潰,如代碼中所述。 我猜測分段錯誤但我不能確定,因為沒有給出輸出。 我也猜測錯誤來自對如何聲明和分配指向函數指針的指針數組的一些有缺陷的理解。

請Stack Overflow,指導我。

編輯:我似乎無法掌握如何縮進代碼塊。 這幾乎有點令人尷尬......

編輯:沒關系。 檢查了其他一些帖子的頁面來源=)。

分配功能應該是:

static void __engine_allocate_vec(engine_callback** vec) {  
    *vec =  malloc(sizeof(engine_callback) * initial_vecsize);  
}  

接着:

if (!vec)  
    __engine_allocate_vec(&vec);  

請注意,如果省略了強制轉換,則原始分配函數中的指針類型不匹配將被捕獲。 另外,不要在代碼中使用包含雙下划線的名稱 - 它們僅供實現使用。

在線:

vec[vecsize++] = func; //error here!  

如果vecsize>= initial_vecsize會發生什么?

__engine_allocate_ve也不起作用,因為它只修改了vec的本地副本,你必須將簽名更改為**並使用&傳遞參數。

static void __engine_allocate_vec(engine_callback** vec)

__engine_allocate_vec(&vec);

您似乎是基於sizeof(engine_callback*)而不是sizeof(engine_callback)進行malloc -ing ...

你的__engine_allocate_vec函數正在為新的engine_callback創建空間,但它沒有對該指針做任何有用的事情。 (它正在改變它的本地版本的vec,它是通過值傳遞的 - 因此更改不會將其返回給調用者。並且參數的名稱隱藏了全局的名稱,因此也沒有設置。)所以當它返回時,你的指針仍為空。

嘗試這樣的事......

static void __engine_allocate_vec(engine_callback** vec) {
    *vec = (engine_callback*) malloc(sizeof(engine_callback) * initial_vecsize);
}

然后在register_event_callback中,將&vec傳遞給函數而不是vec

或者,使函數為void,並讓它設置全局本身。 不,我忘記了。

首先, 不要使用前導下划線表示變量或函數名稱; 這些名稱是為實施保留的。

其他人都指出了最初分配向量的正確方法:

static void engine_allocate_vec(event_callback **vec)
{
  *vec = malloc(sizeof **vec * initial_vecsize);
}

注意幾件事。 首先,我不會拋出malloc的結果。 沒有必要(從C89開始,無論如何;早期版本的C需要強制轉換,C ++也是如此),如果您忘記包含stdlib.h或者沒有原型,它可能會抑制編譯器診斷malloc在范圍內。 第二,我在表達**vec上調用sizeof,而不是類型; 由於表達式**vec的類型是event_callback ,因此sizeof **vec返回與sizeof (event_callback)相同的結果。 這有助於減少視覺混亂,它避免了當某人更改變量類型時會出現的一些常見錯誤,但不會將該更改傳遞給malloc調用中的sizeof表達式,例如

double *f; /* was originally declared as float, later changed to double */
...
f = malloc(sizeof (float) * size); /* type change not carried through */

請注意, sizeof不會計算其操作數(除非它是VLA),因此您不必擔心在未初始化的指針表達式上調用它。

這有助於您創建初始向量。 但是,您希望在注冊多於initial_vecsize回調時能夠根據需要擴展向量,對吧? 如果是這樣,請允許我建議如下:

static int engine_allocate_vec(event_callback **vec, 
  size_t *currentSize, 
  size_t extent)
{
  int success = 0;
  /**
   * Assign the result of realloc to a temporary; realloc returns NULL
   * on failure, and we don't want to risk losing our pointer to the
   * previously allocated memory.  Similarly, we don't update *currentSize
   * unless the call succeeds.  Note that realloc(NULL, size) is equivalent
   * to malloc(size).
   */
  event_callback *tmp = realloc(*vec, sizeof *tmp * (*currentSize + extent));
  if (tmp != NULL)
  {
    *vec = tmp;
    *currentSize += extent;
    success = 1;
  }
  return success;
}

然后您的注冊功能變為:

/**
 * Adding vector_count variable to keep track of the number
 * of items in the vector as opposed to the physical size
 * of the vector.
 */
static size_t vector_count = 0;

void register_callback_event(event_callback func)
{
  if (!vec)
  {
    /**
     * Initial vector allocation
     */
    if (!engine_allocate_vec(&vec, &vecsize, initial_vecsize))
    {
      /* allocation failed; treating this as a fatal error */
      exit(0);
    }
  }
  else if (vector_count == vecsize)
  {
    /**
     * Need to extend the vector to accomodate 
     * the new callback.  Double the vector size (i.e.,
     * extend it by the current vector size)
     */
    if (!engine_allocate_vec(&vec, &vecsize, vecsize))
    {
      /* extension failed - treating this as a fatal error*/
      free(vec);
      exit(0);
    }
  }

  vec[vector_count++] = func;
}

暫無
暫無

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

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