日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言程序设计学习笔记:P7-函数

發(fā)布時間:2023/12/8 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言程序设计学习笔记:P7-函数 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本系列文章為浙江大學翁愷C語言程序設計學習筆記,前面的系列文章鏈接如下
C語言程序設計學習筆記:P1-程序設計與C語言
C語言程序設計學習筆記:P2-計算
C語言程序設計學習筆記:P3-判斷
C語言程序設計學習筆記:P4-循環(huán)
C語言程序設計學習筆記:P5-循環(huán)控制
C語言程序設計學習筆記:P6-數(shù)據(jù)類型

文章目錄

  • 一、函數(shù)的定義和使用
    • 1.1 初見函數(shù)
    • 1.2 函數(shù)的定義和使用
    • 1.3 從函數(shù)中返回
  • 二、函數(shù)的參數(shù)和變量
    • 2.1 函數(shù)原型
    • 2.2 參數(shù)傳遞
    • 2.3 本地變量
    • 2.4 函數(shù)庶事
    • 小測驗


一、函數(shù)的定義和使用

1.1 初見函數(shù)

在第四章我們寫過一個求素數(shù)的程序,在這個程序中,判斷當前這個數(shù)是否是素數(shù)的那個循環(huán)使得我的整個代碼看著很冗余。同時,如果其他地方需要用到這個功能,又得把這些代碼寫一遍,很不方便。

scanf("%d %d", &m, &n); if (m == 1) m=2; for (i = m; i <= n; i++) {int isPrime = 1;int k;for (k = 2; k < i - 1; k++) {if (i%k == 0) {isPrime = 0;break;}}if (isPrime) {sum += i;cnt++;} } printf("%d %d\n", cnt, sum);

因此,我們可以做一些處理,將判斷當前數(shù)是否是素數(shù)的代碼提出來,將其封裝成一個函數(shù)。

int isPrime(int i) {int ret = 1;int k;for (k = 2; k < i - 1; k++) {if (i%k == 0) {ret = 0;break;}}return ret; }

最后我們的代碼就比較簡單了,在主函數(shù)中直接調用我們的函數(shù)即可。

scanf("%d %d", &m, &n); if (m == 1) m = 2; for (i = m; i <= n; i++) {if (isPrime(i)) {sum += i;cnt++;} } printf("%d %d\n", cnt, sum);

現(xiàn)在我們有個例子,分別求出1到10、20到30和35到45的三個和。按照以前我們的做法我們寫出代碼如下:

#include <stdio.h> int main() {int i;int sum;for (i = 1, sum = 0; i <= 10; i++){sum += i;}printf("%d到%d的和是%d\n", 1, 10, sum);for (i = 20, sum = 0; i <= 30; i++){sum += i;}printf("%d到%d的和是%d\n", 20, 30, sum);for (i = 35, sum = 0; i <= 45; i++){sum += i;}printf("%d到%d的和是%d\n", 35, 45, sum);return 0; }

可以看出,我們有三段幾乎一模一樣的代碼,這種叫做代碼復制。代碼復制是程序質量不良的表現(xiàn),如果以后需要維護,則需要維護許多地方。于是我們可以像前面判斷素數(shù)那樣,把這些代碼提出來,然后我們主函數(shù)只需調用寫的函數(shù)即可。

void sum(int begin, int end) {int i;int sum = 0;for (i = begin; i <= end; i++) {sum += i;}printf("%d到%d的和是%d\n",begin, end, sum); }int main() {sum(1,10);sum(20,30);sum(35,45);return 0; }

1.2 函數(shù)的定義和使用

函數(shù)是一塊代碼,接收零個或多個參數(shù),做一件事情,并返回零個或一個值。可以先想像成數(shù)學中的函數(shù): y = f(x)。

函數(shù)由函數(shù)頭和函數(shù)體組成。函數(shù)頭又包括返回類型、函數(shù)名、參數(shù)表。

當我們要調用函數(shù)時,注意事項如下:

? 調用方式:函數(shù)名(參數(shù)值); ? ()起到了表示函數(shù)調用的重要作用? 即使沒有參數(shù)也需要() ? 如果有參數(shù),則需要給出正確的數(shù)量和順序? 這些值會被按照順序依次用來初始化函數(shù)中的參數(shù) ? 函數(shù)知道每一次是哪里調用它,會返回到正確的地方

我們寫段代碼來看看上面求和函數(shù)執(zhí)行過程中的具體情況:

#include <stdio.h>void sum(int begin, int end) {int i;int sum=0;for (i = begin; i <= end; i++){sum += i;}printf("%d到%d的和是%d\n", begin, end, sum); }int main() {sum(1,10);sum(20,30);sum(30,45);return 0; }

我們單步調試,可以看出到了函數(shù)那一行會直接跳入函數(shù)的定義中,且傳遞給函數(shù)的值分別被賦值給函數(shù)的參數(shù)列表中的各參數(shù)。函數(shù)執(zhí)行完后又正確地跳轉到調用函數(shù)的那行代碼后。


1.3 從函數(shù)中返回

在我們那個判定素數(shù)的函數(shù)中,需要返回一個int類型的值。而在函數(shù)中有一個變量ret,這個ret最開始為1,然后進行一些列操作最終返回這個ret值。

int isPrime(int i) {int ret = 1;int k;for (k = 2; k < i - 1; k++) {if (i%k == 0) {isPrime = 0;break;}}}

返回關鍵字return的作用:

return停止函數(shù)的執(zhí)行,并送回一個值。因此,return有兩種使用法:
return;
return 表達式;

一個函數(shù)里可以出現(xiàn)多個return語句

我們測試return的用法。

#include <stdio.h>int max(int a, int b) {int ret;if (a > b){ret = a;}else{ret = b;}return ret; }int main() {int a,b,c;a = 5;b = 6;c = max(10,12);c = max(a,b);c = max(c, 23);printf("%d\n",max(a,b));return 0; }

我們調試運行,可以看到每次調用max的返回值都賦給c。



函數(shù)的返回值可以賦值給變量,可以再傳遞給函數(shù),甚至可以丟棄,如下圖所示。丟棄的原因在有的時候要檢查函數(shù)是否有副作用,而不關心其返回什么值。

int a,b,c; a = 5; b = 6; c = max(10,12); c = max(a,b); c = max(c, 23); c = max(max(23,45), a); c = max(23+35, b);

如果函數(shù)沒有返回值,那么前面的返回類型需要是void,具體用法如下:

void 函數(shù)名(參數(shù)表)
函數(shù)內不能使用帶值的return
可以沒有return
調用的時候不能做返回值的賦值


二、函數(shù)的參數(shù)和變量

2.1 函數(shù)原型

在前面我們定義函數(shù)一般都這樣寫,將函數(shù)定義放在main函數(shù)前面。

void sum(int begin, int end){int i;int sum = 0;for (i = begin; i <= end; i++) {sum += i;}printf("%d到%d的和是%d\n",begin, end, sum);}int main(){sum(1,10);sum(20,30);sum(35,45);return 0;}

像這樣把sum()寫在上面,是因為:

? C的編譯器自上而下順序分析你的代碼
? 在看到sum(1,10)的時候,它需要知道sum()的樣子
? 也就是sum()要幾個參數(shù),每個參數(shù)的類型如何,返回什么類型
? 這樣它才能檢查你對sum()的調用是否正確

如果將函數(shù)定義寫在main函數(shù)后面,則會報錯



如果把所有函數(shù)定義都放main函數(shù)前面不太好看,有時候我們想一開始就能看見main函數(shù)。此時我們的做法是:將函數(shù)頭復制粘貼至main函數(shù)前面并加上分號。我們復制上去的那一行函數(shù)頭叫做函數(shù)的原型聲明,12-21行的叫做函數(shù)的定義。現(xiàn)在我們再來編譯,沒問題。



關于函數(shù)的聲明,總結如下:

1、函數(shù)頭,以分號“;”結尾,就構成了函數(shù)的原型 2、函數(shù)原型的目的是告訴編譯器這個函數(shù)長什么樣? 名稱? 參數(shù)(數(shù)量及類型)? 返回類型 3、舊標準習慣把函數(shù)原型寫在調用它的函數(shù)里面 4、現(xiàn)在一般寫在調用它的函數(shù)前面 5、原型里可以不寫參數(shù)的名字,但是一般仍然寫上

2.2 參數(shù)傳遞

如果函數(shù)有參數(shù),調用函數(shù)時必須傳遞給它數(shù)量、類型正確的值。可以傳遞給函數(shù)的值是表達式的結果,這包括:

? 字面量 ? 變量 ? 函數(shù)的返回值 ? 計算的結果

示例如下:

int a,b,c; a = 5; b = 6; c = max(10,12); c = max(a,b); c = max(c, 23); c = max(max(23,45), a); c = max(23+35, b);

調用函數(shù)時給的值與參數(shù)的類型不匹配是C語言傳統(tǒng)上最大的漏洞。這是由于編譯器總是悄悄替你把類型轉換好,但是這很可能不是你所期望的。后續(xù)的語言,C++/Java在這方面很嚴格。我們測試一下類型不匹配情況,發(fā)現(xiàn)編譯器給我做了類型轉換。

但是會有warning,提示我們類型轉換可能會丟失數(shù)據(jù)。



調用函數(shù)時,傳過去的值到底是什么。之前我們說過要交換兩個變量的值,需要利用第三個變量。那現(xiàn)在我將交換的代碼封裝成一個函數(shù),是否可以完成兩個變量值的交換?代碼如下:

#include <stdio.h> void swap(int a, int b);int main() {int a = 5;int b = 6;swap(a, b);printf("a=%d b=%d\n", a,b);return 0; }void swap(int x, int y) {int t = x;x = y;y = t; }

我們調試運行,可以看出:

a和b的初始值為5和6
進入函數(shù)時,沒有a和b這兩個變量
跳出函數(shù)后,沒有x和y這兩個變量
最終a和b的值仍為5和6


因此,C語言在調用函數(shù)時,永遠只能傳值給函數(shù)。 關于函數(shù),有以下注意事項:

? 每個函數(shù)有自己的變量空間,參數(shù)也位于這個獨立的空間中,和其他函數(shù)沒有關系
? 過去,對于函數(shù)參數(shù)表中的參數(shù),叫做“形式參數(shù)”,調用函數(shù)時給的值,叫做“實際參數(shù)”
? 由于容易讓初學者誤會實際參數(shù)就是實際在函數(shù)中進行計算的參數(shù),誤會調用函數(shù)的時候把變量而不是值傳進去了,所以我們不建議繼續(xù)用這種古老的方式來稱呼它們
? 我們認為,它們是參數(shù)和值的關系


2.3 本地變量

函數(shù)的每一次運行,就會產生一個獨立的運行空間。在這個空間中的變量,是這個函數(shù)這一次運行所獨有的,我們將其稱作本地變量。定義在函數(shù)內部的變量就是本地變量,參數(shù)也是本地變量。

變量的生存期和作用域

? 生存期:什么時候這個變量開始出現(xiàn)了,到什么時候它消亡了 ? 作用域:在(代碼的)什么范圍內可以訪問這個變量(這個變量可以起作用) ? 對于本地變量,這兩個問題的答案是統(tǒng)一的:大括號內 — 塊

本地變量使用的規(guī)則:

? 本地變量是定義在塊內的? 它可以是定義在函數(shù)的塊內? 也可以定義在語句的塊內? 甚至可以隨便拉一對大括號來定義變量 ? 程序運行進入這個塊之前,其中的變量不存在,離開這個塊,其中的變量就消失了 ? 塊外面定義的變量在里面仍然有效 ? 塊里面定義了和外面同名的變量則掩蓋了外面的 ? 不能在一個塊內定義同名的變量 ? 本地變量不會被默認初始化 ? 參數(shù)在進入函數(shù)的時候被初始化了

我們來測試一下,在if語句的大括號內定義一個變量,并在外面使用它。

int a = 5; int b = 6; if (a < b) {int i = 11; } i++;

此時會報錯,說i未聲明。i是在if那個大括號內定義的,出了那個大括號就不在了。

我們再來測試下直接寫個大括號,然后在里面定義變量i,并在大括號外面使用。

int a = 5;int b = 6;{int i = 11;}i++;

可以看出,仍然報相同的錯誤。



我們測試一下在塊外和塊內都定義一個變量a,看塊內是否會覆蓋塊外。

int i = 1;{int i = 2;printf("%d\n", i);}

可以看出,成功覆蓋。


2.4 函數(shù)庶事

當函數(shù)沒有參數(shù)時,是寫成void f(void)還是void f()呢?當你在參數(shù)表內放個void明確代表這個函數(shù)不接受任何參數(shù)。當你在參數(shù)表里不放東西,在傳統(tǒng)C中,它表示f函數(shù)的參數(shù)表未知,并不表示沒有參數(shù)。那么在C99里面會怎樣呢?我們來看看。

現(xiàn)在我把swap函數(shù)生命中的參數(shù)表刪除,然后運行。

#include <stdio.h> void swap();int main() {int a = 5;int b = 6;swap(a, b);printf("a=%d b=%d\n", a,b);return 0; }void swap(int x, int y) {int t = x;x = y;y = t; }

可以看出,編譯通過。編譯通過原因在于,我們寫出void swap()是在告訴編譯器我只知道有個swap函數(shù),但是我不確定這個swap到底要什么參數(shù)。于是編譯器遇到swap(a,b)時,它猜測我的swap函數(shù)需要兩個int。



如果我把swap函數(shù)定義的參數(shù)列表改為兩個double,看看會發(fā)生什么。

#include <stdio.h> void swap();int main() {int a = 5;int b = 6;swap(a, b);printf("a=%d b=%d\n", a,b);return 0; }void swap(double x, double y) {int t = x;printf("in swap, a=%f b=%f\n", x, y);x = y;y = t; }

我們運行,可以看出我們給swap函數(shù)5和6,但是它拿到的是0.00000和一個非常大的數(shù)。

我們分析原因如下:

? 這是因為我們用void swap()這個函數(shù)聲明(原型)去欺騙了編譯器告訴編譯器我也不知道swap函數(shù)要什么參數(shù)。
? 然后編譯器看到swap(a,b)時認為swap函數(shù)要兩個int,于是它為swap調用安排了兩個int傳遞。
? 當編譯器看到void swap(double x, double y)時,由于前面的函數(shù)聲明(原型)不僅僅檢查函數(shù)的調用是否正確,也要檢查對函數(shù)的定義是否正確。現(xiàn)在原型看到這一行時,也不確定是什么類型(兩個double也是可能的一種不確定)。
? 所以編譯器從中沒有發(fā)現(xiàn)任何問題,因此兩個int傳到double這里來就錯了。

因此,不要用void swap()這種。如果確定函數(shù)里面沒參數(shù),就用void swap(void)。


還有一個小問題。調用函數(shù)時參數(shù)表里面也有逗號,我們也說過逗號是運算符。調用函數(shù)時的逗號和逗號運算符怎么區(qū)分?

調用函數(shù)時的圓括號里的逗號是標點符號,不是運算符 對于f(a,b)和f((a,b)) 第一個傳了兩個參數(shù),第二個傳遞了一個參數(shù)。

C語言不允許函數(shù)嵌套定義:C語言不允許在函數(shù)內部定義函數(shù),但是可以放函數(shù)的聲明。


我們來看兩個例子都分別是什么:

? int i,j,sum(int a, int b); 聲明了兩個int變量和一個返回int類型值得sum函數(shù)。(不建議這種寫法) ? return (i); 和return i一樣,這個括號無意義。(不建議這種寫法,讓人誤解return是個函數(shù))

關于main函數(shù)的返回值

main函數(shù)中的return 0是有意義的。main函數(shù)是我們寫的代碼最先被執(zhí)行的地方,但是它并不是程序運行起來第一條運行的代碼。在main函數(shù)之前還有其他東西,那些東西是為了程序運行去做準備的,他們昨晚準備工作后會來調用你的main函數(shù)。因此,這個return 0是有意義的,要把這個0返回給調用它的地方,那個地方回來檢查這個返回值然后報告給操作系統(tǒng)。在Windows中,一個程序返回0是正確的。返回任何非0的值是有錯的。


小測驗

1、以下哪句不是正確的原型? A. int f(); B. int f(int i); C. int f(int); D. int f(int i) {} 答案:D2、以下哪個函數(shù)的定義是錯誤的? A. void f() {} B. void f(int i) { return i+1; } C. void f(int i) {} D. int f() { return 0; } 答案:B3、對于不返回值而且只有一個int類型的參數(shù)的函數(shù),以下哪些函數(shù)原型是正確的? A. void f(int x); B. void f(); C. void f(int); D. void f(x); 答案:A、B、C

4、以下程序的輸出是什么?

#include <stdio.h>void swap(int a, int b);int main() {int a = 5;int b = 6;swap(a,b);printf("%d-%d\n", a, b);return 0; }void swap(int a, int b) {int t = a;a = b;b = t; }

答案: 5-6

總結

以上是生活随笔為你收集整理的C语言程序设计学习笔记:P7-函数的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。