2. 傳入參數與傳出參數

如果函數介面有指針參數,既可以把指針所指向的數據傳給函數使用(稱為傳入參數),也可以由函數填充指針所指的內存空間,傳回給調用者使用(稱為傳出參數),例如strcpysrc參數是傳入參數,dest參數是傳出參數。有些函數的指針參數同時擔當了這兩種角色,如select(2)fd_set *參數,既是傳入參數又是傳出參數,這稱為Value-result參數。

表 24.1. 傳入參數示例:void func(const unit_t *p);

調用者實現者
  1. 分配p所指的內存空間

  2. p所指的內存空間中保存數據

  3. 調用函數

  4. 由於有const限定符,調用者可以確信p所指的內存空間不會被改變

  1. 規定指針參數的類型unit_t *

  2. 讀取p所指的內存空間


想一想,如果有函數介面void func(const int p);這裡的const有意義嗎?

表 24.2. 傳出參數示例:void func(unit_t *p);

調用者實現者
  1. 分配p所指的內存空間

  2. 調用函數

  3. 讀取p所指的內存空間

  1. 規定指針參數的類型unit_t *

  2. p所指的內存空間中保存數據


表 24.3. Value-result參數示例:void func(unit_t *p);

調用者實現者
  1. 分配p所指的內存空間

  2. p所指的內存空間保存數據

  3. 調用函數

  4. 讀取p所指的內存空間

  1. 規定指針參數的類型unit_t *

  2. 讀取p所指的內存空間

  3. 改寫p所指的內存空間


由於傳出參數和Value-result參數的函數介面完全相同,應該在文檔中說明是哪種參數。

以下是一個傳出參數的完整例子:

例 24.2. 傳出參數

/* populator.h */
#ifndef POPULATOR_H
#define POPULATOR_H

typedef struct {
     int number;
     char msg[20];
} unit_t;

extern void set_unit(unit_t *);

#endif
/* populator.c */
#include <string.h>
#include "populator.h"

void set_unit(unit_t *p)
{
     if (p == NULL)
          return; /* ignore NULL parameter */
     p->number = 3;
     strcpy(p->msg, "Hello World!");
}
/* main.c */
#include <stdio.h>
#include "populator.h"

int main(void)
{
     unit_t u;

     set_unit(&u);
     printf("number: %d\nmsg: %s\n", u.number, u.msg);
     return 0;
}

很多系統函數對於指針參數是NULL的情況有特殊規定:如果傳入參數是NULL表示取預設值,例如pthread_create(3)pthread_attr_t *參數,也可能表示不做特別處理,例如free的參數;如果傳出參數是NULL表示調用者不需要傳出值,例如time(2)的參數。這些特殊規定應該在文檔中寫清楚。