C函數介紹

函數是將代碼結構化為子程序的方法,我們可以:

  1. 為其命名
  2. 在需要的時候調用它們

從你的第一個程序開始,一個“Hello, World!”,你就立即使用了C函數:

#include <stdio.h>

int main(void) {
 printf("Hello, World!");
}

main()函數是非常重要的函數,因為它是C程序的入口點。

下面是另一個函數:

void doSomething(int value) {
 printf("%u", value);
}

函數有4個重要方面:

  1. 它們有一個名字,所以我們可以在以後調用它們
  2. 它們指定了一個返回值
  3. 它們可以有參數
  4. 它們有一個用大括號包裹的函數體

函數體是在調用函數時執行的一組指令。

如果函數沒有返回值,你可以在函數名前使用關鍵字void。否則,你需要指定函數的返回值類型(int表示整數,float表示浮點數,const char *表示字符串等)。

你不能從一個函數中返回多個值。

函數可以有參數,它們是可選的。如果沒有參數,我們在括號內插入void,像這樣:

void doSomething(void) {
 /* ... */
}

在這種情況下,當我們調用該函數時,括號內不帶任何內容:

doSomething();

如果我們有一個參數,我們需要指定參數的類型和名稱,像這樣:

void doSomething(int value) {
 /* ... */
}

當我們調用該函數時,我們將在括號內傳遞該參數,像這樣:

doSomething(3);

我們可以有多個參數,如果有多個參數,我們在聲明和調用時使用逗號分隔:

void doSomething(int value1, int value2) {
 /* ... */
}

doSomething(3, 4);

參數是按值傳遞的。這意味著如果你修改了value1的值,它的值只會在本地中被修改,並且在函數外部,它被傳入調用中的值不會改變。

如果你將一個指針作為參數傳遞,你可以修改該變量的值,因為你現在可以直接使用其內存地址訪問它。

你不能為參數定義默認值。C++可以這樣做(因此Arduino語言程序可以這樣做),但C不能。

確保在調用函數之前先定義它,否則編譯器將引發警告和錯誤:

 ~ gcc hello.c -o hello; ./hello
hello.c:13:3: warning: implicit declaration of
 function 'doSomething' is invalid in C99
 [-Wimplicit-function-declaration]
 doSomething(3, 4);
 ^
hello.c:17:6: error: conflicting types for
 'doSomething'
void doSomething(int value1, char value2) {
 ^
hello.c:13:3: note: previous implicit declaration
 is here
 doSomething(3, 4);
 ^
1 warning and 1 error generated.

你得到的警告是關於排序,這一點我已經提到過。

錯誤是與另一個相關的東西。由於C在調用之前不“看到”函數聲明,它必須做出假設。它假定函數返回int。然而,該函數返回void,因此出現了錯誤。

如果你將函數定義更改為:

int doSomething(int value1, int value2) {
 printf("%d %d\n", value1, value2);
 return 1;
}

你只會得到警告,而不是錯誤:

 ~ gcc hello.c -o hello; ./hello
hello.c:14:3: warning: implicit declaration of
 function 'doSomething' is invalid in C99
 [-Wimplicit-function-declaration]
 doSomething(3, 4);
 ^
1 warning generated.

無論如何,確保在使用函數之前聲明它。要么把函數往上移,要么在頭文件中添加函數原型。

在函數內部,你可以聲明變量。

void doSomething(int value) {
 int doubleValue = value * 2;
}

變量在函數調用時被創建,並在函數結束時被銷毀,它對外部不可見。

在函數內部,你可以調用函數自身。這稱為遞迴,它提供了特殊的機會。