C/C++編程筆記:C語言入門知識點(二),請收藏C語言最全筆記!

来源:https://www.cnblogs.com/yxy6/archive/2020/07/15/13309939.html
-Advertisement-
Play Games

今天我們繼續來學習C語言的入門知識點 11. 作用域規則 任何一種編程中,作用域是程式中定義的變數所存在的區域,超過該區域變數就不能被訪問。C 語言中有三個地方可以聲明變數: 在函數或塊內部的局部變數 在所有函數外部的全局變數 在形式參數的函數參數定義中 讓我們來看看什麼是局部變數、全局變數和形式參 ...


今天我們繼續來學習C語言的入門知識點

11. 作用域規則

任何一種編程中,作用域是程式中定義的變數所存在的區域,超過該區域變數就不能被訪問。C 語言中有三個地方可以聲明變數:

在函數或塊內部的局部變數

在所有函數外部的全局變數

形式參數的函數參數定義中

讓我們來看看什麼是局部變數、全局變數和形式參數。

局部變數

在某個函數或塊的內部聲明的變數稱為局部變數。它們只能被該函數或該代碼塊內部的語句使用。局部變數在函數外部是不可知的。下麵是使用局部變數的實例。在這裡,所有的變數 a、b 和 c 是 main() 函數的局部變數。

void main(){

    //局部變數

    int a, b;

    int c;

    //初始化局部變數

    a = 10;

    b = 20;

    c = a + b;

    //%d:以十進位形式輸出帶符號整數(正數不輸出符號)

    printf("values of a = %d,b = %d and c = %d \n", a, b, c);

}

輸出:values of a = 10,b = 20 and c = 30

 

全局變數

全局變數是定義在函數外部,通常是在程式的頂部。全局變數在整個程式生命周期內都是有效的,在任意的函數內部能訪問全局變數。

全局變數可以被任何函數訪問。也就是說,全局變數在聲明後整個程式中都是可用的。下麵是使用全局變數和局部變數的實例:

//全局變數聲明

int g;

void main(){

  int a, b;

    //初始化局部變數

    a = 10;

    b = 20;

  //全部變數賦值

    g = a + c;

    printf("values of a = %d,bc = %d and g = %d \n", a, c, g);

}

輸出:values of a = 10,bc = 30 and g = 40

 

形式參數

函數的參數,形式參數,被當作該函數內的局部變數,如果與全局變數同名它們會優先使用。下麵是一個實例:

int sumA(int a, int b) {

    printf("value of a in sum() = %d\n", a);

    printf("value of b in sum() = %d\n", b);

    return x + y;

}

void main(){

  int a, b,c;

    //初始化局部變數

    a = 10;

    b = 20;

  c = sumA(a, b);

  printf("value of c in main() = %d\n", c);

}

輸出:value of a in main() = 30

 

全局變數和局部變數的區別

(1)全局變數保存在記憶體的全局存儲區中,占用靜態的存儲單元;

(2)局部變數保存在棧中,只有在所在函數被調用時才動態地為變數分配存儲單元。

初始化局部變數和全局變數的預設值

12. 數組

C 語言支持數組數據結構,它可以存儲一個固定大小的相同類型元素的順序集合。數組是用來存儲一系列數據,但它往往被認為是一系列相同類型的變數。

數組的聲明並不是聲明一個個單獨的變數,比如 number0、number1、...、number99,而是聲明一個數組變數,比如 numbers,然後使用 numbers[0]、numbers[1]、...、numbers[99] 來代表一個個單獨的變數。數組中的特定元素可以通過索引訪問。

所有的數組都是由連續的記憶體位置組成。最低的地址對應第一個元素,最高的地址對應最後一個元素。

聲明數組

在 C 中要聲明一個數組,需要指定元素的類型和元素的數量,如下所示:

type arrayName [ arraySize ];

這叫做一維數組。arraySize 必須是一個大於零的整數常量,type 可以是任意有效的 C 數據類型。例如,要聲明一個類型為 double 的包含 10 個元素的數組 balance,聲明語句如下:

double balance[10];

初始化數組

void main(){

  double balance[10] = {1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0}

}

大括弧 { } 之間的值的數目不能大於我們在數組聲明時在方括弧 [ ] 中指定的元素數目。

如果您省略掉了數組的大小,數組的大小則為初始化時元素的個數。因此,如果:

void main(){

  double balance[] = {1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0}

}

您將創建一個數組,它與前一個實例中所創建的數組是完全相同的。下麵是一個為數組中某個元素賦值的實例:

balance[1] = 50.5;

訪問數組元素

//跟 Java 一樣

double value = balance[1]

例子:

void main() {

    //定義一個長度為 10 的整數數組

    int n[10];

    int i, j;

    //初始化數組元素

    for (i = 0; i < 10; i++) {

        n[i] = 2 * i;

    }

    //輸出元素中的數據

    for (int k = 0; k < 10; ++k) {

        printf("Element[%d] = %d \n", k, n[k]);

    }

    //總的大小除以其中一個大小就得到了 數組長度

    printf("整數數組 n 的長度: %d \n", sizeof(n) / sizeof(n[0]));

    //輸出元素中的數據

    for (int k = 0; k < sizeof(n) / sizeof(n[0]); ++k) {

        printf("Element[%d] = %d \n", k, n[k]);

    }

}

輸出:

Element[0] = 0

Element[1] = 2

Element[2] = 4

Element[3] = 6

Element[4] = 8

Element[5] = 10

Element[6] = 12

Element[7] = 14

Element[8] = 16

Element[9] = 18

整數數組 n 的長度: 10

Element[0] = 0

Element[1] = 2

Element[2] = 4

Element[3] = 6

Element[4] = 8

Element[5] = 10

Element[6] = 12

Element[7] = 14

Element[8] = 16

Element[9] = 18

 

C 中數組詳解

在 C 中,數組是非常重要的,我們需要瞭解更多有關數組的細節。下麵列出了 C 程式員必須清楚的一些與數組相關的重要概念:


13. 枚舉

枚舉是 C 語言中的一種基本數據類型,它可以讓數據更簡潔,更易讀。

枚舉語法定義格式為:

enum&emsp;枚舉名&emsp;{枚舉元素1,枚舉元素2,……};

接下來我們舉個例子,比如:一星期有 7 天,如果不用枚舉,我們需要使用 #define 來為每個整數定義一個別名:

#define MON 1

#define TUE  2

#define WED  3

#define THU  4

#define FRI  5

#define SAT  6

#define SUN  7

這個看起來代碼量就比較多,接下來我們看看使用枚舉的方式:

enum DAY

{

      MON=1, TUE, WED, THU, FRI, SAT, SUN

};

這樣看起來是不是更簡潔了。

**註意:**第一個枚舉成員的預設值為整型的 0,後續枚舉成員的值在前一個成員上加 1。我們在這個實例中把第一個枚舉成員的值定義為 1,第二個就為 2,以此類推。

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

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

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

枚舉變數的定義

前面我們只是聲明瞭枚舉類型,接下來我們看看如何定義枚舉變數。

我們可以通過以下三種方式來定義枚舉變數

1、先定義枚舉類型,再定義枚舉變數

enum DAY

{

      MON=1, TUE, WED, THU, FRI, SAT, SUN

};

enum DAY day;

2、定義枚舉類型的同時定義枚舉變數

enum DAY

{

      MON=1, TUE, WED, THU, FRI, SAT, SUN

} day;

3、省略枚舉名稱,直接定義枚舉變數

enum

{

      MON=1, TUE, WED, THU, FRI, SAT, SUN

} day;

 

14. 指針

學習 C 語言的指針既簡單又有趣。通過指針,可以簡化一些 C 編程任務的執行,還有一些任務,如動態記憶體分配,沒有指針是無法執行的。所以,想要成為一名優秀的 C 程式員,學習指針是很有必要的。

正如您所知道的,每一個變數都有一個記憶體位置,每一個記憶體位置都定義了可使用連字型大小(&)運算符訪問的地址,它表示了在記憶體中的一個地址。請看下麵的實例,它將輸出定義的變數地址:

void main(){

    int var1;

    char var2[10];

    //%p : 輸出指針地址

    printf("var1 變數的地址:%p \n", &var1);

    printf("var2 變數的地址:%p \n", &var2);

}

輸出:

var1 變數的地址:0x7ffee7e976b8

var2 變數的地址:0x7ffee7e976be

通過上面的實例,我們瞭解了什麼是記憶體地址以及如何訪問它。接下來讓我們看看什麼是指針。

什麼是指針?

指針是一個變數,其值為另一個變數的地址,即記憶體位置的直接地址。就像其他變數或常量一樣,您必須在使用指針存儲其他變數地址之前,對其進行聲明。指針變數聲明的一般形式為:

type *var-name

在這裡,type 是指針的基類型,它必須是一個有效的 C 數據類型,var-name 是指針變數的名稱。用來聲明指針的星號 * 與乘法中使用的星號是相同的。但是,在這個語句中,星號是用來指定一個變數是指針。以下是有效的指針聲明:

int *i; //一個整型的指針

double *d;//double 型指針

float *f;//浮點型指針

char *ch//字元型指針

所有實際數據類型,不管是整型、浮點型、字元型,還是其他的數據類型,對應指針的值的類型都是一樣的,都是一個代表記憶體地址的長的十六進位數。

不同數據類型的指針之間唯一的不同是,指針所指向的變數或常量的數據類型不同。

如何使用指針?

使用指針時會頻繁進行以下幾個操作:定義一個指針變數、把變數地址賦值給指針、訪問指針變數中可用地址的值。這些是通過使用一元運算符 ***** 來返回位於操作數所指定地址的變數的值。下麵的實例涉及到了這些操作:

例子:

//如何使用指針

    int var = 66;//實際變數的聲明

    int *ip;//指針變數的聲明

    ip = &var; //指針變數中存儲 var 的地址

    printf("var 的地址 : %p  \n", var);

    //在指針變數中存儲的地址

    printf("ip 的地址:%p  \n", ip);

    //使用指針訪問地址

    printf("ip 指針對應的地址:%p \n", *ip);

    //使用指針訪問地址對應的值

    printf("ip 指針對應的地址:%d \n", *ip);

輸出:

var 的地址 : 0x42

ip 的地址:0x7ffee96eb6b4 

ip 指針對應的地址:0x42

ip 指針對應的地址:66

C 中的 NULL 指針

在變數聲明的時候,如果沒有確切的地址可以賦值,為指針變數賦一個 NULL 值是一個良好的編程習慣。賦為 NULL 值的指針被稱為指針。

NULL 指針是一個定義在標準庫中的值為零的常量。請看下麵的程式:

void main(){

    //賦值一個 NULL 指針

    int *ptr = NULL;

    printf("ptr 的地址是: %p \n", ptr);

    //檢查一個空指針

    if (ptr) printf("如果 ptr 不是空指針,則執行"); else printf("如果 ptr 是空指針,則執行");

}

輸出:ptr 的地址是: 0x0 ptr 是空指針

C 指針詳解

在 C 中,有很多指針相關的概念,這些概念都很簡單,但是都很重要。下麵列出了 C 程式員必須清楚的一些與指針相關的重要概念:


15. 函數指針與回調函數

函數指針是指向函數的指針變數。

通常我們說的指針變數是指向一個整型、字元型或數組等變數,而函數指針是指向函數。

函數指針可以像一般函數一樣,用於調用函數、傳遞參數。

函數指針變數的聲明:

typedef int (*fun_ptr)(int,int)//聲明一個指向同樣參數,返回值得函數指針類型

回調函數

函數指針變數可以作為某個函數的參數來使用的,回調函數就是一個通過函數指針調用的函數。

簡單講:回調函數是由別人的函數執行時調用你實現的函數。

例子:

例子中 populate_array 函數定義了三個參數,其中第三個參數是函數的指針,通過該函數來設置數組的值。

實例中我們定義了回調函數 getNextRandomValue,它返回一個隨機值,它作為一個函數指針傳遞給 populate_array 函數。

populate_array 將調用 10 次回調函數,並將回調函數的返回值賦值給數組。

#include <stdlib.h>

#include <stdio.h>

//回調函數

void populate_array(int *array, size_t arraySize, int(*getNextValue)(void)) {

    printf("array 地址:%p \n", array);

    for (size_t i = 0; i < arraySize; i++) {

        array[i] = getNextValue();

        printf(" array[%d] ,存儲值:%d \n", i, array[i]);

    }

}

//獲取一個隨機數

int getNextRandomValue(void) {

    return rand();

}

void main() {

    //回調函數

    int array[10];

    printf("Int array 地址:%p \n", array);

    populate_array(array, sizeof(array)/sizeof(array[0]), getNextRandomValue);

    for (int i = 0; i < sizeof(array)/sizeof(array[0]); ++i) {

        printf(" array[%d] , 對應值為:%d \n", i, array[i]);

    }

}

輸出:

Int array 地址:0x7ffeebf1a650

array 地址:0x7ffeebf1a650

array[0] ,存儲值:16807

array[1] ,存儲值:282475249

array[2] ,存儲值:1622650073

array[3] ,存儲值:984943658

array[4] ,存儲值:1144108930

array[5] ,存儲值:470211272

array[6] ,存儲值:101027544

array[7] ,存儲值:1457850878

array[8] ,存儲值:1458777923

array[9] ,存儲值:2007237709

array[0] , 對應值為:16807

array[1] , 對應值為:282475249

array[2] , 對應值為:1622650073

array[3] , 對應值為:984943658

array[4] , 對應值為:1144108930

array[5] , 對應值為:470211272

array[6] , 對應值為:101027544

array[7] , 對應值為:1457850878

array[8] , 對應值為:1458777923

array[9] , 對應值為:2007237709

 

16. 字元串

在 C 語言中,字元串實際上是使用null字元 '\0' 終止的一維字元數組。因此,一個以 null 結尾的字元串,包含了組成字元串的字元。

下麵的聲明和初始化創建了一個 "Hello" 字元串。由於在數組的末尾存儲了空字元,所以字元數組的大小比單詞 "Hello" 的字元數多一個。

char ch[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

也可以使用以下簡寫模式:

char ch[6] = "Hello"

字元串在 C/C++ 中記憶體表示:

其實,您不需要把 null 字元放在字元串常量的末尾。C 編譯器會在初始化數組時,自動把 '\0' 放在字元串的末尾。讓我們嘗試輸出上面的字元串:

void main(){

      //定義一個 char 數組

    char string[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

    //簡寫

    char string2[6] = "Hello";

    //%s:輸出字元串

    printf("string message : %s\n", string);

}

輸出:string message : Hello

C 中對字元串操作的 API


17. 結構體

C 數組允許定義可存儲相同類型數據項的變數,結構是 C 編程中另一種用戶自定義的可用的數據類型,它允許您存儲不同類型的數據項。

結構用於表示一條記錄,假設您想要跟蹤圖書館中書本的動態,您可能需要跟蹤每本書的下列屬性:

(1)Title

(2)Author

(3)Subject

(4)Book ID

定義結構

為了定義結構,您必須使用struct語句。struct 語句定義了一個包含多個成員的新的數據類型,struct 語句的格式如下:

struct name{

  member-list;

  member-list;

  ...

}name_tag,

name是結構的標簽。

member-list是標準的變數定義,比如 int i;或者 float f,或者其它有效的變數定義。

name_tag結構變數,定義在結構的末尾,最後一個分號之前,你可以指定一個或多個結構變數,下麵是聲明 Book 的結構方式:

struct Books{

  char title[50];

  char author[50];

  char subject[100];

  int book_id;

} book;

註意:在定義結構體的時候name、member-list、name_tag 這 3 部分至少要出現 2 個。

結構體變數的初始化

和其它類型變數一樣,在初始化的時候可以指定初始值。

//定義一個 Books 結構,類似於 Java 中的數據 bean

struct Books {

    char title[50];

    char author[50];

    char subject[100];

    int book_id;

    double rmb;

} book = {"Java", "Android", "C 語言", 666, 55.5};

void main(){

      //列印 Books

    printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\nrmb: %f\n", book.title,

          book.author, book.subject, book.book_id, book.rmb);

}

輸出:

title : Java

author: Android

subject: C 語言

book_id: 666

rmb: 55.500000

訪問結構成員

struct Books2 {

    char title[50];

    char author[50];

    char subject[100];

    int book_id;

};

void main(){

      //訪問 Books2 結構成員

    struct Books2 Books2A;//聲明 Books2A 類型為 Books2

    struct Books2 Books2B;//聲明 Books2B 類型為 Books2

    //Books2A 詳述

    strcpy(Books2A.title, "C Plus");

    strcpy(Books2A.author, "Nuha Ali");

    strcpy(Books2A.subject, "C");

    Books2A.book_id = 666888;

    //Books2B 詳述

    strcpy(Books2B.title, "C++ Plus");

    strcpy(Books2B.author, "DevYK");

    strcpy(Books2B.subject, "C++");

    Books2B.book_id = 666999;

    // 輸出 Book1 信息

    printf("Book 1 title : %s\n", Books2A.title);

    printf("Book 1 author : %s\n", Books2A.author);

    printf("Book 1 subject : %s\n", Books2A.subject);

    printf("Book 1 book_id : %d\n", Books2A.book_id);

    // 輸出 Book2 信息

    printf("Book 2 title : %s\n", Books2B.title);

    printf("Book 2 author : %s\n", Books2B.author);

    printf("Book 2 subject : %s\n", Books2B.subject);

    printf("Book 2 book_id : %d\n", Books2B.book_id);

}

輸出:

Book 1 title : C Plus

Book 1 author : Nuha Ali

Book 1 subject : C

Book 1 book_id : 666888

Book 2 title : C++ Plus

Book 2 author : DevYK

Book 2 subject : C++

Book 2 book_id : 666999

結構作為函數參數

//函數聲明

void printBook(struct Books2 books2);

void main(){

      //訪問 Books2 結構成員

    struct Books2 Books2A;//聲明 Books2A 類型為 Books2

    struct Books2 Books2B;//聲明 Books2B 類型為 Books2

    //Books2A 詳述 ,將 CPlus copy 到 title 中

    strcpy(Books2A.title, "C Plus");

    strcpy(Books2A.author, "Nuha Ali");

    strcpy(Books2A.subject, "C");

    Books2A.book_id = 666888;

    //Books2B 詳述

    strcpy(Books2B.title, "C++ Plus");

    strcpy(Books2B.author, "DevYK");

    strcpy(Books2B.subject, "C++");

    Books2B.book_id = 666999;

    // 輸出 Book1 信息

    printf("Book 1 title : %s\n", Books2A.title);

    printf("Book 1 author : %s\n", Books2A.author);

    printf("Book 1 subject : %s\n", Books2A.subject);

    printf("Book 1 book_id : %d\n", Books2A.book_id);

    // 輸出 Book2 信息

    printf("Book 2 title : %s\n", Books2B.title);

    printf("Book 2 author : %s\n", Books2B.author);

    printf("Book 2 subject : %s\n", Books2B.subject);

    printf("Book 2 book_id : %d\n", Books2B.book_id);

    printf("\n\n\n");

    //結構作為函數參數

    printBook(Books2A);

    printBook(Books2B);

}

void printBook(struct Books2 book) {

    printf("Book  title : %s\n", book.title);

    printf("Book  author : %s\n", book.author);

    printf("Book  subject : %s\n", book.subject);

    printf("Book  book_id : %d\n", book.book_id);

}

輸出:

Book 1 title : C Plus

Book 1 author : Nuha Ali

Book 1 subject : C

Book 1 book_id : 666888

Book 2 title : C++ Plus

Book 2 author : DevYK

Book 2 subject : C++

Book 2 book_id : 666999

Book  title : C Plus

Book  author : Nuha Ali

Book  subject : C

Book  book_id : 666888

Book  title : C++ Plus

Book  author : DevYK

Book  subject : C++

Book  book_id : 666999

指向結構的指針

您可以定義指向結構的指針,方式與定義指向其他類型變數的指針相似,如下所示:

struct Books *struct_pointer;

現在,您可以在上述定義的指針變數中存儲結構變數的地址。為了查找結構變數的地址,請把 & 運算符放在結構名稱的前面,如下所示:

struct_pointer = &Book1;

為了使用指向該結構的指針訪問結構的成員,您必須使用 -> 運算符,如下所示:

struct_pointer->title;

例子:

//定義指向結構的指針

void printBookZZ(struct Books2 *books2);

void main(){

      //訪問 Books2 結構成員

    struct Books2 Books2A;//聲明 Books2A 類型為 Books2

    struct Books2 Books2B;//聲明 Books2B 類型為 Books2

    //Books2A 詳述 ,將 CPlus copy 到 title 中

    strcpy(Books2A.title, "C Plus");

    strcpy(Books2A.author, "Nuha Ali");

    strcpy(Books2A.subject, "C");

    Books2A.book_id = 666888;

    //Books2B 詳述

    strcpy(Books2B.title, "C++ Plus");

    strcpy(Books2B.author, "DevYK");

    strcpy(Books2B.subject, "C++");

    Books2B.book_id = 666999;

 

    //通過記憶體地址傳遞信息,為了查找結構變數的地址,請把 & 運算符放在結構名稱的前面

    printBookZZ(&Books2A);

    printBookZZ(&Books2B);

}

/**

* 為了使用指向該結構的指針訪問結構的成員,您必須使用 -> 運算符,如下所示:

* @param book

*/

void printBookZZ(struct Books2 *book) {

    printf("Book -> title : %s\n", book->title);

    printf("Book -> author : %s\n", book->author);

    printf("Book -> subject : %s\n", book->subject);

    printf("Book -> book_id : %d\n", book->book_id);

}

 

位域

有些信息在存儲時,並不需要占用一個完整的位元組,而只需占幾個或一個二進位位。例如在存放一個開關量時,只有 0 和 1 兩種狀態,用 1 位二進位即可。為了節省存儲空間,並使處理簡便,C 語言又提供了一種數據結構,稱為"位域"或"位段"。

所謂"位域"是把一個位元組中的二進位劃分為幾個不同的區域,並說明每個區域的位數。每個域有一個功能變數名稱,允許在程式中按功能變數名稱進行操作。這樣就可以把幾個不同的對象用一個位元組的二進位位域來表示。

典型的實例:

(1)用 1 位二進位存放一個開關量時,只有 0 和 1 兩種狀態。

(2)讀取外部文件格式——可以讀取非標準的文件格式。

位域ed 定義:

struct 位域結構名稱{

  位域列表

};

位域列表的形式為:類型說明符 位功能變數名稱:位域長度

例:

struct bean {

  int a:8;

  int b:4;

  int c:4;

}data;

說明 data 為 bean 變數,共占 2個位元組。其中位域 a 占 8 位,位域 b 占 4 位,位域 c 占 4 位。

註意:

一個位域存儲在同一個位元組中,如一個位元組所剩空間不夠存放另一位域時,則會從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:

struct bean{

  unsigned a:4;

  unsigned  :4;//空域

  unsigned b:4;//從下一個單元開始存放

  unsigned c:4;

}

在這個位域定義中共占用 2 個位元組,a 占第一位元組的 4 位,後 4 位填 0 表示不使用,b 從第二位元組開始,占用 4 位,c 占用 4 位。

由於位域不允許跨兩個位元組,因此位域的長度不能大於一個位元組的長度,也就是說不能超過8位二進位。如果最大長度大於電腦的整數字長,一些編譯器可能會允許域的記憶體重疊,另外一些編譯器可能會把大於一個域的部分存儲在下一個字中。

位域可以是無名位域,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:

struct k{

int a:1;

int  :2;    /* 該 2 位不能使用 */

int b:3;

int c:2;

};

從以上分析可以看出,位域在本質上就是一種結構類型,不過其成員是按二進位分配的。

位域的使用

位域的使用和結構成員的使用相同,其一般形式為:

(1)位域變數名.位功能變數名稱

(2)位域變數名->位功能變數名稱

位域允許用各種格式輸出。

 

18. 共用體

共用體是一種特殊的數據類型,允許您在相同的記憶體位置存儲不同的數據類型。您可以定義一個帶有多成員的共用體,但是任何時候只能有一個成員帶有值。共用體提供了一種使用相同的記憶體位置的有效方式。

定義共同體

為了定義共用體,您必須使用union語句,方式與定義結構類似。union 語句定義了一個新的數據類型,帶有多個成員。union 語句的格式如下:

union [union tag]

{

member definition;

member definition;

...

member definition;

}[one or more union variables];

union tag是可選的,每個 member definition 是標準的變數定義,比如 int i; 或者 float f; 或者其他有效的變數定義。在共用體定義的末尾,最後一個分號之前,您可以指定一個或多個共用體變數,這是可選的。下麵定義一個名為 Data 的共用體類型,有三個成員 i、f 和 str:

union Data

{

int i;

float f;

char str[20];

}

現在,Data類型的變數可以存儲一個整數、一個浮點數,或者一個字元串。這意味著一個變數(相同的記憶體位置)可以存儲多個多種類型的數據。您可以根據需要在一個共用體內使用任何內置的或者用戶自定義的數據類型。

共用體占用的記憶體應足夠存儲共用體中最大的成員。例如,在上面的實例中,Data 將占用 20 個位元組的記憶體空間,因為在各個成員中,字元串所占用的空間是最大的。下麵的實例將顯示上面的共用體占用的總記憶體大小:

union Data {

    int i;

    float f;

    char str[20];

};

void main(){

    union Data data;

    printf("Memory size occupied by data: %d\n", sizeof(data));

}

輸出:Memory size occupied by data: 20

訪問共同體成員

為了訪問共用體的成員,我們使用成員訪問運算符(.)。成員訪問運算符是共用體變數名稱和我們要訪問的共用體成員之間的一個句號。您可以使用 union 關鍵字來定義共用體類型的變數。下麵的實例演示了共用體的用法:

union Data {

    int i;

    float f;

    char str[20];

};

void main() {

    //1. 訪問共同體 no

    data.i = 10;

    data.f = 1314.520;

    strcpy(data.str,"C/C++");

    printf( "data.i : %d\n", data.i);

    printf( "data.f : %f\n", data.f);

    printf( "data.str : %s\n", data.str);

    printf("\n\n\n");

    //2. 訪問共同體  yes

    data.i = 10;

    printf( "data.i : %d\n", data.i);

    data.f = 1314.520;

    printf( "data.f : %f\n", data.f);

    strcpy(data.str,"C/C++");

    printf( "data.str : %s\n", data.str);

}

輸出:

data.i : 725823299

data.f : 0.000000

data.str : C/C++

data.i : 10

data.f : 1314.520020

data.str : C/C++

在這裡,我們可以看到上面註釋 1 共用體的 i 和 f 成員的值有損壞,因為最後賦給變數的值占用了記憶體位置,這也是 str 成員能夠完好輸出的原因。我們看註釋 2 ,這次我們在同一時間只使用一個變數成員,所以都能完好輸出。

19. 位域

參考 17.(位域的介紹)

20. typedef

C 語言提供了 typedef 關鍵字,您可以使用它來為類型取一個新的名字。下麵的實例為單位元組數字定義了一個術語 BYTE

typedef unsigned char BYTE;

在這個類型定義之後,標識符 BYTE 可作為類型 unsigned char 的縮寫,例如:

BYTE b1, b2;

按照慣例,定義時會大寫字母,以便提醒用戶類型名稱是一個象徵性的縮寫,但您也可以使用小寫字母,如下:

typedef unsigned char byte;

您也可以使用 typedef 來為用戶自定義的數據類型取一個新的名字。例如,您可以對結構體使用 typedef 來定義一個新的數據類型名字,然後使用這個新的數據類型來直接定義結構變數,如下:

typedef struct Books {

    char title[50];

    char author[50];

    char subject[50];

    int book_id;

} Book;

#define TRUE  1

#define FALSE  0

void main(){

    Book book;

    strcpy( book.title, "C 教程");

    strcpy( book.author, "Runoob");

    strcpy( book.subject, "編程語言");

    book.book_id = 12345;

    printf( "書標題 : %s\n", book.title);

    printf( "書作者 : %s\n", book.author);

    printf( "書類目 : %s\n", book.subject);

    printf( "書 ID : %d\n", book.book_id);

    printf( "TRUE 的值: %d\n", TRUE);

    printf( "FALSE 的值: %d\n", FALSE);

}

輸出:

書標題 : C 教程

書作者 : Runoob

書類目 : 編程語言

書 ID : 12345

TRUE 的值: 1

FALSE 的值: 0

typedef vs define

define是 C 指令,用於為各種數據類型定義別名,與typedef類似,但是它們有以下幾點不同:

(1)typedef僅限於為類型定義符號名稱,#define不僅可以為類型定義別名,也能為數值定義別名,比如您可以定義 1 為 ONE。

(2)typedef是由編譯器執行解釋的,#define語句是由預編譯器進行處理的。

例子可以參考上面是 #define  使用。


本節知識將會以分節的形式向大家展示,又想要學習C語言的小伙伴可以關註筆者!一起來加油呀~

自學C/C++編程難度很大,不妨和一些志同道合的小伙伴一起學習成長!

C語言C++編程學習交流圈子,【點擊進入微信公眾號:C語言編程學習基地

有一些源碼和資料分享,歡迎轉行也學習編程的伙伴,和大家一起交流成長會比自己琢磨更快哦!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 許可權管理系統中,菜單也屬於許可權控制的一個資源,應該直接應用於角色,和許可權功能點一樣,屬於角色控制的一環。不同角色用戶,登錄系統後,出現的系統菜單是不同的。在VUE+Element 前端中,我們菜單結合路由集合,實現可訪問路由的過濾,也就實現了對應角色菜單的展示和可訪問路由的控制,詳細可以參考隨筆《循... ...
  • 2020 年真的是災禍頻發,但是在各類前端框架上,依舊是在穩步的推進。近日 Vue 團隊更新了關於 Vue 3 的最新狀態,尤大新增了三個語法糖特性,它們將用於優化 SFC 的開發體驗,你會有興趣嘗鮮試試麽~ 登高遠眺 天高地迥,覺宇宙之無窮 前端框架 Vue 3: 2020 年中的狀態更新 近日 ...
  • 橋接模式的概念與實現 為什麼叫橋接模式 橋接模式的適用場景 繼承是面向對象的三大特性之一,但很多時候使用繼承的結果卻不盡如人意。除了人盡皆知的緊耦合問題外,有的時候還會導致子類的快速膨脹。 設想這樣一個場景:最初設計的時候有一個類型Product,但後來隨著新需求的出現,X原因導致了它的變化,X有兩 ...
  • 本專欄內容均引用《大話設計模式》並做適當修改, 起因 有部分電腦專業的學生或有一定經驗的在職開發者,他們都知道類、方法、構造方法、甚至抽象類、介面等概念,並用各種IDE寫過不少的Windows或Web程式,但是當問到為什麼要用面向對象,它的好處在哪裡,卻沒有人能完整的講出來,多數人的反應是,概念知 ...
  • 關於延遲載入 在 Spring 中,預設情況下所有定的 bean 及其依賴項目都是在應用啟動時創建容器上下文是被初始化的。測試代碼如下: @Slf4j @Configuration public class DemoConfig { public DemoConfig() { log.warn(" ...
  • 一、複習一下前面所學的內容 1.寫出下列字元或者數字的類型以及在printf()函數中使用什麼符號轉換 常量類型轉換說明(%轉換符號) 12 int %d 0X3 unsigned int %#x 'C' char(實際上是int) %c 2.34E07 double %e '\040' char( ...
  • 安裝python的mysqlclient==1.4.6報錯 環境:ubuntu18.04python 3.6.8Django 2.0 想要使用Django來操作MySQL,需要安裝一個驅動程式。在Python3中,選擇用mysqlclient做驅動。 安裝mysqlclient出現報錯: ERROR ...
  • 繼Golang學習系列第二天:變數、常量、數據類型和流程語句之後,今天開始學習數據類型之高級類型: 派生類型。 學過java的人都知道,java其實就8種基本類型:byte、short、int、long、float、double、char、boolean,但它有引用數據類型:字元串、數組、集合、類、 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...