1. 程式人生 > 實用技巧 >06.複合資料型別

06.複合資料型別

06.複合資料型別

字元

字元型別、字元文字與量

定義格式:char ch; const char cch = 'C';

字元文字使用單引號對

實際儲存時字元型別量儲存字元的對應ASCII值

可使用signed與unsigned修飾字符型別

單字元用8個位元組儲存,表達範圍-128127,用unsigned修飾的話範圍為0255

字元表示的等價性

char a = 'A';
char a = 65;    //ASCII值
char a = 0101;	//八進位制
char a = 0x41;	//十六進位制

ASCII碼錶

控制字元、通訊專用字元、可列印字元

回車與換行

Windows: \n\r

Linux:\n

Mac: \r

ASCII使用示例:

判斷某個字元是否為數字

bool isDigit(char c)
{
    if(c >= '0' && c <= '9')  //等價於if(c >= 48 && c <= 57)
        return true;
    else
        return false;
}

將字元轉換為大寫字元

char ToUpperCase(char c)
{
    if(c >= 'a' && c <= 'z')
        return c - 'a' + 'A';  //等價於return c + 32;
    else
        return c;
}

C標準字元特徵庫:ctype.h/cctype,標準字元特徵庫常用函式:bool isalnum(char c);bool isalpha(char c);bool isdigit(char c);bool islower(char c);bool isspace(char c);bool isupper(char c);char tolower(char c);char toupper(char c);

陣列

陣列的意義與性質

陣列的定義

定義格式:元素型別 陣列名稱[常數表示式];

示例:int a[8]; //定義包含8個整數元素的陣列

特別說明

常數表示式必須是常數和常量,不允許為變數

錯誤示例:

int count = 8; int c[count];

陣列元素編號從0開始計數,元素訪問格式為a[0],a[1],a[2]...

不允許對陣列進行整體賦值操作,只能使用迴圈逐一賦值元素

錯誤示例:int a[8], b[8]; a = b;

意義與性質

將相同性質的資料元素組織成整體,構成單一維度上的資料序列

陣列的儲存表示

陣列元素一次連續存放,中間沒有空閒空間

陣列的地址

陣列的基地址:陣列開始儲存的物理位置

陣列首元素的基地址:陣列首個元素開始儲存的實體地址,數值上總是與陣列基地址相同

“&”操作符:&a獲得陣列的基地址;&a[0]獲得陣列首元素的基地址

設陣列基地址為p,並設每個元素的儲存空間為m,則第i個元素的基地址為p+mi

陣列元素的初始化

基本初始化格式

定義格式:元素型別 陣列名稱[元素個數] = {值1, 值2, 值3, ……};

示例:int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};

初始化時忽略元素個數表示式

在全部元素均初始化時可以不寫元素個數,使用sizeof操作符可以獲得元素個數

示例:int a[] = {1, 2, 3, 4, 5, 6, 7, 8}; int num_of_elements = sizeof (a) / sizeof (a[0]);

sizeof獲取陣列儲存空間大小(以位元組為單位),sizeof(a[0])獲取陣列首元素的儲存空間大小。

陣列元素的訪問

陣列與函式

陣列元素作為函式實際引數

int Add(int x, int y) {return (x + y);}
int a[2] = {1, 2}, sum;
sum = Add(a[0], a[1]);

陣列整體作為函式形式引數

陣列整體作為函式形式引數

基本格式:返回值型別 函式名稱 (元素型別 陣列名稱怕[], 元素個數型別 元素個數)

示例:void GenerateIntegers(int a[], unsigned int n);

特別說明:作為函式形式引數時,陣列名稱後的中括號內不需列寫元素個數,必須使用單獨的引數傳遞元素個數資訊

陣列作為函式引數時有個巨大的優勢,是能夠將函式內部對陣列元素的修改帶出函式以外,能對陣列產生實際改變。即陣列作為函式引數時既是輸入的一部分也是輸出的一部分。

示例:

隨機產生n個介於[lower,upper]之間的整數並儲存在陣列中

void GenerateIntegers(int a[],unsigned int n, int lower, int upper)
{
    unsigned int i;
    for(i = 0;i < n;i++)
        a[i] = GenerateRandomNumber(lower,upper);
}

上述程式碼中,對a[]陣列的實際操作真正反映到了a[]中。同時需注意,C++中陣列宣告時陣列元素個數必須為常數或常量(C中只能為常數),所以需額外傳一個引數n表示陣列元素個數,而不能將元素個數寫死或直接宣告a[n]。

上述問題的完整描述:使用單獨陣列名稱作為函式實際引數,傳遞陣列基地址而不是陣列元素值;形式引數與實際引數使用相同儲存區,對陣列形式引數值的改變會自動反應到實際引數中

多維陣列

多維陣列的定義

定義格式:元素型別 陣列名稱[常數表示式1] [常數表示式2] ...;

示例一:int a[2][2]; //2*2的整型二維陣列

示例二:int b[2] [3] [4] ; //2*3*4的整型三維陣列

多維陣列的初始化

與一維陣列類似:int a[2][3] = {1, 2, 3, 4, 5, 6};

單獨初始化每一維:int a[2][3] = {{1, 2, 3}, { 4, 5, 6} };

多維陣列的儲存佈局

同一維陣列,先行後列儲存。

結構體

結構體的意義與性質

結構體的意義

與陣列的最大差別:不同型別資料物件構成的集合

當然也可以為相同型別的但具體意義或解釋不同的資料物件集合

結構體型別的定義:注意型別定義後面的分號

struct 結構體名稱
{
    成員型別1 成員名稱1;
    成員型別2 成員名稱2;
    ......
    成員型別3 成員名稱3;
};

示例

日期結構體

struct DATE
{
    int year;
    int month;
    int day;
};

複數結構體

struct COMPLEX
{
    double real;
    double imag;
};

結構體型別的宣告

僅僅引入結構體型別的名稱,而沒有給出具體定義,其具體定義在其他標頭檔案中或本檔案後續位置

如何表示學生資訊?

成員:整數型別的學號id、字串型別的姓名name、性別(單獨定義列舉型別)gender、年齡age、字串型別的地址addr

enum GENDER{FEMALE,MALE};
struct STUDENT
{
    int id;
    STRING name;   //假設已有字串型別的定義
    GENDER gender;
    int age;
    STRING addr;
};

結構體的儲存表示

按照成員定義順序存放

各成員的儲存空間一般連續

特殊情況

因為不同硬體和編譯器的原因,不同型別的成員可能會按照字(兩個位元組)或雙字(四個位元組)對齊後存放

使用sizeof獲得結構體型別量佔用空間大小(以位元組為單位),下述兩種方式均可:sizeof date; sizeof(date);

結構體資料物件的訪問

結構體型別的變數與常量:按普通量格式定義

示例一:DATE date;

示例二:STUDENT zhang_san;

示例三:STUDENT students[8];

結構體量的初始化

示例四:DATE date = {2008, 8, 8};

結構體量的賦值

與陣列不同,結構體量可直接賦值,拷貝過程為逐成員一一複製

示例五:DATE new_date; new_date = date;

結構體成員的訪問

使用點號操作符(成員選擇操作符)“."解析結構體量的某個特定成員

示例一:DATE date; date.year = 2008; date.month = 8; date.day = 8;

巢狀結構體成員的訪問

可以連續使用點號逐層解析

示例二:

struct FRIEND{int id; STRING name; DATE birthday;};
FRIEND friend;
friend.birthday.year = 1988;

複雜結構體成員的訪問

FRIEND friends[4];
friends[0].birthday.year = 1988;

結構體與函式

編寫一函式,使用結構體型別儲存日期,並返回該日在該年的第幾天資訊,具體天數從1開始計數,例如2016年1月20日返回20,2月1日返回32

unsigned int GetDateCount(DATE date)
{
    static unsigned int days_of_months[13]=
    {0,31,28,31,30,31,31,31,31,30,31,30,31};
    unsigned int i, date_id = 0;
    for(i = 1;i < date.month;i++)
        date_id += days_of_months[i];
    date_id += date.day;
    if(date,month > 2 && IsLeap(date.year))
        date_id++;
    return date_id;
}