Something About Expert C Programming

  1. 字符串的自動合併程序員

int main( )
{
	char *Str[] = {"abc" "def"};
	printf( "%s\n", Str[0] );
	system("pause");
	return 0;
}

輸出結果:abcdef編程

ANSI C規定相鄰的兩個字符串合併成一個字符串,必須注意在兩個字符串之間添加「 ,」!但多餘的「 ,」卻並無什麼影響!數組


2.sizeof 的操做數ide

int main( )
{
	int b = 2;
	int *p = &b;
	int a = 3 *sizeof  *p;
	printf( "%d\n", a );
	system( "pause" );
	return 0;
}

輸出結果:12函數

在上述程序中sizeof後面的操做數是(*p)因此是計算了 p指向的數據的數據類型的長度。性能

此處要注意運算符的優先級問題spa

tips: .高於* []高於* ()高於*  ==和!=高於位操做和賦值 算數高於移位 逗號的優先級最低指針


3.結合性ip

    1)全部賦值運算都具備右結合性  內存

int main( )
	{
		int a, b = 1, c = 2;
		a = b = c;
		printf( "%d\n", a );
		system( "pause" );
		return 0;
	}


    輸出結果:2

    c賦值給b ,b賦值給c。


4.空格的誤用

int main( )
{
	char a[] = "Hi,I am a\ 
		long string!";
	printf( "%d\n", a );
	system( "pause" );
	return 0;
}

此處在轉義符的後面添加了空格,語法錯誤編譯不能經過。這樣的錯誤很難被發現,儘可能避免!


5.最大一口策略

int main( )
{
	int a = 0;
	int b = 0;
	b = a+++3;
	printf( "%d,%d\n", b ,a);
	system( "pause" );
	return 0;
}

輸出結果:3,1

結合性是a++ + 3

int main( )
{
	int *a = NULL;
	int *b = NULL;
	int c=*b/ *a;
	printf( "%d,%d\n", b ,a);
	system( "pause" );
	return 0;
}

在「/」和「*」之間必須有空格,否則編譯器將後面的內容自動解析稱爲註釋!


6.優先級規則分析案列

char *const *(*next)();

解釋爲:next是一個指向函數的指針,該函數的返回值是char *const


7.內存泄漏

內存泄漏:顧名思義,內存泄漏是因爲咱們使用了內存卻沒有收回形成的,

 這樣的問題十分容易下降咱們計算機的性能,而且泄漏的內存

 每每大於你忘記釋放的數據的大小,由於malloc分配的內存一般

 會圓整爲下一個大於申請數量的2的整數次方。

*同時,咱們必需要避免內存損壞,即釋放、改寫仍在使用的內存。


8.段錯誤

1).解引用非法值的指針引發

	//引發一個段錯誤
	int main()
	{
		int *p=0;
		*p = 7; 
		system( "pause" );
		return 0;
	}

2).若是未初始化的指針剛好具備未對齊的值,會引發總線錯誤而不是段錯誤。

3).解引用一個空指針一樣引發段錯誤(經常因爲系統返回一個空指針而程序員不加判斷直接使用形成)

4).用完了堆棧或者堆空間

引發段錯誤常見編程問題:1.壞指針值錯誤:在指針賦值以前就用它來引用內存或在釋放以後仍然使用該指針

2.改寫錯誤:越界寫入數據

3.指針釋放:屢次釋放或者釋放一塊不屬於你的內存

注意:鏈表中元素的釋放會常常引發此問題,咱們必須用一個臨時變量來保存下一次的地址纔可以進行釋放

9.類型轉換

a.類型提高

        printf("%d\n",sizeof'A');

此程序的輸出結果爲4,在此char型自動被提高爲int型。事實上計算機將char和short提高爲整型,將float提高成double型

整型提高規則:每一個變量的值被提高爲int型的長度,而後對這些值進行計算,最後再對結果進行裁剪。

若是兩個char型的加法運算結果沒有溢出,那麼在實際執行時只須要產生char類型的運算結果,能夠省略提高。

	float f1,f2;
	double d;
	....
	f1 = f2*d;

若是編譯器能夠肯定用float運算的結果和用double運算的結果相同,那麼編譯器也可使用float類型運算。


C語言中的類型提高

char-->int 位段-->int 

enum-->int unsigned 

char-->int short-->int 

unsigned short-->int

float-->int 

任何數組-->相應類型的指針

float-->int 任何數組-->相應類型的指針

***參數也會進行提高,可是若是使用了函數原型,那麼缺省的提高將不會發生!


10.有限狀態機

有限狀態機用於有限數量子程序的發展變化每一個程序處理並選擇下一個應該進入的狀態

例如:註釋轉換

基本思路:用一張表來保存所可能的狀態,並列出進入每一個狀態以後須要執行的動做,通常的最後一個動做用於決定你將要進入哪一個狀態。

咱們能夠經過函數指針數組來調用函數

	   extern int a() ,b(),c(),d();
	   int (*State[])()={a,b,c,d};
	   //能夠經過調用數組中的指針來調用函數
	   (*State[i])();

固然,switch也是一個不錯的實現機制


11.數組和指針的規則

a.「表達式中的數組名」至關於指針

b.C語言把數組的下標做爲指針的偏移量

c.做爲函數參數的數組名至關於指針

 關於這一點咱們應該明白是出於對效率的考慮,相似的函數的返回值必定不能是一個數組,而是一個指向該數組的指針

Tips:爲了保證一致性咱們的定義和聲明的形式必須保持一致

請嘗試一下代碼:

char ga[] = "abcdefghi";
void my_array( char ca[10] )
{
	printf( "數組的地址是:%#x \n",&ca);
	printf( "數組第一個元素的地址:%#x\n",&(ca[0]) );
	printf( "數組第二個元素的地址是:%#x\n",&(ca[1]) );
	printf( "++數組名獲得的地址是:%#x\n",&(ca[1]) );
}
void my_pointer( char *pa )
{
	printf( "指針的地址是:%#x\n",&pa);
	printf( "指針偏移0的地址是:%#x\n", &(pa[0]) );
	printf( "指針偏移1的地址是:%#x\n", &(pa[1]) );
	printf( "++指針的地址是:%#x\n", ++pa );
}
int main( )
{
	printf( "全局變量數組的地址爲:%#x\n",&ga );
	printf( "全局變量數組ga[0]的地址爲:%#x\n", &(ga[0]) );
	printf( "全局變量數組ga[1]的地址爲:%#x\n", &(ga[1]) );
	my_array( ga );
	my_pointer( ga );
	system( "pause" );
	return 0;
}

在輸出的結果裏咱們發現:在函數裏數組的地址和數組的第一個參數的地址不同!

**在C語言中,咱們沒法向一個函數傳遞一個長度不肯定的多維數組,你必須提供給它除了最左邊一維之外全部的長度

在數組做爲參數時:

1.一維數組 —— 須要包含一個計數值來方便咱們檢測是否越界訪問

2.二維數組 —— 不能直接傳遞給函數,能夠改爲一個指向向量的指針數組來傳參

        eg: char **myarray;

3.三維或更多維數組 —— 沒法使用。必須將之分解成幾個維度更小的數組。

相關文章
相關標籤/搜索