C語言數據類型問題及答疑

1.C語言裏面如何計算數據類型取值範圍?


Char 8  -128~127 8 -128~127

int   16  -32768~32767 32 -21億~21億

short 16 -32768~32767 16 -32768~32767

long 32 -21億~21億 32 -21億~21億

Unsigned char 8 255 8 255

unsigned int 16 0~65535 32 0~42億

unsigned short 16 0~65535 16 0~65535 

unsigned long 32 0~42億 32 0~42億


2. C語言中數據類型的長度?

  ANSI C99標準中定義了兩類(四個)類型修飾符:long/short和unsigned/signed。

  C99標準規定,long類型不能比變通類型短,short類型不能比普通類型長。而unsigned與signed的區別在實現上是有無符號的區別,而是使用上是取值範圍的區別,兩者表示範圍相同,但前者全是正數,後者關於0對稱。

  說明:

  • long/short可以修飾int,long還可以修飾double。
  • unsigned/signed可以修飾int, char,不可以修飾浮點型。
  • int長度是機器的字長,short int是半個字長,long int是一個或兩個字長。
  • unsigned/signed長度與普通類型一樣,只是表示區間不同。
3.C語言中如何定義全局變量
int f = 7;// 這個是全局變量
int myadd(int a, int b)
{
int c = a + b;// c是局部變量,只能在myadd中使用
return c;
}
int main(void)
{
printf("%d\n", f);// f是全局變量,這句是正確的。
}
先看用來修飾變量的時候。變量在c裏面可分爲存在全局數據區、棧和堆裏。其實我們平時所說的堆棧是棧而不是堆,不要弄混。
int a ;
int main()
{
    int b ; 
    int c* = (int *)malloc(sizeof(int));
}
a是全局變量,b是棧變量,c是堆變量。
static對全局變量的修飾,可以認爲是限制了只能是本文件引用此變量。有的程序是由好多.c文件構成。彼此可以互相引用變量,但加入static修飾之後,只能被本文件中函數引用此變量。
static對棧變量的修飾,可以認爲棧變量的生命週期延長到程序執行結束時。一般來說,棧變量的生命週期由OS管理,在退棧的過程中,棧變量的生命也就結束了。但加入static修飾之後,變量已經不再存儲在棧中,而是和全局變量一起存儲。同時,離開定義它的函數後不能使用,但如再次調用定義它的函數時,它又可繼續使用, 而且保存了前次被調用後留下的值。
static對函數的修飾與對全局變量的修飾相似,只能被本文件中的函數調用,而不能被同一程序其它文件中的函數調用。
文件a.c
static int i; //只在a文件中用
int j;          //在工程裏用
static void init()         //只在a文件中用
{
}
void callme()          //在工程中用
{
    static int sum;
}
文件b.c
extern int j;                    //調用a文件裏的
extern void callme();   //調用a文件裏的
int main()
{
  ...
}
文件A.cpp調用a.c裏面的變量i和函數callme()
extern "C"  //在c++文件裏調用c文件中的變量
{
   int j;
   void callme();
}
int main()
{
   callme();
}
B、若全局變量僅由單個函數訪問,則可以將這個變量改爲該函數的靜態局部變量,以降低模塊間的耦合度;
C、設計和使用訪問動態全局變量、靜態全局變量、靜態局部變量的函數時,需要考慮重入問題;
(1)全局變量一般用外部存儲方式存儲,用保留字extern加以定義。此時,變量的作用域是構成整個程序的所有程序文件,也就是定義的外部變量可供其它程序文件使用。
使用這樣的全局變量一定要非常慎重,一旦產生錯誤,將波及整個程序。
(2)如果希望全局變量僅限於本程序文件使用,而其它程序文件中不能引用,這時必須將其存儲方式定義爲靜態存儲方式,用保留字static加以定義。此時稱爲靜態外部變量。
例如,在上例文件filel.c中,如果作這樣的定義:
static int a:
則變量a的作用域被縮小至本程序文件filel.c,文件file2.c中不能引用。
值得注意的是對全局變量加static,定義爲靜態存儲方式,並不意味着是靜態存儲;而不加static,是動態存儲。兩種形式的全局變量(外部變量)都是靜態存儲方式,都是編譯時分配存儲空間,但作用域不同。使用靜態外部變量,有利於隔離錯誤,有利於模塊化程序設計。
(3)全局變量的缺省存儲方式是外部存儲方式。
前面章節中的程序沒有見到變量的存儲類別定義,實際上採用變量的缺省存儲方式。對局部變量採用auto方式,對全局變量採用extern方式。這也是至今爲止,我們在程序中沒有見到auto、extern等的原因。
至此,我們對變量的存儲類別及數據類型進行了全面討論,在此作個小結。
變量定義的一般形式
存儲類別數據類型變量表;
2.變量定義的作用
①規定了變量的取值範圍。
②規定了變量進行的運行操作。
③規定了變量的作用域。
④規定了變量的存儲方式。
⑤規定了變量佔用的存儲空間。
局部變量和全局變量
從作用域角度將變量分爲局部變量和全局變量。它們採取的存儲類別如下:
局部變量:
①自動變量,即動態局部變量(離開函數,值就消失)。
②靜態局部變量(離開函數,值仍保留)。
③寄存器變量(離開函數,值就消失)。
④形式參數可以定義爲自動變量或寄存器變量。
全局變量:
①靜態外部變量(只限本程序文件使用)。
②外部變量(即非靜態的外部變量,允許其它程序文件引用)。
動態存儲和靜態存儲
從變量存在時間可將變量存儲分爲動態存儲和靜態存儲。靜態存儲是在整個程序運行時都存在,而動態存儲則是在調用函數時臨時分配存儲單元。
動態存儲:
①自動變量(函數內有效)。
②寄存器變量(函數內有效)。
③形式參數。
靜態存儲:
①靜態局部變量(函數內有效)。
②靜態外部變量(本程序文件內有效)。
③外部變量(整個程序可引用)。
靜態存儲區和動態存儲區
從變量值存放的位置可將變量存儲區分爲靜態存儲區和動態存儲區:
內存中靜態存儲區:
①靜態局部變量。
②靜態外部變量。
③外部變量(可被同一程序其它文件引用)。
內存中動態存儲區:自動變量和形式參數。
CPU中的寄存器:寄存器變量。

extern修飾變量的聲明。舉例來說,如果文件a.c需要引用b.c中變量int v,就可以在a.c中聲明extern int v,然後就可以引用變量v。這裏需要注意的是,被引用的變量v的鏈接屬性必須是外鏈接(external)的,也就是說a.c要引用到v,不只是取決於在a.c中聲明extern int v,還取決於變量v本身是能夠被引用到的。這涉及到c語言的另外一個話題--變量的作用域。能夠被其他模塊以extern修飾符引用到的變量通常是全局變量。還有很重要的一點是,extern int v可以放在a.c中的任何地方,比如你可以在a.c中的函數fun定義的開頭處聲明extern int v,然後就可以引用到變量v了,只不過這樣只能在函數fun作用域中引用v罷了,這還是變量作用域的問題。對於這一點來說,很多人使用的時候都心存顧慮。好像extern聲明只能用於文件作用域似的。
2. extern修飾函數聲明。從本質上來講,變量和函數沒有區別。函數名是指向函數二進制塊開頭處的指針。如果文件a.c需要引用b.c中的函數,比如在b.c中原型是int fun(int mu),那麼就可以在a.c中聲明extern int fun(int mu),然後就能使用fun來做任何事情。就像變量的聲明一樣,extern int fun(int mu)可以放在a.c中任何地方,而不一定非要放在a.c的文件作用域的範圍中。對其他模塊中函數的引用,最常用的方法是包含這些函數聲明的頭文件。使用extern和包含頭文件來引用函數有什麼區別呢?extern的引用方式比包含頭文件要簡潔得多!extern的使用方法是直接了當的,想引用哪個函數就用extern聲明哪個函數。這大概是KISS原則的一種體現吧!這樣做的一個明顯的好處是,會加速程序的編譯(確切的說是預處理)的過程,節省時間。在大型C程序編譯過程中,這種差異是非常明顯的。
3. 此外,extern修飾符可用於指示C或者C++函數的調用規範。比如在C++中調用C庫函數,就需要在C++程序中用extern “C”聲明要引用的函數。這是給鏈接器用的,告訴鏈接器在鏈接的時候用C函數規範來鏈接。主要原因是C++和C程序編譯完成後在目標代碼中命名規則不同。
     首先需要注意的是,const修飾的是在它前面的類型,如果它前面沒有類型,那它修 飾的是緊跟着它的那個類型。 例如:
(a)const int i = 0; 和 (b)int const i = 0; 是完全一樣的。
在(a)中,const前面沒有類型,它就修飾它後面的那個int類型。在(b)中,const修飾它前 面的int類型,兩者沒有任何區別。
再看另一個稍複雜一點的例子,下面兩條語句卻不相同: (c)const int *pi = 0;
/* 相當於int const *pi = 0; pi是一個指向const int的指針,復引用此運算符爲得到一 個const int的類型,該類型不能作爲左值,在該語句後使用類似於*pi = 1的操作將導致 編譯錯誤。但該變量本身並不具備const屬性,可以使用pi = &i的操作。可用於訪問只讀 存儲器。*/ 
(d)int* const pi = 0;
/* pi是一個指向int類型的const指針,復引用此運算符爲得到一個int類型,該類型可以 作爲左值,在該語句可以使用類似於*pi = 1的操作,但該變量本身具備const屬性,使用 pi = &i的操作將導致編譯錯誤。可用於訪問固定位置的存儲器。*/ 再看一個更復雜的例子:
(e)const int* const pi = 0;
/* pi和*pi均不能作爲左值。它只適合於讀取某個固定位置的只讀存儲器 */ 
const還有下列典型用法:
     * 用於參數列表,通常修飾的是指針類型,表明該函數不會試圖對傳入的地址進行寫 操作。例如:
void *memcpy(void *, const void *, size_t);
     * 用於返回值,通常是一個指向只讀區域的指針。例如: const datatype_t *get_fixed_item(int index);
     * 給固定不變的數據(例如碼錶)加上只讀屬性,在某些情況下可以減小ram的開銷。   
void (*b[10]) (void (*)()); //#2 
double(*)() (*pa)[9];          //#3
C語言中函數聲明和數組聲明。函數聲明一般是這樣: 
int fun(int, double); 
對應函數指針(pointer to function)的聲明是這樣: 
int (*pf)(int, double); 
可以這樣使用: 
pf = &fun;       //賦值(assignment)操作 
(*pf)(5, 8.9);//函數調用操作 
也請注意,C語言本身提供了一種簡寫方式如下: 
pf = fun;        // 賦值(assignment)操作 
pf(5, 8.9);      // 函數調用操作 
不過我本人不是很喜歡這種簡寫,它對初學者帶來了比較多的迷惑。 
數組聲明一般是這樣: 
int a[5]; 
對於數組指針(pointer to array)的聲明是這樣: 
int (*pa)[5]; 
可以這樣使用: 
pa = &a;             // 賦值(assignment)操作 
int i = (*pa)[2]; // 將a[2]賦值給i;
#1:int* (*a[5])(int, char*); 
首先看到標識符名a,“[]”優先級大於“*”,a與“[5]”先結合。所以a是一個數組,這個數組有5個元素,每一個元素都是一個指針, 
指針指向“(int, char*)”,對,指向一個函數,函數參數是“int, char*”,返回值是“int*”。完畢,我們幹掉了第一個紙老虎。:)
b是一個數組,這個數組有10個元素,每一個元素都是一個指針,指針指向一個函數,函數參數是“void (*)()”【注1】,返回值是“void”。完畢! 
注1:這個參數又是一個指針,指向一個函數,函數參數爲空,返回值是“void”。
#3:double(*)()(*pa)[9]; 
pa是一個指針,指針指向一個數組,這個數組有9個元素,每一個元素都是“double(*)()”【也即一個指針,指向一個函數,函數參數爲空,返回值是“double
#1:int* (*a[5])(int, char*); 
typedef int* (*PF)(int, char*);//PF是一個類型別名【注2】。 
PF a[5];//跟int* (*a[5])(int, char*);的效果一樣! 
注2:很多初學者只知道typedef char* pchar;但是對於typedef的其它用法不太瞭解。Stephen Blaha對typedef用法做過一個總結:“建立一個類型別名的方法很簡單,在傳統的變量聲明表達式裏用類型名替代變量名,然後把關鍵字typedef加在該語句的開頭”。
#2:void (*b[10])(void (*)()); 
typedef void (*pfv)(); 
typedef void (*pf_taking_pfv)(pfv); 
pf_taking_pfv b[10]; //跟void (*b[10]) (void (*)());的效果一樣!
#3. double(*)()(*pa)[9]; 
typedef double(*PF)(); 
typedef PF (*PA)[9]; 
PA pa; //跟doube(*)()(*pa)[9];的效果一樣!
在這裏我只說const,volatile是一樣的!【注3】 
注3:顧名思義,volatile修飾的量就是很容易變化,不穩定的量,它可能被其它線程,操作系統,硬件等等在未知的時間改變, 
所以它被存儲在內存中,每次取用它的時候都只能在內存中去讀取,它不能被編譯器優化放在內部寄存器中。 
類型聲明中const用來修飾一個常量,我們一般這樣使用:const在前面: 
const int; //int是const 
const char*;//char是const 
char* const;//*(指針)是const 
const char* const;//char和*都是const 
對初學者,const char*和 char* const是容易混淆的。這需要時間的歷練讓你習慣它。 上面的聲明有一個對等的寫法:const在後面: 
int const; //int是const 
char const*;//char是const 
char* const;//*(指針)是const 
char const* const;//char和*都是const
第一次你可能不會習慣,但新事物如果是好的,我們爲什麼要拒絕它呢?:)const在後面有兩個好處: 
A.const所修飾的類型正好是在它前面的那一個。如果這個好處還不能讓你動心的話,那請看下一個! 
B.我們很多時候會用到typedef的類型別名定義。比如typedef char* pchar,如果用const來修飾的話,
是不是讓你大喫一驚!但如果你採用const在後面的寫法,意義就怎麼也不會變,不信你試試! 
不過,在真實項目中的命名一致性更重要。你應該在兩種情況下都能適應,並能自如的轉換,公司習慣, 
商業利潤不論在什麼時候都應該優先考慮!不過在開始一個新項目的時候,你可以考慮優先使用const在後面的習慣用法。
二.Typedef聲明有助於創建平臺無關類型,甚至能隱藏複雜和難以理解的語法。 
   不管怎樣,使用 typedef 能爲代碼帶來意想不到的好處,通過本文你可以學習用typedef避免缺欠,從而使代碼更健壯。 
typedef聲明,簡稱typedef,爲現有類型創建一個新的名字。比如人們常常使用 typedef 來編寫更美觀和可讀的代碼。 
所謂美觀,意指typedef 能隱藏笨拙的語法構造以及平臺相關的數據類型,從而增強可移植性和以及未來的可維護性。 
本文下面將竭盡全力來揭示 typedef 強大功能以及如何避免一些常見的陷阱,如何創建平臺無關的數據類型,隱藏笨拙且難以理解的語法. 
typedef使用最多的地方是創建易於記憶的類型名,用它來歸檔程序員的意圖。類型出現在所聲明的變量名字中,位於typedef關鍵字右邊。 
例如:typedef int size; 
此聲明定義了一個 int 的同義字,名字爲 size。注意typedef並不創建新的類型。它僅僅爲現有類型添加一個同義字。 
你可以在任何需要 int 的上下文中使用 size: 
void measure(size * psz); 
size array[4]; 
size len = file.getlength(); 
typedef 還可以掩飾複合類型,如指針和數組。例如,你不用象下面這樣重複定義有81個字符元素的數組: 
char line[81]; char text[81]; 
定義一個typedef,每當要用到相同類型和大小的數組時,可以這樣: 
typedef char Line[81]; 
Line text, secondline; 
getline(text); 
同樣,可以象下面這樣隱藏指針語法: 
typedef char * pstr; 
int mystrcmp(pstr, pstr); 
這裏將帶我們到達第一個 typedef 陷阱。標準函數 strcmp()有兩個const char *類型的參數。因此,它可能會誤導人們象下面這樣聲明: 
int mystrcmp(const pstr, const pstr); 
這是錯誤的,事實上,const pstr被編譯器解釋爲char * const(一個指向 char 的常量指針),而不是const char *(指向常量 char 的指針)。 
這個問題很容易解決: 
typedef const char * cpstr; 
int mystrcmp(cpstr, cpstr); 
上面討論的 typedef 行爲有點像 #define 宏,用其實際類型替代同義字。不同點是typedef在編譯時被解釋 
,因此讓編譯器來應付超越預處理器能力的文本替換。例如: 
typedef int (*PF) (const char *, const char *); 
這個聲明引入了 PF 類型作爲函數指針的同義字,該函數有兩個 const char * 類型的參數以及一個 int 類型的返回值。如果要使用下列形式的函數聲明,那麼上述這個 typedef 是不可或缺的: 
PF Register(PF pf); 
Register()的參數是一個PF類型的回調函數,返回某個函數的地址,其署名與先前註冊的名字相同。做一次深呼吸。下面我展示一下如果不用 typedef,我們是如何實現這個聲明的: 
int (*Register (int (*pf)(const char *, const char *))) (const char *, const char *); 
很少有程序員理解它是什麼意思,更不用說這種費解的代碼所帶來的出錯風險了。顯然,這裏使用 typedef 不是一種特權, 
而是一種必需。typedef 就像 auto,extern,mutable,static,和 register 一樣,是一個存儲類關鍵字。 
這並不是說typedef會真正影響對象的存儲特性;它只是說在語句構成上,typedef 聲明看起來象 static,extern 等類型的變量聲明。 
下面將帶到第二個陷阱: 
typedef register int FAST_COUNTER; // 錯誤編譯通不過 
問題出在你不能在聲明中有多個存儲類關鍵字。因爲符號 typedef 已經佔據了存儲類關鍵字的位置, 
在 typedef 聲明中不能用 register(或任何其它存儲類關鍵字)。typedef 有另外一個重要的用途,那就是定義機器無關的類型, 
例如,你可以定義一個叫 REAL 的浮點類型,在目標機器上它可以獲得最高的精度:
在不支持 long double 的機器上,該 typedef 看起來會是下面這樣: 
typedef double REAL; 
並且,在連 double 都不支持的機器上,該 typedef 看起來會是這樣: 
typedef float REAL; 
你不用對源代碼做任何修改,便可以在每一種平臺上編譯這個使用 REAL 類型的應用程序。唯一要改的是 typedef 本身。 
在大多數情況下,甚至這個微小的變動完全都可以通過奇妙的條件編譯來自動實現。不是嗎? 
標準庫廣泛地使用 typedef 來創建這樣的平臺無關類型:size_t,ptrdiff 和 fpos_t 就是其中的例子。 
此外,象 std::string 和 std::ofstream 這樣的 typedef 還隱藏了長長的,難以理解的模板特化語法, 
例如:basic_string,allocator> 和 basic_ofstream>。
定義一種類型的別名,而不只是簡單的宏替換。可以用作同時聲明指針型的多個對象。比如: 
char* pa, pb; // 這多數不符合我們的意圖,它只聲明瞭一個指向字符變量的指針, 
// 和一個字符變量; 
以下則可行: 
typedef char* PCHAR; // 一般用大寫 
PCHAR pa, pb; // 可行,同時聲明瞭兩個指向字符變量的指針 
雖然: 
char *pa, *pb; 
也可行,但相對來說沒有用typedef的形式直觀,尤其在需要大量指針的地方,typedef的方式更省事。
用在舊的C代碼中(具體多舊沒有查),幫助struct。以前的代碼中,聲明struct新對象時,必須要帶上struct,即形式爲: struct 結構名 對象名,如: 
struct tagPOINT1 

int x; 
int y; 
}; 
struct tagPOINT1 p1;
tagPOINT1 p1;
typedef struct tagPOINT 

int x; 
int y; 
}POINT;
用typedef來定義與平臺無關的類型。 
比如定義一個叫 REAL 的浮點類型,在目標平臺一上,讓它表示最高精度的類型爲: 
typedef long double REAL; 
在不支持 long double 的平臺二上,改爲: 
typedef double REAL; 
在連 double 都不支持的平臺三上,改爲: 
typedef float REAL; 
也就是說,當跨平臺時,只要改下 typedef 本身就行,不用對其他源碼做任何修改。 
標準庫就廣泛使用了這個技巧,比如size_t。 
另外,因爲typedef是定義了一種類型的新別名,不是簡單的字符串替換,所以它比宏來得穩健(雖然用宏有時也可以完成以上的用途)。
爲複雜的聲明定義一個新的簡單的別名。方法是:在原來的聲明裏逐步用別名替換一部分複雜聲明,如此循環,把帶變量名的部分留到最後替換,得到的就是原聲明的最簡化版。舉例:
變量名爲a,直接用一個新別名pFun替換a就可以了: 
typedef int *(*pFun)(int, char*); 
原聲明的最簡化版: 
pFun a[5];
變量名爲b,先替換右邊部分括號裏的,pFunParam爲別名一: 
typedef void (*pFunParam)(); 
再替換左邊的變量b,pFunx爲別名二: 
typedef void (*pFunx)(pFunParam); 
原聲明的最簡化版: 
pFunx b[10];
變量名爲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。
type (*)(....)函數指針 
type (*)[]數組指針 
---------------------------------
記住,typedef是定義了一種類型的新別名,不同於宏,它不是簡單的字符串替換。比如: 
先定義: 
typedef char* PSTR; 
然後: 
int mystrcmp(const PSTR, const PSTR);
原因在於const給予了整個指針本身以常量性,也就是形成了常量指針char* const。 
簡單來說,記住當const和typedef一起出現時,typedef不會是簡單的字符串替換就行。
typedef在語法上是一個存儲類的關鍵字(如auto、extern、mutable、static、register等一樣),雖然它並不真正影響對象的存儲特性,如: 
typedef static int INT2; //不可行 
編譯將失敗,會提示“指定了一個以上的存儲類”。
現在是不是覺得要認識它們是易如反掌,工欲善其事,必先利其器!我們對這種表達方式熟悉之後,就可以用“typedef”來簡化這種類型聲明。
9.枚舉類型(Enum)是什麼
union成員共享同一塊大小的內存,一次只能使用其中的一個成員。 
對某一個成員賦值,會覆蓋其他成員的值(也不奇怪,因爲他們共享一塊內存。但前提是成員所佔字節數相同,當成員所佔字節數不同時只會覆蓋相應字節上的值,比如對char成員賦值就不會把整個int成員覆蓋掉,因爲char只佔一個字節,而int佔四個字節)

10.C語言中關於float、double、long double精度及數值範圍應該如何理解?

floatdouble的精度是由尾數的位數來決定的。浮點數在內存中是按科學計數法來存儲的,其整數部分始終是一個隱含着的“1”,由於它是不變的,故不能對精度造成影響。float2^23 = 8388608,一共七位,這意味着最多能有7位有效數字,但絕對能保證的爲6位,也即float的精度爲6~7位有效數字;double2^52 = 4503599627370496,一共16位,同理,double的精度爲15~16位。

其中負指數決定了浮點數所能表達的絕對值最小的非零數;而正指數決定了浮點數所能表達的絕對值最大的數,也即決定了浮點數的取值範圍。float的範圍爲-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38double的範圍爲-2^1024 ~ +2^1024,也即-1.79E+308 ~+1.79E+308




11.typedef的用法

一.基本概念剖析

int* (*a[5])(int, char*);       //#1 


2.有了上面的基礎,我們就可以對付開頭的三隻紙老虎了!:) 這個時候你需要複習一下各種運算符的優先順序和結合順序了,順便找本書看看就夠了。 

#2:void (*b[10]) (void (*)()); 


--------------------------------------------------------------- 



3.const和volatile在類型聲明中的位置。 


當const在前面的時候,就是const pchar,你會以爲它就是const char* ,但是你錯了,它的真實含義是char* const。 


typedef long double REAL; 

用途一: 

用途二: 

而在C++中,則可以直接寫:結構名 對象名,即: 

估計某人覺得經常多寫一個struct太麻煩了,於是就發明了: 

POINT p1; // 這樣就比原來的方式少寫了一個struct,比較省事,尤其在大量使用的時候

或許,在C++中,typedef的這種用途二不是很大,但是理解了它,對掌握以前的舊代碼還是有幫助的,畢竟我們在項目中有可能會遇到較早些年代遺留下來的代碼。

用途三: 

用途四: 

1. 原聲明:int *(*a[5])(int, char*); 

2. 原聲明:void (*b[10]) (void (*)()); 

3. 原聲明:doube(*)() (*e)[9]; 

理解複雜聲明可用的“右左法則”:從變量名看起,先往右,再往左,碰到一個圓括號就調轉閱讀的方向;括號內分析完就跳出括號,還是按先右後左的順序,如此循環,直到整個聲明分析完。舉例: 

也可以記住2個模式: 

陷阱一: 

const PSTR實際上相當於const char*嗎?不是的,它實際上相當於char* const。 

陷阱二: 

”】。(注意typedef int* p[9]與typedef int(*p)[9]的區別,前者定義一個數組,此數組包含9個int*類型成員,而後者定義一個指向數組的指針,被指向的數組包含9個int類型成員)。 

(1) 枚舉型是一個集合,集合中的元素(枚舉成員)是一些命名的整型常量,元素之間用逗號,隔開。

(2) DAY是一個標識符,可以看成這個集合的名字,是一個可選項,即是可有可無的項。

(3) 第一個枚舉成員的默認值爲整型的0,後續枚舉成員的值在前一個成員上加1。

(4) 可以人爲設定枚舉成員的值,從而自定義某個範圍內的整數。

(5) 枚舉型是預處理指令#define的替代。

(6) 類型定義以分號;結束。

12.聯合體是什麼

1、union中可以定義多個成員,union的大小由最大的成員的大小決定。 

4、聯合體union的存放順序是所有成員都從低地址開始存放的。

(1) 枚舉型是一個集合,集合中的元素(枚舉成員)是一些命名的整型常量,元素之間用逗號,隔開。

(2) DAY是一個標識符,可以看成這個集合的名字,是一個可選項,即是可有可無的項。

(3) 第一個枚舉成員的默認值爲整型的0,後續枚舉成員的值在前一個成員上加1。

(4) 可以人爲設定枚舉成員的值,從而自定義某個範圍內的整數。

(5) 枚舉型是預處理指令#define的替代。

(6) 類型定義以分號;結束。

(1) 枚舉型是一個集合,集合中的元素(枚舉成員)是一些命名的整型常量,元素之間用逗號,隔開。

(2) DAY是一個標識符,可以看成這個集合的名字,是一個可選項,即是可有可無的項。

(3) 第一個枚舉成員的默認值爲整型的0,後續枚舉成員的值在前一個成員上加1。

(4) 可以人爲設定枚舉成員的值,從而自定義某個範圍內的整數。

(5) 枚舉型是預處理指令#define的替代。

(6) 類型定義以分號;結束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章