C/C++編程筆記:C語言入門知識點(二),請收藏C語言最全筆記!
今天我們繼續(xù)來學(xué)習(xí)C語言的入門知識點,關(guān)注我,去看第一課哦~

11. 作用域規(guī)則
任何一種編程中,作用域是程序中定義的變量所存在的區(qū)域,超過該區(qū)域變量就不能被訪問。C 語言中有三個地方可以聲明變量:
在函數(shù)或塊內(nèi)部的局部變量
在所有函數(shù)外部的全局變量
在形式參數(shù)的函數(shù)參數(shù)定義中
讓我們來看看什么是局部變量、全局變量和形式參數(shù)。
局部變量
在某個函數(shù)或塊的內(nèi)部聲明的變量稱為局部變量。它們只能被該函數(shù)或該代碼塊內(nèi)部的語句使用。局部變量在函數(shù)外部是不可知的。下面是使用局部變量的實例。在這里,所有的變量 a、b 和 c 是 main() 函數(shù)的局部變量。
void main(){
? ? //局部變量
? ? int a, b;
? ? int c;
? ? //初始化局部變量
? ? a = 10;
? ? b = 20;
? ? c = a + b;
? ? //%d:以十進(jìn)制形式輸出帶符號整數(shù)(正數(shù)不輸出符號)
? ? printf("values of a = %d,b = %d and c = %d \n", a, b, c);
}
輸出:values of a = 10,b = 20 and c = 30
全局變量
全局變量是定義在函數(shù)外部,通常是在程序的頂部。全局變量在整個程序生命周期內(nèi)都是有效的,在任意的函數(shù)內(nèi)部能訪問全局變量。
全局變量可以被任何函數(shù)訪問。也就是說,全局變量在聲明后整個程序中都是可用的。下面是使用全局變量和局部變量的實例:
//全局變量聲明
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
形式參數(shù)
函數(shù)的參數(shù),形式參數(shù),被當(dāng)作該函數(shù)內(nèi)的局部變量,如果與全局變量同名它們會優(yōu)先使用。下面是一個實例:
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
全局變量和局部變量的區(qū)別
(1)全局變量保存在內(nèi)存的全局存儲區(qū)中,占用靜態(tài)的存儲單元;
(2)局部變量保存在棧中,只有在所在函數(shù)被調(diào)用時才動態(tài)地為變量分配存儲單元。
初始化局部變量和全局變量的默認(rèn)值

12. 數(shù)組
C 語言支持數(shù)組數(shù)據(jù)結(jié)構(gòu),它可以存儲一個固定大小的相同類型元素的順序集合。數(shù)組是用來存儲一系列數(shù)據(jù),但它往往被認(rèn)為是一系列相同類型的變量。
數(shù)組的聲明并不是聲明一個個單獨的變量,比如 number0、number1、...、number99,而是聲明一個數(shù)組變量,比如 numbers,然后使用 numbers[0]、numbers[1]、...、numbers[99] 來代表一個個單獨的變量。數(shù)組中的特定元素可以通過索引訪問。
所有的數(shù)組都是由連續(xù)的內(nèi)存位置組成。最低的地址對應(yīng)第一個元素,最高的地址對應(yīng)最后一個元素。
聲明數(shù)組
在 C 中要聲明一個數(shù)組,需要指定元素的類型和元素的數(shù)量,如下所示:
type arrayName [ arraySize ];
這叫做一維數(shù)組。arraySize?必須是一個大于零的整數(shù)常量,type?可以是任意有效的 C 數(shù)據(jù)類型。例如,要聲明一個類型為 double 的包含 10 個元素的數(shù)組?balance,聲明語句如下:
double balance[10];
初始化數(shù)組
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}
}
大括號 { } 之間的值的數(shù)目不能大于我們在數(shù)組聲明時在方括號 [ ] 中指定的元素數(shù)目。
如果您省略掉了數(shù)組的大小,數(shù)組的大小則為初始化時元素的個數(shù)。因此,如果:
void main(){
? double balance[] = {1.1,1.2,1.3,1.4,1.5,1.6,1.7,1.8,1.9,2.0}
}
您將創(chuàng)建一個數(shù)組,它與前一個實例中所創(chuàng)建的數(shù)組是完全相同的。下面是一個為數(shù)組中某個元素賦值的實例:
balance[1] = 50.5;

訪問數(shù)組元素
//跟 Java 一樣
double value = balance[1]
例子:
void main() {
? ? //定義一個長度為 10 的整數(shù)數(shù)組
? ? int n[10];
? ? int i, j;
? ? //初始化數(shù)組元素
? ? for (i = 0; i < 10; i++) {
? ? ? ? n[i] = 2 * i;
? ? }
? ? //輸出元素中的數(shù)據(jù)
? ? for (int k = 0; k < 10; ++k) {
? ? ? ? printf("Element[%d] = %d \n", k, n[k]);
? ? }
? ? //總的大小除以其中一個大小就得到了 數(shù)組長度
? ? printf("整數(shù)數(shù)組 n 的長度: %d \n", sizeof(n) / sizeof(n[0]));
? ? //輸出元素中的數(shù)據(jù)
? ? 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
整數(shù)數(shù)組 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 中數(shù)組詳解
在 C 中,數(shù)組是非常重要的,我們需要了解更多有關(guān)數(shù)組的細(xì)節(jié)。下面列出了 C 程序員必須清楚的一些與數(shù)組相關(guān)的重要概念:

13. 枚舉
枚舉是 C 語言中的一種基本數(shù)據(jù)類型,它可以讓數(shù)據(jù)更簡潔,更易讀。
枚舉語法定義格式為:
enum 枚舉名 {枚舉元素1,枚舉元素2,……};
接下來我們舉個例子,比如:一星期有 7 天,如果不用枚舉,我們需要使用 #define 來為每個整數(shù)定義一個別名:
#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
};
這樣看起來是不是更簡潔了。
**注意:**第一個枚舉成員的默認(rèn)值為整型的 0,后續(xù)枚舉成員的值在前一個成員上加 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. 指針
學(xué)習(xí) C 語言的指針既簡單又有趣。通過指針,可以簡化一些 C 編程任務(wù)的執(zhí)行,還有一些任務(wù),如動態(tài)內(nèi)存分配,沒有指針是無法執(zhí)行的。所以,想要成為一名優(yōu)秀的 C 程序員,學(xué)習(xí)指針是很有必要的。
正如您所知道的,每一個變量都有一個內(nèi)存位置,每一個內(nèi)存位置都定義了可使用連字號(&)運算符訪問的地址,它表示了在內(nèi)存中的一個地址。請看下面的實例,它將輸出定義的變量地址:
void main(){
? ? int var1;
? ? char var2[10];
? ? //%p : 輸出指針地址
? ? printf("var1 變量的地址:%p \n", &var1);
? ? printf("var2 變量的地址:%p \n", &var2);
}
輸出:
var1 變量的地址:0x7ffee7e976b8
var2 變量的地址:0x7ffee7e976be
通過上面的實例,我們了解了什么是內(nèi)存地址以及如何訪問它。接下來讓我們看看什么是指針。
什么是指針?
指針是一個變量,其值為另一個變量的地址,即內(nèi)存位置的直接地址。就像其他變量或常量一樣,您必須在使用指針存儲其他變量地址之前,對其進(jìn)行聲明。指針變量聲明的一般形式為:
type *var-name
在這里,type?是指針的基類型,它必須是一個有效的 C 數(shù)據(jù)類型,var-name?是指針變量的名稱。用來聲明指針的星號 * 與乘法中使用的星號是相同的。但是,在這個語句中,星號是用來指定一個變量是指針。以下是有效的指針聲明:
int *i; //一個整型的指針
double *d;//double 型指針
float *f;//浮點型指針
char *ch//字符型指針
所有實際數(shù)據(jù)類型,不管是整型、浮點型、字符型,還是其他的數(shù)據(jù)類型,對應(yīng)指針的值的類型都是一樣的,都是一個代表內(nèi)存地址的長的十六進(jìn)制數(shù)。
不同數(shù)據(jù)類型的指針之間唯一的不同是,指針?biāo)赶虻淖兞炕虺A康臄?shù)據(jù)類型不同。
如何使用指針?
使用指針時會頻繁進(jìn)行以下幾個操作:定義一個指針變量、把變量地址賦值給指針、訪問指針變量中可用地址的值。這些是通過使用一元運算符 ***** 來返回位于操作數(shù)所指定地址的變量的值。下面的實例涉及到了這些操作:
例子:
//如何使用指針
? ? int var = 66;//實際變量的聲明
? ? int *ip;//指針變量的聲明
? ? ip = &var; //指針變量中存儲 var 的地址
? ? printf("var 的地址 : %p? \n", var);
? ? //在指針變量中存儲的地址
? ? printf("ip 的地址:%p? \n", ip);
? ? //使用指針訪問地址
? ? printf("ip 指針對應(yīng)的地址:%p \n", *ip);
? ? //使用指針訪問地址對應(yīng)的值
? ? printf("ip 指針對應(yīng)的地址:%d \n", *ip);
輸出:
var 的地址 : 0x42
ip 的地址:0x7ffee96eb6b4?
ip 指針對應(yīng)的地址:0x42
ip 指針對應(yīng)的地址:66
C 中的 NULL 指針
在變量聲明的時候,如果沒有確切的地址可以賦值,為指針變量賦一個 NULL 值是一個良好的編程習(xí)慣。賦為 NULL 值的指針被稱為空指針。
NULL 指針是一個定義在標(biāo)準(zhǔn)庫中的值為零的常量。請看下面的程序:
void main(){
? ? //賦值一個 NULL 指針
? ? int *ptr = NULL;
? ? printf("ptr 的地址是: %p \n", ptr);
? ? //檢查一個空指針
? ? if (ptr) printf("如果 ptr 不是空指針,則執(zhí)行"); else printf("如果 ptr 是空指針,則執(zhí)行");
}
輸出:ptr 的地址是: 0x0 ptr 是空指針
C 指針詳解
在 C 中,有很多指針相關(guān)的概念,這些概念都很簡單,但是都很重要。下面列出了 C 程序員必須清楚的一些與指針相關(guān)的重要概念:

15. 函數(shù)指針與回調(diào)函數(shù)
函數(shù)指針是指向函數(shù)的指針變量。
通常我們說的指針變量是指向一個整型、字符型或數(shù)組等變量,而函數(shù)指針是指向函數(shù)。
函數(shù)指針可以像一般函數(shù)一樣,用于調(diào)用函數(shù)、傳遞參數(shù)。
函數(shù)指針變量的聲明:
typedef int (*fun_ptr)(int,int)//聲明一個指向同樣參數(shù),返回值得函數(shù)指針類型
回調(diào)函數(shù)
函數(shù)指針變量可以作為某個函數(shù)的參數(shù)來使用的,回調(diào)函數(shù)就是一個通過函數(shù)指針調(diào)用的函數(shù)。
簡單講:回調(diào)函數(shù)是由別人的函數(shù)執(zhí)行時調(diào)用你實現(xiàn)的函數(shù)。
例子:
例子中 populate_array 函數(shù)定義了三個參數(shù),其中第三個參數(shù)是函數(shù)的指針,通過該函數(shù)來設(shè)置數(shù)組的值。
實例中我們定義了回調(diào)函數(shù) getNextRandomValue,它返回一個隨機(jī)值,它作為一個函數(shù)指針傳遞給 populate_array 函數(shù)。
populate_array 將調(diào)用 10 次回調(diào)函數(shù),并將回調(diào)函數(shù)的返回值賦值給數(shù)組。
#include <stdlib.h>
#include <stdio.h>
//回調(diào)函數(shù)
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]);
? ? }
}
//獲取一個隨機(jī)數(shù)
int getNextRandomValue(void) {
? ? return rand();
}
void main() {
? ? //回調(diào)函數(shù)
? ? 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] , 對應(yīng)值為:%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] , 對應(yīng)值為:16807
array[1] , 對應(yīng)值為:282475249
array[2] , 對應(yīng)值為:1622650073
array[3] , 對應(yīng)值為:984943658
array[4] , 對應(yīng)值為:1144108930
array[5] , 對應(yīng)值為:470211272
array[6] , 對應(yīng)值為:101027544
array[7] , 對應(yīng)值為:1457850878
array[8] , 對應(yīng)值為:1458777923
array[9] , 對應(yīng)值為:2007237709
16. 字符串
在 C 語言中,字符串實際上是使用null字符 '\0' 終止的一維字符數(shù)組。因此,一個以 null 結(jié)尾的字符串,包含了組成字符串的字符。
下面的聲明和初始化創(chuàng)建了一個 "Hello" 字符串。由于在數(shù)組的末尾存儲了空字符,所以字符數(shù)組的大小比單詞 "Hello" 的字符數(shù)多一個。
char ch[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
也可以使用以下簡寫模式:
char ch[6] = "Hello"
字符串在 C/C++ 中內(nèi)存表示:

其實,您不需要把?null?字符放在字符串常量的末尾。C 編譯器會在初始化數(shù)組時,自動把 '\0' 放在字符串的末尾。讓我們嘗試輸出上面的字符串:
void main(){
? ? ? //定義一個 char 數(shù)組
? ? 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. 結(jié)構(gòu)體
C 數(shù)組允許定義可存儲相同類型數(shù)據(jù)項的變量,結(jié)構(gòu)是 C 編程中另一種用戶自定義的可用的數(shù)據(jù)類型,它允許您存儲不同類型的數(shù)據(jù)項。
結(jié)構(gòu)用于表示一條記錄,假設(shè)您想要跟蹤圖書館中書本的動態(tài),您可能需要跟蹤每本書的下列屬性:
(1)Title
(2)Author
(3)Subject
(4)Book ID
定義結(jié)構(gòu)
為了定義結(jié)構(gòu),您必須使用struct語句。struct 語句定義了一個包含多個成員的新的數(shù)據(jù)類型,struct 語句的格式如下:
struct name{
? member-list;
? member-list;
? ...
}name_tag,
name是結(jié)構(gòu)的標(biāo)簽。
member-list是標(biāo)準(zhǔn)的變量定義,比如 int i;或者 float f,或者其它有效的變量定義。
name_tag結(jié)構(gòu)變量,定義在結(jié)構(gòu)的末尾,最后一個分號之前,你可以指定一個或多個結(jié)構(gòu)變量,下面是聲明 Book 的結(jié)構(gòu)方式:
struct Books{
? char title[50];
? char author[50];
? char subject[100];
? int book_id;
} book;
注意:在定義結(jié)構(gòu)體的時候name、member-list、name_tag?這 3 部分至少要出現(xiàn) 2 個。
結(jié)構(gòu)體變量的初始化
和其它類型變量一樣,在初始化的時候可以指定初始值。
//定義一個 Books 結(jié)構(gòu),類似于 Java 中的數(shù)據(jù) 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
訪問結(jié)構(gòu)成員
struct Books2 {
? ? char title[50];
? ? char author[50];
? ? char subject[100];
? ? int book_id;
};
void main(){
? ? ? //訪問 Books2 結(jié)構(gòu)成員
? ? 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
結(jié)構(gòu)作為函數(shù)參數(shù)
//函數(shù)聲明
void printBook(struct Books2 books2);
void main(){
? ? ? //訪問 Books2 結(jié)構(gòu)成員
? ? 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");
? ? //結(jié)構(gòu)作為函數(shù)參數(shù)
? ? 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
指向結(jié)構(gòu)的指針
您可以定義指向結(jié)構(gòu)的指針,方式與定義指向其他類型變量的指針相似,如下所示:
struct Books *struct_pointer;
現(xiàn)在,您可以在上述定義的指針變量中存儲結(jié)構(gòu)變量的地址。為了查找結(jié)構(gòu)變量的地址,請把 & 運算符放在結(jié)構(gòu)名稱的前面,如下所示:
struct_pointer = &Book1;
為了使用指向該結(jié)構(gòu)的指針訪問結(jié)構(gòu)的成員,您必須使用 -> 運算符,如下所示:
struct_pointer->title;
例子:
//定義指向結(jié)構(gòu)的指針
void printBookZZ(struct Books2 *books2);
void main(){
? ? ? //訪問 Books2 結(jié)構(gòu)成員
? ? 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;
? ? //通過內(nèi)存地址傳遞信息,為了查找結(jié)構(gòu)變量的地址,請把 & 運算符放在結(jié)構(gòu)名稱的前面
? ? printBookZZ(&Books2A);
? ? printBookZZ(&Books2B);
}
/**
* 為了使用指向該結(jié)構(gòu)的指針訪問結(jié)構(gòu)的成員,您必須使用 -> 運算符,如下所示:
* @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);
}
位域
有些信息在存儲時,并不需要占用一個完整的字節(jié),而只需占幾個或一個二進(jìn)制位。例如在存放一個開關(guān)量時,只有 0 和 1 兩種狀態(tài),用 1 位二進(jìn)位即可。為了節(jié)省存儲空間,并使處理簡便,C 語言又提供了一種數(shù)據(jù)結(jié)構(gòu),稱為"位域"或"位段"。
所謂"位域"是把一個字節(jié)中的二進(jìn)位劃分為幾個不同的區(qū)域,并說明每個區(qū)域的位數(shù)。每個域有一個域名,允許在程序中按域名進(jìn)行操作。這樣就可以把幾個不同的對象用一個字節(jié)的二進(jìn)制位域來表示。
典型的實例:
(1)用 1 位二進(jìn)位存放一個開關(guān)量時,只有 0 和 1 兩種狀態(tài)。
(2)讀取外部文件格式——可以讀取非標(biāo)準(zhǔn)的文件格式。
位域ed 定義:
struct 位域結(jié)構(gòu)名稱{
? 位域列表
};
位域列表的形式為:類型說明符 位域名:位域長度
例:
struct bean {
? int a:8;
? int b:4;
? int c:4;
}data;
說明 data 為 bean 變量,共占 2個字節(jié)。其中位域 a 占 8 位,位域 b 占 4 位,位域 c 占 4 位。
注意:
一個位域存儲在同一個字節(jié)中,如一個字節(jié)所剩空間不夠存放另一位域時,則會從下一單元起存放該位域。也可以有意使某位域從下一單元開始。例如:
struct bean{
? unsigned a:4;
? unsigned? :4;//空域
? unsigned b:4;//從下一個單元開始存放
? unsigned c:4;
}
在這個位域定義中共占用 2 個字節(jié),a 占第一字節(jié)的 4 位,后 4 位填 0 表示不使用,b 從第二字節(jié)開始,占用 4 位,c 占用 4 位。
由于位域不允許跨兩個字節(jié),因此位域的長度不能大于一個字節(jié)的長度,也就是說不能超過8位二進(jìn)位。如果最大長度大于計算機(jī)的整數(shù)字長,一些編譯器可能會允許域的內(nèi)存重疊,另外一些編譯器可能會把大于一個域的部分存儲在下一個字中。
位域可以是無名位域,這時它只用來作填充或調(diào)整位置。無名的位域是不能使用的。例如:
struct k{
int a:1;
int? :2;? ? /* 該 2 位不能使用 */
int b:3;
int c:2;
};
從以上分析可以看出,位域在本質(zhì)上就是一種結(jié)構(gòu)類型,不過其成員是按二進(jìn)位分配的。
位域的使用
位域的使用和結(jié)構(gòu)成員的使用相同,其一般形式為:
(1)位域變量名.位域名
(2)位域變量名->位域名
位域允許用各種格式輸出。
18. 共用體
共用體是一種特殊的數(shù)據(jù)類型,允許您在相同的內(nèi)存位置存儲不同的數(shù)據(jù)類型。您可以定義一個帶有多成員的共用體,但是任何時候只能有一個成員帶有值。共用體提供了一種使用相同的內(nèi)存位置的有效方式。
定義共同體
為了定義共用體,您必須使用union語句,方式與定義結(jié)構(gòu)類似。union 語句定義了一個新的數(shù)據(jù)類型,帶有多個成員。union 語句的格式如下:
union [union tag]
{
member definition;
member definition;
...
member definition;
}[one or more union variables];
union tag是可選的,每個 member definition 是標(biāo)準(zhǔn)的變量定義,比如 int i; 或者 float f; 或者其他有效的變量定義。在共用體定義的末尾,最后一個分號之前,您可以指定一個或多個共用體變量,這是可選的。下面定義一個名為 Data 的共用體類型,有三個成員 i、f 和 str:
union Data
{
int i;
float f;
char str[20];
}
現(xiàn)在,Data類型的變量可以存儲一個整數(shù)、一個浮點數(shù),或者一個字符串。這意味著一個變量(相同的內(nèi)存位置)可以存儲多個多種類型的數(shù)據(jù)。您可以根據(jù)需要在一個共用體內(nèi)使用任何內(nèi)置的或者用戶自定義的數(shù)據(jù)類型。
共用體占用的內(nèi)存應(yīng)足夠存儲共用體中最大的成員。例如,在上面的實例中,Data 將占用 20 個字節(jié)的內(nèi)存空間,因為在各個成員中,字符串所占用的空間是最大的。下面的實例將顯示上面的共用體占用的總內(nèi)存大小:
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?關(guān)鍵字來定義共用體類型的變量。下面的實例演示了共用體的用法:
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?成員的值有損壞,因為最后賦給變量的值占用了內(nèi)存位置,這也是?str?成員能夠完好輸出的原因。我們看注釋 2 ,這次我們在同一時間只使用一個變量成員,所以都能完好輸出。
19. 位域
參考 17.(位域的介紹)
20. typedef
C 語言提供了?typedef?關(guān)鍵字,您可以使用它來為類型取一個新的名字。下面的實例為單字節(jié)數(shù)字定義了一個術(shù)語?BYTE:
typedef unsigned char BYTE;
在這個類型定義之后,標(biāo)識符 BYTE 可作為類型?unsigned char?的縮寫,例如:
BYTE b1, b2;
按照慣例,定義時會大寫字母,以便提醒用戶類型名稱是一個象征性的縮寫,但您也可以使用小寫字母,如下:
typedef unsigned char byte;
您也可以使用?typedef?來為用戶自定義的數(shù)據(jù)類型取一個新的名字。例如,您可以對結(jié)構(gòu)體使用 typedef 來定義一個新的數(shù)據(jù)類型名字,然后使用這個新的數(shù)據(jù)類型來直接定義結(jié)構(gòu)變量,如下:
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( "書標(biāo)題 : %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);
}
輸出:
書標(biāo)題 : C 教程
書作者 : Runoob
書類目 : 編程語言
書 ID : 12345
TRUE 的值: 1
FALSE 的值: 0
typedef vs define
define是 C 指令,用于為各種數(shù)據(jù)類型定義別名,與typedef類似,但是它們有以下幾點不同:
(1)typedef僅限于為類型定義符號名稱,#define不僅可以為類型定義別名,也能為數(shù)值定義別名,比如您可以定義 1 為 ONE。
(2)typedef是由編譯器執(zhí)行解釋的,#define語句是由預(yù)編譯器進(jìn)行處理的。
例子可以參考上面是 #define? 使用。
本節(jié)知識將會以分節(jié)的形式向大家展示,又想要學(xué)習(xí)C語言的小伙伴可以關(guān)注筆者!一起來加油呀~

學(xué)習(xí)C/C++編程知識,提升C/C++編程能力,歡迎關(guān)注UP一起來成長!
另外,UP在主頁上傳了一些學(xué)習(xí)C/C++編程的視頻教程,有興趣或者正在學(xué)習(xí)的小伙伴一定要去看一看哦!會對你有幫助的~