程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C語言知識總結(4),c語言知識總結

C語言知識總結(4),c語言知識總結

編輯:關於C語言

C語言知識總結(4),c語言知識總結


變量的作用域

C語言根據變量作用域的不同,將變量分為局部變量和全局變量

1.局部變量

1> 定義:在函數內部定義的變量,稱為局部變量。形式參數也屬於局部變量。

2> 作用域:局部變量只在定義它的函數內部有效,即局部變量只有在定義它的函數內部使用,其它函數不能使用它。

2.全局變量

1> 定義:在所有函數外部定義的變量,稱為全局變量。

2> 作用域:全局變量的作用范圍是從定義變量的位置開始到源程序結束,即全局變量可以被在其定義位置之後的其它函數所共享。

變量的存儲類型

* 變量的存儲類型就是指變量存儲在什麼地方。有3個地方可以用於存儲變量:普通內存、運行時堆棧、硬件寄存器。變量的存儲類型決定了變量何時創建、何時銷毀以及它的值能保持多久,也就是決定了變量的生命周期。

* C語言根據變量的存儲類型的不同,可以把變量分為:自動變量、靜態變量、寄存器變量。

1.自動變量

1> 定義:自動變量是存儲在堆棧中的。

2> 哪些是自動變量:被關鍵字auto修飾的局部變量都是自動變量,但是極少使用這個關鍵字,基本上是廢的,因為所有的局部變量在默認情況下都是自動變量。

3> 生命周期:在程序執行到聲明自動變量的代碼塊(函數)時,自動變量才被創建;當自動變量所在的代碼塊(函數)執行完畢後,這些自動變量就會自行銷毀。如果一個函數被重復調用,這些自動變量每次都會重新創建。

2.靜態變量

1> 定義:靜態變量是存儲在靜態內存中的,也就是不屬於堆棧。

2> 哪些是靜態變量:

  • 所有的全局變量都是靜態變量

  • 被關鍵字static修飾的局部變量也是靜態變量

3> 生命周期:靜態變量在程序運行之前創建,在程序的整個運行期間始終存在,直到程序結束。

 1 #include <stdio.h>
 2 
 3 int a;
 4 
 5 void test() {
 6     static int b = 0;
 7     b++;
 8     
 9     int c = 0;
10     c++;
11     
12     printf("b=%d, c=%d \n", b, c);
13 }
14 
15 int main() {
16     int i;
17     // 連續調用3次test函數
18     for (i = 0; i<3; i++) {
19         test();
20     }
21     
22     return 0;
23 }

* 第3行的變量a、第6行的變量b都是靜態變量,第9行的變量c、第16行的變量i是自動變量。

* 因為第6行的變量b是靜態變量,所以它只會被創建一次,而且生命周期會延續到程序結束。因為它只會創建一次,所以第6行代碼只會執行一次,下次再調用test函數時,變量b的值不會被重新初始化為0。

* 注意:雖然第6行的變量b是靜態變量,但是只改變了它的存儲類型(即生命周期),並沒有改變它的作用域,變量b還是只能在test函數內部使用。

* 我們在main函數中重復調用test函數3次,輸出結果為:  b = 1, c = 1

                                    b = 2, c = 1

                                    b = 3, c = 1

3.寄存器變量

1> 定義:存儲在硬件寄存器中的變量,稱為寄存器變量。寄存器變量比存儲在內存中的變量訪問效率更高(默認情況下,自動變量和靜態變量都是放在內存中的)

2> 哪些變量是寄存器變量:

  • 被關鍵字register修飾的自動變量都是寄存器變量

  • 只有自動變量才可以是寄存器變量,全局變量和靜態局部變量不行

  • 寄存器變量只限於int、char和指針類型變量使用

3> 生命周期:因為寄存器變量本身就是自動變量,所以函數中的寄存器變量在調用該函數時占用寄存器中存放的值,當函數結束時釋放寄存器,變量消失。

4> 使用注意:

  • 由於計算機中寄存器數目有限,不能使用太多的寄存器變量。如果寄存器使用飽和時,程序將寄存器變量自動轉換為自動變量處理

  • 為了提高運算速度,一般會將一些頻繁使用的自動變量定義為寄存器變量,這樣程序盡可能地為它分配寄存器存放,而不用內存

結構體

形式:

struct 結構體名{
類型名1 成員名1;
類型名2 成員名2;
……
類型名n 成員名n;   
};

結構體變量的定義

1.先定義結構體類型,再定義變量

struct Student {
    char *name;
    int age;
};

struct Student stu;

2.定義結構體類型的同時定義變量

struct Student {
    char *name;
    int age;
} stu;

3.直接定義結構體類型變量,省略類型名

struct {
    char *name;
    int age;
} stu;

結構體的注意點

  • 不允許對結構體本身遞歸定義

  • 結構體內可以包含別的結構體

  • 定義結構體類型,只是說明了該類型的組成情況,並沒有給它分配存儲空間,就像系統不為int類型本身分配空間一樣。只有當定義屬於結構體類型的變量時,系統才會分配存儲空間給該變量

  • 結構體變量占用的內存空間是其成員所占內存之和,而且各成員在內存中按定義的順序依次排列

結構體內存結構

1、結構體所占用的內存與其成員的聲明順序有關,例如:

 1 struct stu1 {
 2    char a;   //1個字節
 3    char b;   //1個字節
 4    int c;    //4個字節
 5 };
 6 struct stu2 {
 7    char a;
 8    int c;
 9    char b;
10 };
11 
12 sizeof(stu1) --> 8 ?;  //和系統有關
13 sizeof(stu2) --> 12 ?; //和系統有關

2、寬度和對齊的概念

1)每個成員的寬度用sizeof即可知道,例如bool和char是1,short是2,int是4,string是8。 2)預編譯命令#pragma pack(n), n=1,2,4,8,16用來指定"對齊系數",#pragma pack()用來恢復默認。 3)數據成員對齊規則:結構體struct(或聯合體union)的成員,第一個成員的偏移量為0,以後每個數據成員的偏移量取其寬度和對齊系數的最小值。 4)結構體自身對齊規則:結構體自身也要對齊,對齊按照其成員最大寬度和對齊系數的最小值。

解析(#pragma pack(4)):

 1 struct stu1 {
 2    char a;   //1個字節 偏移0
 3    char b;   //1個字節 偏移1
 4    //由於對齊系數是4,這裡要補充2個字節。
 5    int c;    //4個字節 偏移4
 6 };
 7 sizeof(stu1) --> 8
 8 struct stu2 {
 9    char a; //1個字節,偏移0,占1個字節
10    //由於對齊系數是4,這裡要補充3個字節
11    int c;  //4個字節,偏移4
12    char b; //1個字節,偏移8
13    //由於對齊系數是4,這裡要補充3個字節
14 };
15 sizeof(stu2) --> 12

結構體的初始化

將各成員的初值,按順序地放在一對大括號{}中,並用逗號分隔,一一對應賦值。

比如初始化Student結構體變量stu

struct Student {
    char *name;
    int age;
};

struct Student stu = {"Zhy", 23};

只能在定義變量的同時進行初始化賦值,初始化賦值和變量的定義不能分開,下面的做法是錯誤的:

struct Student stu;
stu = {"Zhy", 23};

結構體的使用

  • 一般對結構體變量的操作是以成員為單位進行的,引用的一般形式為:結構體變量名.成員名

  • 如果某個成員也是結構體變量,可以連續使用成員運算符"."訪問最低一級成員

  • 相同類型的結構體變量之間可以進行整體賦值

結構體數組

定義方式

struct Student {
    char *name;
    int age;
};
struct Student stu[5]; //第一種

struct Student {
    char *name;
    int age;
} stu[5]; //第二種

struct {
    char *name;
    int age;
} stu[5]; //第三種

初始化

struct {
    char *name;
    int age;
} stu[2] = { {"Zhy", 23}, {"zz", 18} };

結構體作為函數參數

將結構體變量作為函數參數進行傳遞時,其實傳遞的是全部成員的值,也就是將實參中成員的值一一賦值給對應的形參成員。因此,形參的改變不會影響到實參

指向結構體的指針

* 每個結構體變量都有自己的存儲空間和地址,因此指針也可以指向結構體變量

* 結構體指針變量的定義形式:struct 結構體名稱 *指針變量名

* 有了指向結構體的指針,那麼就有3種訪問結構體成員的方式

  • 結構體變量名.成員名

  • (*指針變量名).成員名

  • 指針變量名->成員名

#include <stdio.h>

int main(int argc, const char * argv[]) {
    // 定義一個結構體類型
    struct Student {
        char *name;
        int age;
    };
    
    // 定義一個結構體變量
    struct Student stu = {"Zhy", 23};
    
    // 定義一個指向結構體的指針變量
    struct Student *p;
    
    // 指向結構體變量stu
    p = &stu;

    /*
     這時候可以用3種方式訪問結構體的成員
     */
    // 方式1:結構體變量名.成員名
    printf("name=%s, age = %d \n", stu.name, stu.age);
    
    // 方式2:(*指針變量名).成員名
    printf("name=%s, age = %d \n", (*p).name, (*p).age);
    
    // 方式3:指針變量名->成員名
    printf("name=%s, age = %d \n", p->name, p->age);
    
    return 0;
}

枚舉

概念:枚舉是C語言中的一種基本數據類型,並不是構造類型,它可以用於聲明一組常數。當一個變量有幾個固定的可能取值時,可以將這個變量定義為枚舉類型。

例如:可以用一個枚舉類型的變量描述星期,因為星期只有7中可能星期一至星期日

枚舉類型的定義

一般形式為:enum 枚舉名 {枚舉元素1,枚舉元素2,……};

1.先定義枚舉類型,再定義枚舉變量

enum Season {spring, summer, autumn, winter};

enum Season s;

2.定義枚舉類型的同時定義枚舉變量

enum Season {spring, summer, autumn, winter} s;

3.省略枚舉名稱,直接定義枚舉變量

enum {spring, summer, autumn, winter} s;

上面三種方式定義的都是枚舉變量s

枚舉使用注意

1> C語言編譯器會將枚舉元素(spring、summer等)作為整型常量處理,稱為枚舉常量。

2> 枚舉元素的值取決於定義時各枚舉元素排列的先後順序。默認情況下,第一個枚舉元素的值為0,第二個為1,依次順序加1。

enum Season {spring, summer, autumn, winter};

也就是說spring的值為0,summer的值為1,autumn的值為2,winter的值為3

3> 也可以在定義枚舉類型時改變枚舉元素的值

enum season {spring, summer=3, autumn, winter};

沒有指定值的枚舉元素,其值為前一元素加1。也就說spring的值為0,summer的值為3,autumn的值為4,winter的值為5

枚舉基本操作

enum Season {spring, summer, autumn, winter} s;

s = spring; // 等價於 s = 0;

s = 3; // 等價於 s = winter;

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved