struct結構體是C語言中非常重要的複合類型,初始化的方法很多,下面對這些方法進行總結,便于以後查閱。
一、gcc擴充方式(不知道該如何命名)
[cpp] view plain copy
- #include <stdio.h>
- struct mych {
- int k;
- };
- struct myst {
- int i;
- int j;
- struct mych ch;
- };
- int main(void)
- {
- struct myst st = {
- .i = 1,
- .j = 2,
- .ch = {
- .k = 3
- }
- };
- printf("st.i = %d, st.j = %d, st.ch.k = %d\n", st.i, st.j, st.ch.k);
- return 0;
- }
這種方式是在成員前面加上“."來初始化,這種方式比較直覺,但是屬于gcc擴充,可移植性較差。但是如果是完全面向Linux的開發,這種方式還是比較好的。這是在linux核心中發現的,具體可以參考Linux核心中/net/ipv4目錄中的arp.c檔案
二、使用{}進行初始化
[cpp] view plain copy
- struct myst st = { 1 ,2, {4}};
這種方式輸入C标準的用法,可移植性好,但是結構體類型複雜時,可讀性很差
三、使用庫函數
常用的函數有兩個:memset和bzero。用法如下:
[cpp] view plain copy
- memset(&st, 0, sizeof (st));
- bzero(&set, sizeof (st));
memset和bzero的主要差別是:參數個數不同;memset 需要三個參數,其中第二個參數是&st指向的記憶體中要初始化的值,而bzero使用0來初始化
typedef總結及用法:
不管實在C還是C++代碼中,typedef這個詞都不少見,當然出現頻率較高的還是在C代碼中。typedef與#define有些相似,但更多的是不同,特别是在一些複雜的用法上,就完全不同了,看了網上一些C/C++的學習者的部落格,其中有一篇關于typedef的總結還是很不錯,由于總結的很好,我就不加修改的引用過來了,以下是引用的内容(紅色部分是我自己寫的内容)。
用途一:
定義一種類型的别名,而不隻是簡單的宏替換。可以用作同時聲明指針型的多個對象。比如:
char* pa, pb; // 這多數不符合我們的意圖,它隻聲明了一個指向字元變量的指針,
// 和一個字元變量;
以下則可行:
typedef char* PCHAR;
PCHAR pa, pb;
這種用法很有用,特别是char* pa, pb的定義,初學者往往認為是定義了兩個字元型指針,其實不是,而用typedef char* PCHAR就不會出現這樣的問題,減少了錯誤的發生。
用途二:
用在舊的C代碼中,幫助struct。以前的代碼中,聲明struct新對象時,必須要帶上struct,即形式為: struct 結構名對象名,如:
struct tagPOINT1
{
int x;
int y;
};
struct tagPOINT1 p1;
而在C++中,則可以直接寫:結構名對象名,即:tagPOINT1 p1;
typedef struct tagPOINT
{
int x;
int y;
}POINT;
POINT p1; // 這樣就比原來的方式少寫了一個struct,比較省事,尤其在大量使用的時
候,或許,在C++中,typedef的這種用途二不是很大,但是了解了它,對掌握以前的舊代
碼還是有幫助的,畢竟我們在項目中有可能會遇到較早些年代遺留下來的代碼。
用途三:
用typedef來定義與平台無關的類型。
比如定義一個叫 REAL 的浮點類型,在目标平台一上,讓它表示最高精度的類型為:
typedef long double REAL;
在不支援 long double 的平台二上,改為:
typedef double REAL;
在連 double 都不支援的平台三上,改為:
typedef float REAL;
也就是說,當跨平台時,隻要改下 typedef 本身就行,不用對其他源碼做任何修改。
标準庫就廣泛使用了這個技巧,比如size_t。另外,因為typedef是定義了一種類型的新别名,不是簡單的字元串替換,是以它比宏來得穩健。
這個優點在我們寫代碼的過程中可以減少不少代碼量哦!
用途四:
為複雜的聲明定義一個新的簡單的别名。方法是:在原來的聲明裡逐漸用别名替換一部
分複雜聲明,如此循環,把帶變量名的部分留到最後替換,得到的就是原聲明的最簡化
版。舉例:
原聲明:void (*b[10]) (void (*)());
變量名為b,先替換右邊部分括号裡的,pFunParam為别名一:
typedef void (*pFunParam)();
再替換左邊的變量b,pFunx為别名二:
typedef void (*pFunx)(pFunParam);
原聲明的最簡化版:
pFunx b[10];
原聲明:doube(*)() (*e)[9];
變量名為e,先替換左邊部分,pFuny為别名一:
typedef double(*pFuny)();
再替換右邊的變量e,pFunParamy為别名二
typedef pFuny (*pFunParamy)[9];
原聲明的最簡化版:
pFunParamy e;
了解複雜聲明可用的“右左法則”:從變量名看起,先往右,再往左,碰到一個圓括号
就調轉閱讀的方向;括号内分析完就跳出括号,還是按先右後左的順序,如此循環,直
到整個聲明分析完。舉例:
int (*func)(int *p);
首先找到變量名func,外面有一對圓括号,而且左邊是一個*号,這說明func是一個指針
;然後跳出這個圓括号,先看右邊,又遇到圓括号,這說明(*func)是一個函數,是以
func是一個指向這類函數的指針,即函數指針,這類函數具有int*類型的形參,傳回值
類型是int。
int (*func[5])(int *);
func右邊是一個[]運算符,說明func是具有5個元素的數組;func的左邊有一個*,說明
func的元素是指針(注意這裡的*不是修飾func,而是修飾func[5]的,原因是[]運算符
優先級比*高,func先跟[]結合)。跳出這個括号,看右邊,又遇到圓括号,說明func數
組的元素是函數類型的指針,它指向的函數具有int*類型的形參,傳回值類型為int。
這種用法是比較複雜的,出現的頻率也不少,往往在看到這樣的用法卻不能了解,相信以上的解釋能有所幫助。
*****以上為參考部分,以下為本人領悟部分*****
使用示例:
1.比較一:
#include <iostream>
using namespace std;
typedef int (*A) (char, char);
int ss(char a, char b)
{
cout<<"功能1"<<endl;
cout<<a<<endl;
cout<<b<<endl;
return 0;
}
int bb(char a, char b)
{
cout<<"功能2"<<endl;
cout<<b<<endl;
cout<<a<<endl;
return 0;
}
void main()
{
A a;
a = ss;
a('a','b');
a = bb;
a('a', 'b');
}
2.比較二:
typedef int (A) (char, char);
void main()
{
A *a;
a = ss;
a('a','b');
a = bb;
a('a','b');
}
兩個程式的結果都一樣:
功能1
a
b
功能2
b
a
*****以下是參考部分*****
參考自:http://blog.hc360.com/portal/personShowArticle.do?articleId=57527
typedef 與 #define的差別:
案例一:
通常講,typedef要比#define要好,特别是在有指針的場合。請看例子:
typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;
在上述的變量定義中,s1、s2、s3都被定義為char *,而s4則定義成了char,不是我們
所預期的指針變量,根本原因就在于#define隻是簡單的字元串替換而typedef則是為一
個類型起新名字。
案例二:
下面的代碼中編譯器會報一個錯誤,你知道是哪個語句錯了嗎?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;
是p2++出錯了。這個問題再一次提醒我們:typedef和#define不同,它不是簡單的
文本替換。上述代碼中const pStr p2并不等于const char * p2。const pStr p2和
const long x本質上沒有差別,都是對變量進行隻讀限制,隻不過此處變量p2的資料類
型是我們自己定義的而不是系統固有類型而已。是以,const pStr p2的含義是:限定數
據類型為char *的變量p2為隻讀,是以p2++錯誤。雖然作者在這裡已經解釋得很清楚了,可我在這個地方仍然還是糊塗的,真的希望哪位高手能幫忙指點一下,特别是這一句“隻不過此處變量p2的資料類型是我們自己定義的而不是系統固有類型而已”,難道自己定義的類型前面用const修飾後,就不能執行更改運算,而系統定義的類型卻可以?
分析:const char *p1 = string; 你可以這樣了解:(const char) *p1 = string, p1是一個指針,指向const char的東西,這個東西就是string(string是一個字元數組的首位址,它的位址聲明後肯定是const的,除非該數組銷毀),但是p1是一個指針變量,它是可以遞增的,即你看到的p1++,它可以完成從數組的來周遊數組的目的。
而const pStr p2 = string;是這樣的:由于p2不是指針,const直接修飾到了p2,即現在的p2是常量了,它的類型是pStr(我們自己定義的類型),相當于const int p2, const long p2等等,const都是直接修飾p2的,隻不過int,long是系統類型,而pStr是我們定義的類型。為什麼會出現這種效果了,就是因為typedef,它把char *定義成一個複合的類型,要從整體上來了解語義,而不是字元替換後來了解語義。
1. 基本解釋
typedef為C語言的關鍵字,作用是為一種資料類型定義一個新名字。這裡的資料類型包括内部資料類型(int,char等)和自定義的資料類型(struct等)。
在程式設計中使用typedef目的一般有兩個,一個是給變量一個易記且意義明确的新名字,另一個是簡化一些比較複雜的類型聲明。
至于typedef有什麼微妙之處,請你接着看下面對幾個問題的具體闡述。
2. typedef & 結構的問題
當用下面的代碼定義一個結構時,編譯器報了一個錯誤,為什麼呢?莫非C語言不允許在結構中包含指向它自己的指針嗎?請你先猜想一下,然後看下文說明:
typedef struct tagNode
{
char *pItem;
pNode pNext;
} *pNode;
答案與分析:
1、typedef的最簡單使用
typedef long byte_4;
給已知資料類型long起個新名字,叫byte_4。
2、 typedef與結構結合使用
typedef struct tagMyStruct
{
int iNum;
long lLength;
} MyStruct;
這語句實際上完成兩個操作:
1) 定義一個新的結構類型
struct tagMyStruct
{
int iNum;
long lLength;
};
分析:tagMyStruct稱為“tag”,即“标簽”,實際上是一個臨時名字,struct 關鍵字和tagMyStruct一起,構成了這個結構類型,不論是否有typedef,這個結構都存在。
我們可以用struct tagMyStruct varName來定義變量,但要注意,使用tagMyStruct varName來定義變量是不對的,因為struct 和tagMyStruct合在一起才能表示一個結構類型。
2) typedef為這個新的結構起了一個名字,叫MyStruct。
typedef struct tagMyStruct MyStruct;
是以,MyStruct實際上相當于struct tagMyStruct,我們可以使用MyStruct varName來定義變量。
答案與分析
C語言當然允許在結構中包含指向它自己的指針,我們可以在建立連結清單等資料結構的實作上看到無數這樣的例子,上述代碼的根本問題在于typedef的應用。
根據我們上面的闡述可以知道:新結建構立的過程中遇到了pNext域的聲明,類型是pNode,要知道pNode表示的是類型的新名字,那麼在類型本身還沒有建立完成的時候,這個類型的新名字也還不存在,也就是說這個時候編譯器根本不認識pNode。
解決這個問題的方法有多種:
1)、
typedef struct tagNode
{
char *pItem;
struct tagNode *pNext;
} *pNode;
2)、
typedef struct tagNode *pNode;
struct tagNode
{
char *pItem;
pNode pNext;
};
注意:在這個例子中,你用typedef給一個還未完全聲明的類型起新名字。C語言編譯器支援這種做法。
3)、規範做法:
struct tagNode
{
char *pItem;
struct tagNode *pNext;
};
typedef struct tagNode *pNode;
3. typedef & #define的問題
有下面兩種定義pStr資料類型的方法,兩者有什麼不同?哪一種更好一點?
typedef char *pStr;
#define pStr char *;
答案與分析:
通常講,typedef要比#define要好,特别是在有指針的場合。請看例子:
typedef char *pStr1;
#define pStr2 char *;
pStr1 s1, s2;
pStr2 s3, s4;
在上述的變量定義中,s1、s2、s3都被定義為char *,而s4則定義成了char,不是我們所預期的指針變量,根本原因就在于#define隻是簡單的字元串替換而typedef則是為一個類型起新名字。
#define用法例子:
#define f(x) x*x
main( )
{
int a=6,b=2,c;
c=f(a) / f(b);
printf("%d ",c);
}
以下程式的輸出結果是: 36。
因為如此原因,在許多C語言程式設計規範中提到使用#define定義時,如果定義中包含表達式,必須使用括号,則上述定義應該如下定義才對:
#define f(x) (x*x)
當然,如果你使用typedef就沒有這樣的問題。
4. typedef & #define的另一例
下面的代碼中編譯器會報一個錯誤,你知道是哪個語句錯了嗎?
typedef char * pStr;
char string[4] = "abc";
const char *p1 = string;
const pStr p2 = string;
p1++;
p2++;
答案與分析:
是p2++出錯了。這個問題再一次提醒我們:typedef和#define不同,它不是簡單的文本替換。上述代碼中const pStr p2并不等于const char * p2。const pStr p2和const long x本質上沒有差別,都是對變量進行隻讀限制,隻不過此處變量p2的資料類型是我們自己定義的而不是系統固有類型而已。是以,const pStr p2的含義是:限定資料類型為char *的變量p2為隻讀,是以p2++錯誤。
(注:關于const的限定内容問題,在本系列第二篇有詳細講解)。
#define與typedef引申談
1) #define宏定義有一個特别的長處:可以使用 #ifdef ,#ifndef等來進行邏輯判斷,還可以使用#undef來取消定義。
2) typedef也有一個特别的長處:它符合範圍規則,使用typedef定義的變量類型其作用範圍限制在所定義的函數或者檔案内(取決于此變量定義的位置),而宏定義則沒有這種特性。
5. typedef & 複雜的變量聲明
在程式設計實踐中,尤其是看别人代碼的時候,常常會遇到比較複雜的變量聲明,使用typedef作簡化自有其價值,比如:
下面是三個變量的聲明,我想使用typdef分别給它們定義一個别名,請問該如何做?
>1:int *(*a[5])(int, char*);
>2:void (*b[10]) (void (*)());
>3. doube(*)() (*pa)[9];
答案與分析:
對複雜變量建立一個類型别名的方法很簡單,你隻要在傳統的變量聲明表達式裡用類型名替代變量名,然後把關鍵字typedef加在該語句的開頭就行了。
(注:如果你對有些變量的聲明文法感到難以了解,請參閱本系列第十篇的相關内容)。
>1:int *(*a[5])(int, char*);
//pFun是我們建的一個類型别名
typedef int *(*pFun)(int, char*);
//使用定義的新類型來聲明對象,等價于int* (*a[5])(int, char*);
pFun a[5];
>2:void (*b[10]) (void (*)());
//首先為上面表達式藍色部分聲明一個新類型
typedef void (*pFunParam)();
//整體聲明一個新類型
typedef void (*pFun)(pFunParam);
//使用定義的新類型來聲明對象,等價于void (*b[10]) (void (*)());
pFun b[10];
>3. doube(*)() (*pa)[9];
//首先為上面表達式藍色部分聲明一個新類型
typedef double(*pFun)();
//整體聲明一個新類型
typedef pFun (*pFunParam)[9];
//使用定義的新類型來聲明對象,等價于doube(*)() (*pa)[9];
pFunParam pa;
下面的3篇文檔是我在學習typedef歸納的總結,樓主覺得有用一定要給分哦!
//第1篇:typedef語句格式
#include<stdio.h>
typedef int GTYPE;//定義全局類型GTYPE
void main()
{
//一、基本格式
typedef char CH;//重定義基本類型
typedef struct{int a,b,c;}STRU;//重定義自定義類型(結構、共用、枚舉)
typedef union{int a,b,c;}UNIO;
typedef enum{one,two,three}NUM;
typedef char* STR;//重定義派生類型(指針、數組、函數)
typedef int AI[10];
typedef void FUN(void);
//可見,typedef使用的格式為:typedef 變量/函數定義語句;即在原變量/函數定義語句的開頭加上
//typedef,便可将原變量/函數定義語句改寫為類型定義語句,原來定義的變量名/函數名都成了類型名。
//注:當重定義基本、自定義類型時,格式也可總結為:typedef 原類型 新類型1,新類型2,…;
//二、觀察原類型
//1.原類型可以帶有類型限定符
typedef const int CI;//原類型含const限定符
CI ci=3;
//ci=4;//可見CI确實代表const int
//2.原類型可以是typedef定義的新類型
typedef CH NEWCH;//CH已在前面定義為char
NEWCH nc='a';
//3.原類型不可帶有存儲類别
//typedef static int SI;//錯誤,"指定的存儲類多于1個"
//typedef register int RI;//錯誤同上
//4.原類型應是一種類型,而不可是變量/對象
float f=0;//将f定義為變量
//typedef f FL;//錯誤
//5.不宜重定義的類型
typedef const CON;//重定義const
//CON int a=0;//但該類型無法正常使用
typedef unsigned US;//重定義unsigned
US us1=0;//正确,相當于unsigned int
//US int us2;//錯誤,無法正常使用
//注:因const、unsigned等并不是一種獨立的類型,故不便對它們重定義
//三、觀察新類型
//1.新類型的作用域
typedef int LTYPE;//定義局部類型LTYPE
void fun();//觀察LTYPE在fun中是否有效
fun();
//可見,用typedef定義的類型也有作用域之分。在函數内用typedef定義的是局部類型
//typedef也可以像變量定義語句一樣放置在函數之外,這時定義的是全局類型
//2.新類型可否是已有類型
//typedef int float;//錯誤,不能重定義标準類型
typedef int TYPE; //定義了新類型TYPE
//typedef char TYPE;//錯誤,"TYPE重定義"
typedef int GTYPE;//正确,盡管GTYPE是已有類型,但它是本函數外定義的
//可見,新類型名必須是合法的辨別符,它在其作用域内必須是唯一的
//3.新類型可否不止一個
typedef float LENGTH,WIDTH;//對float取兩個别名,LENGTH和WIDTH
LENGTH L=0;//用新類型定義變量
WIDTH W=0;
//可見,可以一次性為某個原類型指定多個别名
//4.一次可否定義多個不同類型
//typedef int I,float F;//一次定義了二個不同類型I和F
//F v=6.0;//試圖使用F類型
//printf("v=%f ",v);//v=0,類型F無效
//可見,一條typedef語句隻宜為一個原類型定義别名
}
void fun()
{ //LTYPE i;//錯誤,"LTYPE:未定義的辨別符"
GTYPE g=1;//使用全局類型GTYPE
printf("g=%d ",g);//正常使用
}
//第3篇:typedef具體應用
#include<stdio.h>
int fun1(int a,int b){return 0;}
int fun2(int a,int b){return 0;}
int fun3(int a,int b){return 0;}
void main()
{ //一、使用typedef的優點
//1可以為現有類型取一個更有意義的名字,增加程式的可讀性,如
typedef char* STRING;
STRING s1="string1",s2="string2";//STRING便可當作字元串類型來使用
//2使變量定義更簡短,減少書寫麻煩,如
typedef float A3[2][3][4];//為2*3*4的實型數組取簡短的名字A3
A3 a,b,c;//相當于定義float a[2][3][4],b[2][3][4],c[2][3][4]
typedef unsigned int(*PFUN)(int(*)[4]);//PFUN是一種函數指針,該類函數參數為一維數組型指針,傳回值為無符号整型
PFUN pf1,pf2;//相當于定義unsigned int(*pf1)(int(*)[4]);unsigned int(*pf2)(int(*)[4])
//3在定義複雜類型前,先用typedef建立一些中間類型,再用中間類型去構造複雜類型,以降低其複雜性(主要用途)
//例:對于如下的複雜定義
int(*ap[3])(int,int);//ap是一個數組,其元素為函數型指針,該類函數的參數和傳回值都是整型
//采用typedef以降低定義難度
//方法1
typedef int(*PF)(int,int);//定義PF為該種函數的指針
PF ap1[3];//ap1為一數組,每個元素都是PF類型
ap1[0]=fun1;ap1[1]=fun2;ap1[2]=fun3;
//方法2
typedef int FUN(int,int);//将該種函數定義為FUN類型
FUN* ap2[3];//ap2為一數組,每個元素都是指向FUN的指針
ap2[0]=fun1;ap2[1]=fun2;ap2[2]=fun3;
//4增加程式的可移植性(有利于程式在不同處理器、作業系統和編譯系統之間的移植)
//二、typedef與define的差別
//用define也可實作簡單的類型替換,如
#define INT long //用INT來代替long
//兩種方式的差別如下:
//1.二者處理時間不同,宏替換是在預編譯時進行的,而類型定義是在正式編譯時處理的
//2二者本質不同,宏替換隻是将宏名簡單替換為目标字元串,而類型定義如同定義變量一樣
//是真的為程式增加了一種可用類型
//3.二者複雜性不同,用typedef可定義各種複雜的類型,并以各種方式使用新類型(詳見10_10_2.cpp)
//而define隻能替換基本類型和自定義類型,無法替換派生類型,且使用起來很不安全,例如
#define pi int* //試圖用pi代替整型指針
pi pi1;//正确,展開後為int* pi1;
pi pi2,pi3;//錯誤,原意是将pi2,pi3都定義成整型指針,但展開後為int* pi2,pi3; pi3并未定義成指針
#define NUM enum{one,two,three}//試圖用NUM代替該枚舉類型
NUM n1;//正确,定義了枚舉常量one,two,three和枚舉變量n1
//NUM n2;//錯誤,展開後為enum{one,two,three}n2;進而造成枚舉常量one,two,three的重定義
#define DATE struct{int y,m,d;}
DATE *pd;//正确,定義了該結構型指針
//pd=(DATE)1;//錯誤,展開後為pi=(struct{int y,m,d;})1;目前尚不支援此種類型轉換寫法
#define TIME union{int h,m,s;}
//int L=sizeof(TIME);//錯誤,展開後為int L=sizeof(union{int h,m,s;});sizeof操作數錯誤
//可見,用define進行類型替換時,會産生各種意想不到的錯誤,故應避免使用,而改用安全的typedef
}
//第2篇:typedef詳細使用
/* 為了從易到難地使用typedef,現将C++資料類型按照類型名的來源和複雜性重分類如下:
一、基本類型(類型名是系統指定的單一辨別符)
in,char,float,double,void,const
二、自定義類型(類型名是使用者定義的單一辨別符)
1.結構類型
struct stru{int i;struct stru*;};
2.共用類型
union unio{int i;enum num[10];};
3.枚舉類型
enum num{a,b,c};
4.typedef類型
typedef double db;
三、派生類型(類型名由已有類型與其它符号組合而成)
1.指針類型(由 已有類型* 組成)
void*,char**,void(*)(),struct stru*,enum num*
2.數組類型(由 已有類型[][] 組成)
int[3][4],struct stru[10],enum num[10],char*[10]
3.函數類型(類型名是各種符号組成的函數原型)
void main(void),char* strcpy(char*,char*)
以上三大類别的類型辨別符由簡單到複雜,學習typedef時要依照先後順序,練習每種類型的重定義
每定義出一種新類型後,從以下幾個方面使用它:用它定義變量、指針、數組、帶存儲類别的對象、
帶const的對象;用它作函數參數和傳回值類型;用它進行類型轉換;用sizeof求長度*/
#include<stdio.h>
#include<stdlib.h>
void main()
{
//一、重定義基本類型
//1.定義
typedef int in;
typedef char ch;
typedef float fl;
typedef double db;
typedef unsigned int ui;//或寫為typedef unsigned ui;
typedef unsigned char uc;
typedef void vo;
//2.使用
in i=3;printf("i=%d
",i); //用新類型定義變量
ch* pc="pc";printf("pc=%s
",pc);//用新類型定義指針
fl af[3]={1,2,3};printf("af[0]=%f
",af[0]);//用新類型定義數組
static double sd;printf("sd=%f
",sd);//用新類型定義帶存儲類别的變量
const ui cui=3;printf("cui=%d
",cui);//用新類型定義帶類型限定符的變量
vo fun1(uc);fun1('a');//用新類型作函數的參數和傳回值類型
printf("in(1.5)=%d
",in(1.5));//将新類型用作類型轉換
printf("$db=%d
",sizeof(db));//對新類型求長度,$db=$double=8
//二、重定義自定義類型
//1.定義
//(1)完整寫法(先定義好自定義類型,再重定義它)
struct datetype //重定義結構類型
{ ui year;//ui即是unsigned int;
uc month;//uc即是unsigned char;
uc day;};
typedef datetype date;
union scoretype //重定義共用類型
{ fl sco1;
ch* sco2;};
typedef scoretype score;
enum numtype{one,two,three}; //重定義枚舉類型
typedef numtype num;
typedef num newnum; //重定義typedef類型
//(2)通常寫法(對無類型名的結構、共用、枚舉定義語句直接重定義)
typedef struct{uc hou,min,sec;} time;
typedef union{fl sco1;ch* sco2;} sco;
typedef enum{red,green,blue} color;
//可見,無論何種寫法,都遵循typedef語句的格式:typedef 原類型 新類型;
//2.使用
date vs={2002,10,15};//定義結構變量
printf("vs:%d.%d.%d
",vs.year,vs.month,vs.day);
score vu,*pu=&vu;printf("&vu=%x pu=%x
",&vu,pu);//定義共用指針
newnum ae[3]={one,two,three};//定義枚舉數組
printf("ae[0]=%d ae[1]=%d ae[2]=%d
",ae[0],ae[1],ae[2]);
static num vn;//定義帶存儲類别的對象
printf("vn=%d
",vn);
const sco cs={90};//定義const對象
printf("cs.sco1=%f
",cs.sco1);
time fun2(time);//作函數的參數和傳回值類型
static time vt=fun2(vt);
printf("fun2:%d:%d:%d
",vt.hou,vt.min,vt.sec);
vn=(num)10;printf("vn=%d
",vn);//将新類型用作類型轉換
printf("$time=%d
",sizeof(time));//對新類型求長度,$time=3
printf("$sco=%d
",sizeof(sco));//對新類型求長度,$sco=4
printf("$color=%d
",sizeof(color));//對新類型求長度,$color=4
//未完待續
//2.重定義數組類型
//(1)定義
typedef int ai[5];//重定義基本類型數組
typedef float a2[3][4];//重定義數組型數組(二維數組)
typedef time as[2];//重定義結構型數組
typedef sco au[2];//重定義共用型數組
typedef color ae2[2];//重定義枚舉型數組
typedef char* ap2[2];//重定義指針型數組
//注:重定義數組時,C++暫不支援typedef int[10] ai這種正規寫法
//(2)使用
//定義變量(數組變量)
ai vai={1,2,3,4,5};//相當于int vai[5];
printf("vai:%d %d
",vai[0],vai[1]);
//定義指針(數組指針)
a2 va2,*pa2=&va2;//相當于float va2[3][4],(*pa2)[3][4]=&va2;
printf("&va2=%x pa2=%x
",va2,pa2);
//定義數組(多元數組)
as vas[2]={{10,20,30},{20,40,59}};//vas此時是二維結構數組,相當于time vas[2][2];
printf("vas[0][0]:%d:%d:%d
",vas[0][0].hou,vas[0][0].min,vas[0][0].sec);
//定義帶存儲類别的數組
static au vau;//vau是含2元素的靜态共用數組
printf("vau[2]:%f %f
",vau[0].sco1,vau[1].sco1);
//定義cosnt數組
const ae2 cae2={red,green};//cae2是含2元素的常量枚舉數組
printf("cae2[2]:%d %d
",cae2[0],cae2[1]);
//定義函數
void fun4(ap2);//參數是指針數組,相當于void fun4(char* ap2[2]);
ap2 vap2={"str1","str2"};//vap2的兩元素分别指向"str1"和"str2"
fun4(vap2);
printf("$ai=%d
",sizeof(ai));//對新類型求長度,$ai=$int[5]=20
printf("$a2=%d
",sizeof(a2));//對新類型求長度,$a2=$float[3][4]=48
printf("$as=%d
",sizeof(as));//對新類型求長度,$as=$=time[2]=6
printf("$au=%d
",sizeof(au));//對新類型求長度,$au=$=sco[2]=8
printf("$ae2=%d
",sizeof(ae2));//對新類型求長度,$ae2=$color[2]=8
printf("$ap2=%d
",sizeof(ap2));//對新類型求長度,$ap2=$=char*[2]=8
//注:因函數傳回值不能是數組類型,故這裡不再将重定義類型用作函數傳回值類型
//3.重定義函數類型
//(1)定義方法
int fun(int,int);//聲明了一個函數,它有兩個整型參數、傳回值為整型
typedef int FUN(int,int);//定義了一個類型,它代表含兩個整型參數、傳回值為整型的函數
//(2)使用方法
//定義變量(函數)
FUN max,min;//用類型FUN定義了兩個對象max和min,因FUN是函數類型,故它們自然是函數對象
//這裡相當于int max(int,int)和int min(int,int)兩個聲明
printf("max(3,5)=%d
",max(3,5));//調用這兩個函數
printf("min(3,5)=%d
",min(3,5));
//定義指針(函數指針)
FUN* pfun;//pfun是一種指針,它專門指向FUN類型的對象。相當于定義int(*pfun)(int,int);
pfun=max;//max和min都是FUN類型的對象
printf("&max=%x pfun=%x
",max,pfun);
//其它使用基本無意義,略
//可見,若程式中要用到許多類型相同但名稱不同的函數,可先用typedef抽象出類型,再用該類型
//一次便可聲明許多函數,以簡化函數原型的書寫。但這種類型隻能用來聲明函數,而不能用來定義函數
} //main end
//下面是main中用到的函數
void fun1(unsigned char p)//因vo與uc的作用域不在此處,故這裡直接使用void和unsigned
{ printf("fun1:%c
",p);//這樣與函數原型vo fun1(uc)亦對應
}
typedef struct{unsigned char hou,min,sec;} time;//因main中的time類型作用域已結束,故這裡要使用必須重新定義
time fun2(time p)
{ p.hou=20;p.min=30,p.sec=55;
return p;}
/*注:嚴格來說這裡的time與main中函數原型裡的time并不是同一類型,但系統忽略了這點
正确用法應将main中的time作為全局類型定義在程式開頭,這樣其後的函數都可共享使用該類型*/
void* fun3(float** p)
{ printf("fun3:malloc(%d)",p);
return malloc(int(p));
}
typedef char* ap2[2];
void fun4(ap2 p)
{ printf("fun4:p[0]=%s p[1]=%s
",p[0],p[1]);
}
int max(int a,int b)
{ return a>b?a:b;
}
int min(int a,int b)
{ return a<b?a:b;
}