C 語言學習筆試

來源:互聯網
上載者:User

================================================================================
《C和指標》
================================================================================
1、指標的效率(P146):指標的效率高於下標,不對指標進行加減運算,sizeof接常量運算式可以在編譯時間求值。

2、運行時環境(P397)
主調函數從右至左壓入被調函數的實參、返回地址,然後轉到被調函數,被調函數在其函數序中儲存相關寄存器值和局部變數,然後執行函數體,最後由被調函數轉至返回地址,然後主調函數再來清除其實參。

3、void *類型不能進行指標運算,因為void的大小未知,所以編譯器會報錯。
函數指標也不能進行指標運算(沒意義)。

================================================================================
《C專家編程》
================================================================================
1、P22 尋常算術轉換(操作符的運算元類型不一致時發生):char shrot 轉 int ,float 轉 double, 同類型時有unsigned 就全轉 unsinged

// char 轉 int (型別提升)
printf("%d", sizeof('A')); // 輸出為4

整型升級:如果int可以完整表示源類型的所有值,則該源類型的值就轉換為int否則轉為unsigned int
註:ANSI C表示如果編譯器能夠保證運算結果一致,也可以省略型別提升。

2、不要為了方便對結構使用typedef,因為struct關鍵字可以提示一些資訊,不應省掉。

3、數組和指標不同(定址方式不同):數組是變址定址即 EA=(IX)+A, A是數組首地址,指標是間接定址即 EA=(A), A是指標值。總之指標訪存開銷比數組訪存多一次(如p[i]這種),如果把數組名賦給指標,那麼以後對指標的任何操作就與指標同。但是如果是大量的非單純訪存的操作用指標方針可以提高效率。
// 正常,與*(p+3)完全相同。
char * p = "adsdfs";
char c = p[3];

// 錯誤,因為p會按照指標方式定址,從而把字元'1'+2的位移來作為p[2]的地址。
extern char * p;
char p[4] = "123";
char c = p[2];

4、避免interpositioning,否則不光自己代碼,系統調用也會影響(5.4系統保留的關鍵字)
ldd命令列出可執行檔的動態依賴集

5、有用的工具:
cflow 列印源檔案中函數的調用關係
sum 列印可執行檔的檢驗和與程式塊計數,用於檢查檔案版本,傳輸出錯否。
file 列印檔案類型,如是二進位檔案還是文字檔。
gprof 程式效能評測工具:(gcc編譯時間要加-pg選項,並且要在程式運行後才能評測)
time 顯示程式所使用的實際時間和cpu時間。

6、進程的記憶體布局:
高地址
    堆棧段---------函數的局部資料
    空洞
    ------------break,堆的邊界
    堆-----------用於malloc等
    資料區段的BSS段-----未賦值的符號
    資料區段其它-------靜態儲存區
    文本段---------指令區
低地址
     
相關函數:
  brk(),是系統調用。改變資料區段大小(即break的位置),一般不用顯式調用,malloc會自動調它
  sbrk(),是C庫函數。改變資料區段大小(即break的位置)。
命令:
vmstat,報告虛擬記憶體統計資訊。
ps -lu 使用者名稱 ,查看該使用者的進程,並顯示進程記憶體使用量情況。

系統並不支援在訊號處理函數內部調用庫函數,因為可能陷入無盡的訊號迴圈。

7、K&R C會在參數傳遞時進行型別提升,然後在函數內部再按參數類型裁減。而ANSI C的參數傳遞是什麼類型就傳什麼類型,沒有提升和裁減問題。
以下4種情況:
(1).K&R C 函式宣告和K&R C 函數定義:能順利調用,傳遞的參數會進行型別提升。
(2).ANSI C 函式宣告(原型)和ANSI C 函數定義:能順利調用,傳遞的參數為實際參數。
(3).ANSI C 函式宣告(原型)和K&R C 函數定義:如果使用一個較窄的類型就會失敗,傳遞的參數是實際類型,而函數期望接收的是提升後的類型。
(4).K&R C 函式宣告和ANSI C 函數定義:如果使用一個較窄的類型就會失敗,傳遞的參數是提升後的類型,而函數期望接收的是實際類型。

#include <stdio.h>
int main(void)
{
    int c;
    /* The terminal driver is in its ordinary line-at-a-time mode */
    system("stty raw");
    /* Now the terminal driver is in character-at-a-time mode */
    c = getchar();
    system("stty cooked");
    /* The terminal driver is back in line-at-a-time mode */
    return 0;
}

perror可以自動列印當前errno中的錯誤資訊。
strerror可以把errno的值對應為錯誤描述資訊。

8、數組和指標相同的時候:
(1).運算式中的數組名(與聲明不同)被編譯器當作一個指向該數組第一個元素的指標。
(2).數組下標總是與指標的位移量相同。(事實上a[i]在編譯時間總是被編譯器改寫成*(a+i))
(3).在函數參數的聲明中,數組名被編譯器當作指向該數組第一個元素的指標。

9、數組轉化為指標:
Argument is:                                   Matches Formal Param:
array of array       char c[8][10];            char (*c)[10]; pointer to array
array of pointer      char *c[15];            char **c; pointer to pointer
pointer to array    char (*c)[64];            char (*c)[64]; doesn't change    
pointer to pointer     char **c;                char **c; doesn't change

同型指標的加減運算,其值以其指向類型為單位,而非位元組大小。如 struct S{int a; int b}x;
&x.b-&x.a==1而不是4

10、注意:
a[--j + i++] += --y;
等價於:
--j;
--y;
a[j+i] =  a[j+i] + y;
i++;

11、fgets比gets安全

getchar通常實現為宏,返回的是int,等價於getc(stdin);
fgetc和getc相似都是從輸入資料流讀入一個字元,但是getc通常實現為宏,更加高效,所以其實參不能有副作用,因為它可能求值多次。
putchar、fputc和putc同上
ungetc將字元推回指定的輸入資料流,資料流成功使用檔案定位命令(fseek、fsetpos、rewind)時放棄所有推回的字元。
c99:snprintf

12、signal的handler中不應該調用庫函數,因為訊號中斷可能發生在庫函數更新某個資料結構的過程中。
而自己寫的函數則可以清楚所有資料結構的細節。
註:signal不利於可移植性。其handler應儘可能簡單(如列印錯誤資訊,然後馬上exit或者longjmp)才能保證安全性。

================================================================================
《C陷阱與缺陷》
================================================================================
1、優先順序:前述(調用、下標、結構成員選擇,左到右)>單目(尾碼最高,右到左)>雙目(賦以外:左到右)

算(移)關(== !=低)(& ^ |)邏(與>或)條賦(右到左)逗
註:具有相同優先順序的所有運算子具有相同的結合律

2、兩個無符號數沒有溢出問題。但是兩個有符號數a,b的加法運算可能會溢出:可以通過把它們強制轉換為無符號數計算後寫INT_MAX比較
if ((unsigned)a + (unsigned)b > INT_MAX)
或者
if (a > INT_MAX - b)

3、對同一檔案交替執行fwrite和fread,需要在其中間插入fseek函數。
setbuf(stdout, buf); // 設定buf被stdout的輸出緩衝區

4、常見錯誤:
   char c;
   
   (unsigned)c是得不到與c等價的不帶正負號的整數,因為c轉換為不帶正負號的整數前,首先被轉換為int型整數
   
   正確方式:
   (unsigned char)c,因為unsigned char類型的字元轉換為不帶正負號的整數時無需先轉換為int型整數。
   
   無符號數右移,前面都是添0;有符號數右移可能添0也可能添1。
   
5、運算式"23424253525"[i]是合法的,可以用來解決字元集移植性問題,因為不是所有的字元集的數字字元都是按順序排列的。(ansi c是這樣規定的)
ascii的字母表是連續編碼的,但EBCDIC的字母表不是的

6、值位為N的有符號數的表示範圍一般是:-2^(N-1)到2^(N-1)-1,所以負數取負可能會溢出,而正數取負一定不會溢出。

7、除法運算的截斷
q = a / b;
r = a % b;
a、b、q、r之間應該維持的關係:
1).最重要的:q*b+r==a
2).如果改變a的加號或減號,希望也會改變q的符號,但不會改變q的絕對值
3).當b>0時,希望保證r>=0且r<b。
在實際實現中,C語言的定義只保證了性質1),及當a>=0且b>0時,保證|r|<|b|及r>=0.

因此當a<0,b>0時,如果C語言的實現是r>0,那麼可以通過r-=b;q++;來修正到對稱情況。
對稱情況:滿足1), 2)條件

================================================================================
《C語言參考手冊第五版》
================================================================================

1、邏輯來源程式碼,C89:>=509,C99:>=4095
   標識符字元數:C89:>=31,C99:>=63
   外部標識符字元數:C89:>=6且不區別大小寫,C99:>=31且區分大小寫,允許把“通用字元名“當作6個字元(最大為\U0000FFFF)或10個字元(\U00010000以上)

通用字元名: P42
   C語言也支援把通用字元名稱(universal character name)作為使用擴充字元集的方法,而不管C 的實現版本採用何種編碼。可以使用通用字元名稱指定擴充字元,而通用字元名稱就是其Unicode 的值,格式如下:

\u XXXX
或者:
\U XXXXXXXX    

其中XXXX或XXXXXXXX是十六進位標記法的Unicode 碼點(code point,指的是碼集合內的一個碼)。小寫u 後面接著四個十六進位數字,或者大寫的U 後面接著正好八個十六進位數字。如果某個碼點前四個十六進位數字是零,那麼其通用字元名稱寫成\uXXXX或\U0000XXXX都可以。

C99允許在字元(串)型常量中使用通用字元名。

2、注釋大段源碼用宏
#if 0
...
#endif

3、iso646.h檔案中定義了展開一些運算子的宏以及一些不能完全表示美語或英語字元I/O裝置的替換拼字:
如三字母詞。
<% %> : { }
<: :> : [ ]
%:    : #
%:%   : ##

標準C語言保留所有以底線開頭加大寫字母或另一個底線的標識符。
保留以is和to開頭的名稱,以便今後在庫(ctype.h)中增加相關函數。
C的關鍵字不能作為普通標識符但可以作為宏名,因為預先處理發生在編譯分詞的前面。
C99新增關鍵字:_Bool、_Complex、_Imaginary、inline(只能在函式宣告中出現)、restrict
C99新增預定義標識符:__func__
C99新增:long long  對應:ll或LL
C99保留:bool、true、false

4、C99允許十六進位浮點型常量(用字母p而不是e分開小數與指數部分,表示指數的基為2),以前則只有十進位型的。
如:0X0X0.4P2F 表示1.0
1.0+1.0*I是C99複數常量
常見浮點型常量形式:0.、3e1、3.14159、.0、1.0E-3、1e-3、1.0、.00034、2e+9
常量浮點數可以加F、L尾碼,F是double,L是long double

5、mktemp函數的輸入要被修改,所以不能傳指向常量字串的指標,要傳數組或者malloc啥的。

寬字元串和正常字串緊挨著接合得到寬字元串常量,C89不行,C99支援。

CTRL + D :結束輸入(EOF)

6、C99支援帶參數宏中的可變參數表即... ,在宏函數中用__VA_ARGS__代替...要出現的位置

無參數的帶參宏可以類比不帶參數的函數
標準C語言不重新擴充自己的擴充中出現的自身宏,如
#define char unsigned char // 不會遞迴擴充char
標準C語言前置處理器自訂對象宏,都以雙底線開頭和結尾,不能被#undef或者重新定義
標準C語言禁止替換字元(串)型常量中的宏參數。
標準C語言在預先處理時會將注釋替換成空格

P49:
__STDC__(當編程器為ISO相容實現時值為1)與__STDC_VERSION__(實現符合C89增補1,值為199409L,符合C99,值為199901L,否則值是未定義)宏可以編寫與標準C語言和非標準C實現相容的代碼。
__STDC_HOSTED__宏是C99中引入的,用於區別宿主實現(宏值為1)和獨立實現(宏值為0,大部分庫函數不能用)。

7、#inlcude中的檔案名稱形式只能是:字母與數字(以字母開頭).一個字母
C89:點號前最多5個符號, C99:點號前最多8個符號
#include命令的包含嵌套至少支援8級,C99要求至少15級

8、#if或#elif的常量運算式中出現未定義宏名,則換成整數常量0.
#line 10 test.c // 指定line所在檔案名稱為test.c的第10行。

9、#pragma 雜注 // 雜注是不會宏擴充的,內建標準雜注在C99中要在前面加 STDC
如: #pragma STDC FENV_ACCESS ON

_Pragma運算子是C99新增的,是一個運算式,後接字串常量,支援逸出字元。
_Pragma("STDC FENV_ACCESS ON") //同上式是一樣的,且會擴開宏

10、標準C才有 #error tokens(可以多個) // tokens可以是字串常量(宏名不擴充)也可以不用雙引號,這樣宏會被擴充。

11、C++使用C89前置處理器,__cplusplus是C++實現的,__STDC__在C++中定義與否取決於實現。

12、聲明的組成部分:儲存類說明符(quto、register、extern、static 、typedef)、類型說明符(type)與限定符(const、volatile、restrict)、函數說明符、聲明符、初始化語句。
註:禁止計算register變數的地址

####C語言中,(代碼塊、檔案塊)塊開頭的聲明可以隱藏塊外的同名聲明。但同一個範圍中的同名聲明是錯誤的,叫做衝突。####
C99不允許函數調用隱式聲明函數。
C99允許塊中任何地方聲明。

13、C語言有5種命名空間P68:預先處理宏名;語句標號(如goto後的那種,總是後面跟一個冒號);結構、聯合、枚舉標誌;成員名(用在.或->之後,結構體、聯合體);其它名稱(變數、函數、typedef名稱、枚舉常量)。

14、goto標號之前的auto變數的初始化操作可能不會被執行。且auto塊級標識符的值不從塊的上次傳遞到下次執行中。P205

goto L; /* 在C中合法,但不提倡,在C++中非法(C++不能繞過帶初始化的聲明而跳轉入複合陳述式) */
...
{
    static int vector[10] = {0};
    int sum = 0; // 在goto 轉到下句時,這裡的sum是不會初始化的。
L:
    ...
}

15、volatile:編譯器這個變數易變。告訴編譯器在使用時不要使用在寄存器中備份而是重新去讀一遍RAM裡的值。
有volatie修飾的變數,每次操作時遵循下面動作:
從記憶體取值 ---> 放入寄存器 ----> 操作 ---->寫回記憶體
沒有volatie修飾的變數,操作可能遵循(可能就是不是所有情況都如此):
從記憶體取值 ---> 放入寄存器 ----> 第一次操作 -----> 第二次操作(此時仍操作寄存器中的值) …… ---->第N次操作 ---->寫回記憶體

C99:restrict用來修飾指標,即只有被其修飾的指標可以修改指向的內容,其它指向相同對象的指標的任何行為都是未定義的(這樣編譯器就可以放心地對restrict指標進行最佳化)。兩個限制指標或者一個限制指標和一個非限制指標可以引用同一個對象,條件是該對象在限制指標存在期間不被修改。
如:memcpy函數要求源和目標記憶體區不重疊,那麼像如下聲明函數即可達到目的:
void * memcpy(void * restrict s1, const void * restrict s2, size_t n);
這樣如果s1和s2有重疊記憶體區的話就會違背聲明的restrict

16、C99中,結構的最後一個成員可以是靈活數組,不聲明長度。(注n維數組必須把右邊n-1維的長度以常量方式寫出)。
C99變長數組:不能是static、extern型,且不能作為結構成員或聯合成員。但是可變修改類型(如變長數組指標)可以用static修飾。
typedef聲明使用變長數組時,長度運算式只在聲明時求值一次。
變長數組或可變修改類型可以作函數參數類型:如果數組長度也是參數,則必須出現在數組參數之前。調用具有變長數組參數的函數時,數組參數的維長應符合函數參數聲明,否則結果不確定。
在函數原型聲明(而不是函數定義)中,可用[*]表示變長數組維度,但在函數定義時要提供非常量運算式。(因為在原型聲明中任何非常量維度都是和*一樣處理)

17、外部名稱:一組同名聲明中,只允許一個是定義聲明,其餘的都是它的引用聲明。定義聲明滿足以下任何一條即可:
1)初始化語句(C標準採用) 2)省略儲存類型(無extern)
建議:外部變數的定義點應在源檔案中,並省略extern且包含初始化語句。

18、C++相容性:
嵌套定義的struct或union在標準C中,內部定義對外是可見的,而C++的不可見。

P97 具有const限定符而沒有顯示儲存類型說明的頂層聲明在C++被認為是static的,而在C中是extern的。

C++頂層變數沒有試探性定義,C中的試探性定義在C++中被看成實際定義。
如:
int i;
..
int i; // 在C中有效,在C++中會造成重複定義

19、C99支援擴充整數類型名

20、 if (ip != NULL)...比if (ip)...更好,因為NULL不一定在所有類型指標的null實現上都是值0(註:NULL是對象指標值,長度可能不適用於函數指標)

21、(位段非常不利於移植,跟硬體直接相關)結構體的位欄位成員通常不在機器的可定址邊界上,困此可能無法建立指向位欄位的指標,所以C語言沒有提供指向位欄位的指標;可以放置無名位欄位,提供相鄰成員之間的填充(對無名欄位指定長度0有特殊含義——表示儲存前一位欄位的字中不能再放置更多的位欄位,下一個位欄位只能放到下一個字中)。
結構不能包含自身類型的執行個體,但可以包含自身類型的指標。
C99中,結構的最後一個成員可以是不完整數群組類型,稱為靈活數群組成員,使得結構長度可以在運行時改變;在C99以前是在結構最後一個成員聲明為只含一個元素的數組,如char s[1],現在要聲明為char s[],在sizeof計算該結構大小時,忽略s的存在。

22、聯合成員在標準C中可以是位欄位,傳統C中則不能。

23、extern int fun(void); // 有傳回值
    (void)fun(); // 顯式放棄傳回值
    
24、typedef定義的類型(此類型並不是新類型,而是原類型的同義字)前不能加其它類型說明符(如unsigned等),但可加類型限定符(如const, restrict, volatile等)。
用typedef定義的函數類型不能繼承函數性,故只能用過定義函數指標,指標數組等。如下:
typedef int func();
func * f_p, * f_array[10]; // 正確
func fun ,fun_array[10];   // 錯誤

25、C語言中不要求整型長度很大,使它能夠表示指標,但C語言編程人員通常假設long類型長度足夠表示指標。C99中,inttypes.h可能定義整數型別intptr_t與uintptr_t,保證整數類型的長度跢表示指標。

26、類型轉換:
整型-->整型:
帶符號(短)-->無符號(長):先位擴充為帶符號的,再轉為無符號的。
無符號或帶符號(長)-->無符號(短):截去高位。
指標-->整型:把指標當作長度等於指標長度的不帶正負號的整數,然後再轉為目標類型。
複數-->實數:放棄虛部
虛數<-->實數:結果都為0
任何-->void:讓讀者知道編程人員故意忽略運算式的值。
指標-->_Bool:null指標為0,否則為1

型別提升(一元轉換):(標準C)
float:不轉(傳統C轉為double)
階>=int的整型:無轉換
階<int的帶符號整型:轉為int
階<int的無符號整型:值可以用int表示的轉為int,不能的轉為unsigned int,(傳統C都轉為unsigned int)

二元轉換:(假設每個運算元都已進行一元轉換)
運算元一                運算元二                標準C            傳統C
long double             *實數類型            long double            不適用
double                *實數類型                double            同標準
float                *實數類型                float            double
*無符號類型            *無符號類型     階較大的無符號類型            同標準
*帶符號類型            *帶符號類型     階較大的帶符號類型            同標準
*無符號類型    階較小或相等的帶符號類型            無符號類型        同標準
*無符號類型        階較大的帶符號類型,能      帶符號類型    帶符號類型的無符號版本
                表示所有無符號類型值
*無符號類型        階較大的帶符號類型,不能        帶符號類型的        同標準
                表示所有無符號類型值        無符號版本
*其它類型                *其它類型                不轉換            同標準

函數參數類型轉換:
無原型控制或形參為...的部分:進行一元轉換,但是float都提升為double(因此在格式化字串中%f對應的類型為double,%Lf對應的類型為long double,而沒有float的對應格式字元,因此%lf是未定義行為,只是在C99中允許lf與f同義)

27、sizeof(函數名)無效,sizeof(void)無效,但值 == 1
利用null指標獲得結構成員位移量,標準C沒有顯式地允許或禁止;
#define OFFSET(type, field) \
    ((size_t)&((type *)0)->field) // OFFSET宏類似於stddef.h檔案中的offsetof宏
    
28、C99引入了複合字面值(左值型常量):即在普通字面值前面加上類型轉換。
複合字面值出現在檔案頂部,則是外部類型的,且初始設定式列表只能包含常量值。
char * temp1 = (char []){"4242423"}; // temp1指向的字串可修改
char * temp2 = "daqewrw";

29、因為有的C實現會忽略“縮小”數值作用的類型轉換,為了保證最大的可移植性,編程人員應自己實現截尾數值:將其放在變數中,或對整數進行顯式掩碼運算,而不是依賴於類型縮小轉換。
如(double)(float)3.1415926535897932384; // 有的實現會忽略float轉換,從而沒有減小值的精度。

30、sizeof接運算式時,只在編譯時間確定其類型,也不會去求值運算式。
int i = 0;
sizeof(i++); // 這裡的i++不會執行
sizeof接數組時,如果數組長度影響結果,則總是完全求值數組長度運算式,而其不影響結果時,沒有確定是否求值長度運算式。
sizeof接類型名(如struct s),則副作用為聲明了這個類型。// C++中無效

31、標準C中:-e是0-(e)的縮寫,+e是0+(e)的縮寫。
不同實現可能對帶正負號的整數使用不同表示方法,因此對帶符號數按位取反~的結果可能無法移植,為了保持可移植性,只對無符號數作~運算。
無符號數e:~e的值為MAX-e

32、運算子
實數都可以做++,--運算。
%兩邊只能接整型數,div,ldiv,fmod可以用於浮點數。
位元運算符用於整型數(只要用於無符號數才具有可移植性)
關係運算子中,浮點數可能有NaN的情況,這樣會造成“無效”異常,此時關係的值為false
結構和等位型別不能比較相等性,即使這些關係可以賦值也不行。(因為對齊造成的空洞可能包含任意值,要補償這些空洞以比較相等性會帶來巨大的開銷)

33、常量運算式
宏常量:類型為C99:intmax_t、uintmax_t或C89:long、unsigned long,不能做類型轉換也不能sizeof運算。
整型常量(整數、字元、枚舉):可以sizeof,也可以類型轉換

34、編譯器對含 二元運算子+、*、&、^、|的運算式的重新布置(按結合性和交換性)的結果是不確定的。

35、P254:標準C中,如果連續序列點之間對一個對象修改多次,則結果是未定義的。
序列點:程式執行序列中發生前面執行流的所有副作用的點,此後不再發生任何副作用(副作用產生的運算包括賦值和函數調用)。
*完整運算式結束時,即初始設定式、運算式語句、return語句中的運算式、條件迭代或switch語句中的控製表達式(包括for語句中的每個運算式)之後。
*&&、||、?:、逗號運算子的第一個運算元之後。
*函數調用運算式中求值參數和函數運算式之後。

36、switch後不一定要是複合陳述式,case和default標號不一定要放在內層的最頂層,可以嵌套在其它複合陳述式的中間。
continue語句對switch語句無效。

37、C99函式宣告中:
int f(int x[const 10]); // x視為int * const類型
int g(int const y[10]); // y視為int const *類型

38、內聯
任何靜態函數都可以指定為inline。(因為內聯聲明和函數定義必須在同一單元才能正常內聯)
外部函數可採用內聯定義的方式實現正常內聯:
// 檔案square.h,實現Inline definition
inline double square(doulbe x) // 必須不用extern聲明
{
    return x*x;
}

// 檔案square.c
#include "square.h"
extern inline square(double x); // force an external definition using the inline code

39、C++中main函數不能遞迴調用,也不能取得其地址。

40、獨立實現與宿主實現必有的核心庫:
float.h、iso646.h、limits.h、stdarg.h、stdbool.h、stddef.h、stdint.h

41、可變參函數實現
標準C:stdarg.h
參數列表中至少含一個固定參數param,供va_start使用
void fun(type param, ...)
{
    va_list ap;
    
    va_start(ap, param); // 獲得param後的地址(第一個可變參數)放在ap內部指標中
    // 迴圈處理va_arg
    va_arg(ap, any_type);
    ...
    va_end(ap);
}

傳統C:vararg.h
參數列表必須是全可變參
void fun(va_alist)
va_dcl // 傳統函數參數聲明,不加;以防止空參數
{
    va_list ap;
    
    va_start(ap); // 獲得第一個參數地址放到ap內部指標中
    
    // 迴圈處理va_arg
    va_arg(ap, any_type);
    ...
    va_end(ap);
}

42、資料流:文字資料流+二進位流
文字資料流:由分成行的字元序列組成,每行由\n結束。因此在不同實現中,都必須把文字檔中換行的實際表示映射為標準的\n
二進位流:
fclose在出錯時返回EOF,否則返回0。
exit函數會重新整理輸出緩衝區。
freopen用於重新導向stream到新的資料流,如將stdin、stdout、stderr重新關聯到另一檔案.
輸出和輸入交替進行,則中間須調用:fsetpos、fseek、rewind、fflush,這些操作會清空所有內部緩衝區。
fwide用於設定與測試流定向:根據stream為面向寬字元、面向位元組、無定向,函數返回正值、負值、0。當流定向(寬字元或位元組)以後就不受setlocale影響,也不能再重新定向。定向時是受當前的locale影響的。
setvbuf()的參數bufmode:_IOFBF(資料流完全緩衝)、_IOLBF(寫入分行符號或緩衝區滿時重新整理緩衝區)、_IONBF(資料流不緩衝)
stderr不帶緩衝,stdin、stdout是行緩衝
setbuf(stream, buf); // 等價於下句
((buf==NULL) ?
(void)setvbuf(stream,NULL,_IONBF,0) :
(void)setvbuf(stream,buf,_IOFBF,BUFSIZ))

ftell和fseek:不能用於寬字元
對於二進位流:ftell返迴文件位置指標當前位置相對於檔案首的位移位元組數,該數值適用於fseek的第二個參數(此時其第三個參數應當是SEEK_SET)。而文字資料流ftell返回的數值跟實現有關。
標準不要求對二進位流的SEEK_END提供有意義的支援。
// 文字資料流只提供以下有限的調用形式
fseek(stream, 0L, SEEK_SET);         // 檔案開頭
fseek(stream, 0L, SEEK_CUR);         // 同一位置
fseek(stream, 0L, SEEK_END);         // 檔案末尾
fseek(stream, ftell_pos, SEEK_SET);  // 在上次對stream調用ftell返回的位置

fgetpos和fsetpos:用於寬字元流定位
wint_t用來存放wchar_t的所有值以及WEOF。

43、格式字串說明P277
#用於o、x。。輸出八進位、十六進位首碼。

44、FP_NORMAL 正常浮點數(規格化),FP_SUBNORMAL 精度降低的浮點數(次規格化)
nan(char * p); // 若p指向的字串是數字則返回其浮點值,否則返回0

P442:如果兩個浮點數值中的一個或兩個為NaN,則它們是無序的,對無序值使用C語言的比較運算
符時,會產生“無效”浮點數異常。
用isunordered, isgreater, isgreaterequal, isless, islessequal, islessgreater宏可以避免異常問題。除第一個在無充時返回真,其餘在無序時返回0

45、sleep(), alarm()不是標準C函數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.