C語言——函數

@toc數組

1.函數是什麼?

數學中咱們常見到函數的概念。可是你瞭解C語言中的函數嗎? 維基百科中對函數的定義:子程序 markdown

  • 在段落引用計算機科學中,子程序(英語:Subroutine, procedure, function, routine, method,subprogram, callable unit),是一個大型程序中的某部分代碼, 由一個或多個語句塊組
    成。它負責完成某項特定任務,並且相較於其餘代 碼,具有相對的獨立性。
  • 通常會有輸入參數並有返回值,提供對過程的封裝和細節的隱藏。這些代碼一般被集成爲軟 件庫。

 

2.C語言中函數的分類:

1.庫函數
2.自定義函數
  ide

(1)庫函數

那怎麼學習庫函數呢?
C語言庫查詢:www.cplusplus.com
以下:
圖片.png
簡單的總結,C語言經常使用的庫函數都有:函數

  • IO函數
  • 字符串操做函數
  • 字符操做函數
  • 內存操做函數
  • 時間/日期函數
  • 數學函數
  • 其餘庫函數
    庫函數實例
    圖片.png
    1.代碼以下(strcpy示例):
    將字符串拷貝到另外一地址
    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <string.h>
    int main()
    {
    char arr1[] = "hello";
    char arr2[] = "###########";
    strcpy(arr2, arr1);
    //strcpy->string copy 字符串拷貝,拷貝字符串(含‘\0’)
    //strcpy(拷貝目的地,字符串拷貝地址)
    printf("%s\n", arr1);

    圖片.png
     
    2.代碼以下(memset示例):
    字符串替換工具

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <string.h>
    int main()
    {
    char arr1[] = "hello world";
    memset(arr1, '*', 5);
    //memset(目的地,改變值(整形),改變個數)
    printf("%s\n", arr1);
    return 0;
    }

    圖片.png

 
: 可是庫函數必須知道的一個祕密就是:使用庫函數,必須包含 #include對應的頭文件。 這裏對照文檔來學習上面幾個庫函數,目的是掌握庫函數的使用方法。
如何學會使用庫函數?
 
學會查詢工具的使用:學習

MSDN(Microsoft Developer Network)
www.cplusplus.com
zh.cppreference.com指針

(2)自定義函數

函數的組成:
圖片.png
 
定義函數
函數體:即定義的函數中{}中的部分,交代的是函數的實現
咱們舉一個栗子:code

寫一個函數能夠找出兩個整數中的最大值。blog

#define _CRT_SECURE_NO_WARNINGS
#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
//求兩數中的較大值
//定義函數
int get_max(int x, int y)
{
if (x &gt; y)
return x;
else
return y;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d%d", &a, &b);
//函數的使用
int max = get_max(a, b);
printf("max = %d\n", max);
max = get_max(100, 300);
printf("max = %d\n", max);
return 0;
}

圖片.png

//使用函數編寫代碼實現兩數交換
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
//直接傳遞值進行交換,無效
//對形參的修改不會改變實參
//形參是實參的一份臨時拷貝
void Swap1(int x,int y)//形參
//void表示空,無,此函數沒有返回值,全部用void
{
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
    printf("x = %d  y = %d\n", x, y);//x,y交換成功,但x,y的值與a,b交換沒有關係
}
//經過指針,取地址交換a,b的值有效
void Swap2(int* pa, int* pb)//形參
{
    int tmp = 0;
    tmp = *pa;
    *pa = *pb;
    *pb = tmp;
    printf("*pa = %d  *pb = %d\n", *pa, *pb);
}
int main()
{
    int a = 0;
    int b = 0;
    scanf("%d%d", &a, &b);
    printf("a = %d  b = %d\n", a, b);
    int tmp = 0;
    //tmp = a;
    //a = b;
    //b = tmp;//將這三條交換程序寫成函數
    //調用Swap1函數——傳值調用
    Swap1(a, b);//實參
    printf("a = %d  b = %d\n", a, b);//無效交換
    //調用Swap2函數——傳址調用
    Swap2(&a, &b);//實參
    printf("a = %d  b = %d\n", a, b);//交換有效
    return 0;
}

圖片.png
 

3.函數的參數

(1)實際參數(實參):真實傳給函數的參數,叫實參。實參能夠是:常量、變量、表達式、函數等。不管實參是何種類型的量,在進行函數調用時,它們都必須有肯定的值,以便把這些值傳送給形參。
(2)形式參數(形參):形式參數是指函數名後括號中的變量,由於形式參數只有在函數被調用的過程當中才實例化(分配內存單元),因此叫形式參數。形式參數當函數調用完成以後就自動銷燬了。所以形式參數只在函數中有效。three

上面Swap1和Swap2函數中的參數 x,y,pa,pb 都是形式參數;在main函數中傳給Swap1的a,b和傳給Swap2的a,b是實際參數。<br/>形參實例化以後其實至關於實參的一份臨時拷貝。
 

4.函數的調用

(1)傳值調用:
函數的形參和實參分別佔有不一樣內存塊,對形參的修改不會影響實參。
(2)傳址調用:
傳址調用是把函數外部建立變量的內存地址傳遞給函數參數的一種調用函數的方式。
這種傳參方式可讓函數和函數外邊的變量創建起正真的聯繫,也就是函數內部能夠直接操做函數外部的變量。

 

5.函數實例

1)寫一個函數能夠判斷一個數是否是素數

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//求100-200間的素數
//素數返回1,不是素數返回0
int is_prime(int n)
{
    int m = 0;
    //用小於n的值試除n,能整除即不是素數
    for (m = 2; m<n; m++)//任何一個數的值必不大於其開根號的平方和,9<=3^2+3^2
    {
        if (n%m == 0)
            return 0;
        //在此處不能寫else,return 1
        //由於只作了一次判斷
    }
    if (m == n)//只有當for循環m<n不成立時跳到這,即m == n,此判斷可不寫
        return 1;
}
int main()
{
    int i = 0;
    for (i = 100; i <= 200; i++)
    {
        if (is_prime(i) == 1)
            printf("%d ", i);
    }
    return 0;
}

2)寫一個函數,實現一個整形有序數組的二分查找

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//數組元素查找
// 能找到返回數組下標,不能找到返回-1
 //arr其實是一個地址
int binary_search(int arr[], int k, int sz)
{
    int left = 0;
    //數組傳參僅傳數組首元素地址,在函數內部不能獲得數組個數
    //int sz = sizeof(arr) / sizeof(arr[0]);
    int right = sz - 1;
    while (left <= right)
    {
        int mid = (left + right) / 2;
        if (arr[mid] > k)
            right = mid -1;
        else if (arr[mid] < k)
            left = mid +1;
        else
            return mid;
    }
    return -1;
}
int main()
{
    int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
    int k = 7;
    int ret = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);
    ret = binary_search(arr, k, sz);
    if (ret == -1)
    {
        printf("找不到指定的數字\n");
    }
    else
    {
        printf("找到了,下標是%d\n",ret );
    }
    return 0;
}

 

6.函數的嵌套調用和鏈式訪問

嵌套調用:

#include <stdio.h>
void new_line()
{
 printf("hehe\n");
}
void three_line()
{
    int i = 0;
 for(i=0; i<3; i++)
   {
        new_line();
   }
}
int main()
{
 three_line();
 return 0; 
 }

鏈式訪問:把一個函數的返回值做爲另一個函數的參數。
實例:

#include <stdio.h>
int main()
{
    printf("%d", printf("%d", printf("%d", 43)));
    return 0; 
}

圖片.png
這是由於printf的返回值是打印字符的個數,即printf("%d", printf("%d", printf("%d", 43)))—>printf("%d", printf("%d", 2))—>printf("%d", 1),即打印4321.

 

7.函數的聲明和定義

函數聲明:
1.告訴編譯器有一個函數叫什麼,參數是什麼,返回類型是什麼。可是具體是否是存在,無關
緊要。
2.函數的聲明通常出如今函數的使用以前。要知足先聲明後使用。

  1. 函數的聲明通常要放在頭文件中的。
     
    函數定義:

    函數的定義是指函數的具體實現,交待函數的功能實現。

圖片.png

通常來講,咱們最好將函數的定義部分放到函數調用前面,這樣就能夠避免函數聲明的部分(編譯器讀取代碼是從上往下依次掃描的),例如上面的這個代碼能夠寫成這樣:

圖片.png
 
函數分寫
test.h的內容 放置函數的聲明

#ifndef __TEST_H__
#define __TEST_H__
//函數的聲明
int Add(int x, int y); 
#endif //__TEST_H__

test.c的內容 放置函數的實現

#include "test.h"
//函數Add的實現
int Add(int x, int y) 
{
return x+y;
}

咱們看到過不少t頭文件都會加上相似上面的代碼,爲何要加上這些代碼呢?

防止同一個頭文件被屢次使用頭文件在使用的時候,其實是將整個頭文件的內容複製到這條語句處,若是同一個頭文件屢次使用,就會產生大量重複且無效的代碼,下降代碼的效率和增長代碼所在內存。

相關文章
相關標籤/搜索