詳解C語言中的函數(shù)、數(shù)組與指針
1、函數(shù):當(dāng)程序很小的時候,我們可以使用一個main函數(shù)就能搞定,但當(dāng)程序變大的時候,就超出了人的大腦承受范圍,邏輯不清了,這時候就需要把一個大程序分成許多小的模塊來組織,于是就出現(xiàn)了函數(shù)概念;
函數(shù)是C語言代碼的基本組成部分,它是一個小的模塊,整個程序由很多個功能獨(dú)立的模塊(函數(shù))組成。這就是程序設(shè)計的基本分化方法;
(1) 寫一個函數(shù)的關(guān)鍵:
函數(shù)定義:函數(shù)的定義是這個函數(shù)的實現(xiàn),函數(shù)定義中包含了函數(shù)體,函數(shù)體中的代碼段決定了這個函數(shù)的功能;
函數(shù)聲明:函數(shù)聲明也稱函數(shù)原型聲明,函數(shù)的原型包含三部分:函數(shù)名,返回值類型,函數(shù)參數(shù)列表,函數(shù)的聲明是告訴使用函數(shù)的人,這個函數(shù)使用時應(yīng)該傳遞給他什么樣的參數(shù),
它會返回什么樣類型的返回值。這些東西都是寫函數(shù)的人在函數(shù)定義中規(guī)定好的,如果使用函數(shù)的人不參照這個原型來使用,就會出錯,結(jié)果就會和你想的不一樣;
函數(shù)調(diào)用:函數(shù)調(diào)用就是使用函數(shù)名來調(diào)用函數(shù)完成功能。調(diào)用時必須參照原型給函數(shù)傳參,然后從函數(shù)得到適當(dāng)?shù)姆祷刂底鳛榻Y(jié)果;
(2) 函數(shù)的參數(shù):函數(shù)調(diào)用的過程,其實就是實參傳遞給形參的一個過程。這個傳遞像是一次拷貝,實參(本質(zhì)是一個變量)本身并沒有進(jìn)入到函數(shù)內(nèi),而是把自己的值復(fù)制了一份傳給了函數(shù)中的形參,
在函數(shù)中參與運(yùn)算,這種傳參方法,就叫做傳值調(diào)用;
形參:形式參數(shù),在函數(shù)定義和函數(shù)聲明中的參數(shù)列表中的參數(shù)都是形參;
實參:實際參數(shù),函數(shù)調(diào)用中,實際傳遞的參數(shù)才是實參。
(3) 返回值(關(guān)鍵字return):當(dāng)函數(shù)執(zhí)行完之后,會給調(diào)用該函數(shù)的地方返回一個值。這個值的類型就是函數(shù)聲明中返回值類型,這個值就是函數(shù)體中最后一句return xxx;返回的那個值;
(4) 函數(shù)名:取函數(shù)名要注意以下幾點(diǎn):
第一,起名字時候不能隨意,要符合規(guī)則,而這個規(guī)則分別有兩個層次,即第一層是合法,第二層是合理。合法就是符號C語言中變量名的命名規(guī)則,合理就是變量名起的好,
人一看就知道什么意思,一看就知道這個函數(shù)是干嘛的;
第二,C語言中,所有的符號都是區(qū)分大小寫的;
第三,C語言函數(shù)名的命名習(xí)慣。這個沒有固定的結(jié)論,有多種使用都很廣泛的命名方式如下:
linux的命名習(xí)慣:student_age str_to_int
駱駝命名法:studentAge strToInt
注:想進(jìn)一步了解可以參考林銳的《高質(zhì)量程序設(shè)計指南》;
// 簡單計算器 #include <stdio.h> int add(int a, int b); int sub(int a, int b); int mul(int a, int b); int div(int a, int b); int main(void) { int a, b, c; a = 54; b = 32; c = add(a, b); //c = sub(a, b); //c = mul(a, b); //c = div(a, b); printf("c = %d.\n", c); printf("a - b = %d.\n", sub(a, b)); return 0; } int add(int a, int b) { return a + b; } int sub(int a, int b) { return a - b; } int mul(int a, int b) { return a * b; } int div(int a, int b) { return a / b; }
2、數(shù)組:數(shù)組就是若干個數(shù)組成的一個組,數(shù)就是一個特定數(shù)據(jù)類型的變量,組就是說好多數(shù)放在了一起;
(1) 數(shù)組的定義:
int a[10]; 數(shù)組中元素類型 數(shù)組名[數(shù)組元素個數(shù)];
注:數(shù)組中的所有元素都是同一種數(shù)據(jù)類型,不可能在一個數(shù)組中出現(xiàn)兩種數(shù)據(jù)類型的數(shù)。
(2) 數(shù)組的使用:數(shù)組定義的時候是作為一個整體來定義的,但是使用的時候不能作為一個整體來使用,使用時必須拆開使用數(shù)組中的各個元素;
如:數(shù)組int a[10],使用其中的十個元素,分別用a[0]……a[9],其中[]是數(shù)組的標(biāo)志,[]中的數(shù)字叫做數(shù)組的下標(biāo)(index,索引),下標(biāo)是我們訪問數(shù)組中各個元素的指引,
下標(biāo)是0代表數(shù)組中第一個元素,下標(biāo)是1代表數(shù)組第二個元素,以此類推,若數(shù)組長度為n,則下標(biāo)中最后一個是n-1;
注:訪問數(shù)組時要特別注意下標(biāo),下標(biāo)是從0開始的,如果下標(biāo)超出了n-1,會產(chǎn)生越界訪問,結(jié)果是不可預(yù)期的;
(3) 數(shù)組的初始化:初始化是為了讓對象有一個預(yù)定的初始狀態(tài),數(shù)組的初始化分兩種:
第一種:完全初始化。依次賦值;
第二種:不完全初始化。初始化式中的值從a[0]開始,依次向后賦值,不足的默認(rèn)用0填充賦值
(4) 不同數(shù)據(jù)類型的數(shù)組:
int a[3]; // 整型數(shù)組 float b[3]; // 單精度浮點(diǎn)型數(shù)組 double c[3]; // 雙精度浮點(diǎn)型數(shù)組 char d[3]; // 字符型數(shù)組
(5) 字符數(shù)組:在C語言中引用一個單個字符時,應(yīng)該用單引號''括起來,譬如'a';
字符數(shù)組的初始化:定義數(shù)組同時初始化,則可以省略數(shù)組定義時[]中的長度。C語言編譯器會自動推論其長度,推論依據(jù)是初始化式中初始化元素的個數(shù);
引用字符串:在C語言中引用一個字符串時,應(yīng)該用""括起來,如"abcde",其中"abcde"實際上有6個字符,分別是'a' 'b' 'c' 'd' 'e' '\0';
'\0' 是C語言中定義的字符串的結(jié)尾標(biāo)志,這個字符是ASCII碼表中的第一個字符,它的編碼值是0,對應(yīng)的字符是空字符(不可見字符);
// 數(shù)組的演示 #include <stdio.h> int main(void) { int a[4]; a[0] = 23; a[1] = 54; a[2] = 98; a[3] = 74; printf("a[1] = %d, a[3]= %d.\n", a[1], a[3]); return 0; }
// 字符數(shù)組的演示 #include <stdio.h> int main(void) { /* int i = 0; //char a[5]; //char a[5] = {'a', 'b', 'c', 'd', 'e'}; //char a[5] = {97, 98, 99, 100, 101}; //char a[] = {97, 98, 99, 100, 101}; char a[] = "abcde"; for (i=0; i<5; i++) { printf("a[%d] = %d %c\n", i, a[i], a[i]); } */ int i = 0; char a[] = {97, 98, 99, 100, 101}; char b[] = "abcde"; printf("sizeof(a) = %d, sizeof(b) = %d.\n", sizeof(a), sizeof(b)); return 0; }
3、指針:全稱是指針變量,其實質(zhì)是C語言的一種變量。這種變量比較特殊,通常它的值會被賦值為某個變量的地址值(p = &a),然后我們可以使用*p這樣的方式去間接訪問p所指向的那個變量;
(1) 指針存在的意義:可以間接訪問。有了指針之后,我們訪問變量a不必只通過a這個變量名來訪問。而可以通過p = &a; *p = xxx;這樣的方式來間接訪問變量a;
(2) 兩個重要的運(yùn)算符:&和*
&:取地址符,將它加在某個變量前面,則組合后的符號代表這個變量的地址值;
如: int a; int *p; p = &a; 則將變量a的地址值賦值給p
a 代表變量a本身
p 代表指針變量p本身
&a 代表變量a的地址值
*p 代表指針變量p所指向的那個變量,也就是變量a
&p 代表指針變量p本身的地址值,符號雖合法,但對題目無意義
*a 把a(bǔ)看作一個指針,*a表示這個指針?biāo)赶虻淖兞?,該符號不合?/p>
*:指針符號。指針符號在指針定義和指針操作的時候,解析方法是不同的;
int *p; 定義指針變量p,這里的*p含義不是代表指針變量p所指向的那個變量,在定義時這里的*含義是告訴編譯器p是一個指針
*p = 0x24; 使用指針的時候,*p則代表指針變量p所指向的那個變量
(3) 指針的定義和初始化:
第一種:先定義再賦值
int *p; // 定義指針變量p
p = &a; // 給p賦值
第二種:定義的同時初始化
int *p = &a; // 效果等同于上面的兩句
(4) 各種不同類型的指針:指針變量本質(zhì)上是一個變量,指針變量的類型屬于指針類型。int *p;定義了一個指針類型的變量p,這個p所指向的那個變量是int型;
int *pInt; // pInt是指針變量,指向的變量是int類型
char *pChar; // pChar是指針類型,指向的變量是char類型
float *pFloat;
double *pDouble;
注:各種指針類型和它們所指向的變量類型必須匹配,否則結(jié)果不可預(yù)知;
(5) 指針定義的兩種理解方法:
int *p;
第一種(推薦):首先看到p,這個是變量名;其次,p前面有個*,說明這個變量p是一個指針變量;最后,*p前面有一個int,說明這個指針變量p所指向的是一個int型數(shù)據(jù);
第二種:首先看到p,這個是變量名;其次,看到p前面的int *,把int *作為一個整體來理解,int *是一種類型(復(fù)合類型),該類型表示一種指向int型數(shù)據(jù)的指針;
(6) 指針與數(shù)組的初步結(jié)合:
數(shù)組名:做右值時,數(shù)組名表示數(shù)組的首元素首地址,因此可以直接賦值給指針;
如:int a[10];其中a和&a[0]都表示數(shù)組首元素a[0]的首地址,而&a則表示數(shù)組的首地址;
注:數(shù)組首元素的首地址和數(shù)組的首地址是不同的,前者是數(shù)組元素的地址,而后者是數(shù)組整體的地址。兩個東西的含義不同,但是數(shù)值上是相同的;
根據(jù)以上,我們知道可以用一個指針指向數(shù)組的第一個元素,這樣就可以用間接訪問的方式去逐個訪問數(shù)組中的元素,這樣訪問數(shù)組就有了兩種方式:
有 int a[5]; int *p; p = a;
數(shù)組的方式依次訪問:a[0] a[1] a[2] a[3] a[4]
指針的方式依次訪問:*p *(p+1) *(p+2) *(p+3) *(p+4)
(7) 指針與++ --符號進(jìn)行運(yùn)算:指針本身也是一種變量,因此也可以進(jìn)行運(yùn)算,但是因為指針變量本身存的是某個其他變量的地址值,因此該值進(jìn)行* / %等運(yùn)算是無意義的,
故兩個指針變量相加本身也無意義,但相減有意義。指針變量+1,-1是有意義的,+1就代表指針?biāo)赶虻母褡酉蚝笈惨桓瘢?1代表指針?biāo)赶虻母褡酉蚯芭惨桓瘛?/p>
*p++的解析:++先跟p結(jié)合,但是因為++后置的時候,本身含義就是先運(yùn)算后增加1(運(yùn)算指的是p++整體與前面的*進(jìn)行運(yùn)算;增加1指的是p+1),所以實際上*p++符號整體對外表現(xiàn)的
值是*p的值,運(yùn)算完成后p再加1;
*p++等同于:*p; p += 1;
*++p等同于:p += 1; *p;
(*p)++,使用()強(qiáng)制將*與p結(jié)合,只能先計算*p,然后對*p整體的值++
++(*p),先*p取值,再前置++,該值+1后作為整個表達(dá)式的值
// 指針的定義、賦值及初始化 #include <stdio.h> int main(void) { int a = 23; int *p = &a; *p = 111; printf("a = %d\n", a); return 0; }
// 用指針去訪問數(shù)組 #include <stdio.h> int main(void) { int a[5] = {555, 444, 333, 222, 111}; int *p; //p = &a; //p = &a[0]; p = a; //p += 1; //printf("*p = %d.\n", *p); //printf("*p++ = %d.\n", *p++); //printf("*++p = %d.\n", *++p); //printf("(*p)++ = %d.\n", (*p)++); printf("++(*p) = %d.\n", ++(*p)); return 0; }
4、補(bǔ)充:變量與數(shù)據(jù)類型的實質(zhì)
(1) 程序在環(huán)境中運(yùn)行時,需要一定的資源支持,而這些資源包括:CPU(運(yùn)算能力)、內(nèi)存等,這些資源一般由運(yùn)行時環(huán)境(一般是操作系統(tǒng))來提供,比如我們在linux系統(tǒng)上./a.out運(yùn)行程序時,
linux系統(tǒng)為我們提供了運(yùn)算能力和內(nèi)存;
(2) 程序越龐大,運(yùn)行時消耗的資源越多,比如說內(nèi)存額定占用,如果越大的程序,占用的內(nèi)存肯定越多,而占用內(nèi)存的其中之一,就是我們在程序中定義的變量;
(3) C語言程序中,變量的實質(zhì)就是內(nèi)存中的一個格子。當(dāng)我們定義了一個變量后,就相當(dāng)于在內(nèi)存中得到了一個格子,而這個格子的名字就是變量名,
以后訪問這個內(nèi)存格子就只用使用該變量名就行了,這就是變量的本質(zhì);
(4) 數(shù)據(jù)類型的實質(zhì)是內(nèi)存中格子的不同種類。比如在32位的機(jī)器上:
短整形格子(short) 占用2字節(jié),即16位的空間
整形格子(int) 占用4字節(jié),即32位的空間
單精度浮點(diǎn)型格子(float) 占用4字節(jié),即32位的空間
雙精度浮點(diǎn)型格子(double) 占用8字節(jié),即64位的空間
字符型格子(char) 占用1字節(jié),即8位的空間
(5) sizeof運(yùn)算符:返回一個變量或者一個數(shù)據(jù)類型的內(nèi)存占用長度,以字節(jié)為單位;
// sizeof運(yùn)算符的演示 #include <stdio.h> int main(void) { int len; //len = sizeof(int); //len = sizeof(float); //len = sizeof(double); //len = sizeof(char); //double d; //len = sizeof(d); int a[5]; //len = sizeof(a); len = sizeof(a) / sizeof(a[0]); printf("len = %d.\n", len); return 0; }
以上所述是小編給大家介紹的C語言中的函數(shù)、數(shù)組與指針,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
C 語言基礎(chǔ)實現(xiàn)青蛙跳臺階和漢諾塔問題
這篇文章我們九里講講C 語言基礎(chǔ)實現(xiàn)青蛙跳臺階和漢諾塔問題,感興趣的小伙伴可以參考下面文章的具體內(nèi)容2021-09-09C++基于boost asio實現(xiàn)sync tcp server通信流程詳解
這篇文章主要介紹了C++基于boost asio實現(xiàn)sync tcp server通信的流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07