01 C語言中的一些細節

1(網絡編程模型)
{
	網絡編程分爲B / S模型與C / S模型,B指Browsers,C指Clients
		B / S模型中,走的應用層協議是HTTP協議,走的是行業標準化的報文
		C / S模型中,C與S之間走的應用層協議是基於TCP / UDP的自定義的協議,走的是自定義的報文;
}
2(業務模塊的功能抽象)
{
	客戶端				接口		服務器;
	1:客戶端初始化環境		<-->		??;
	2:客戶端發報文			<-->		??;
	3:客戶端收報文			<-->		??;
	4:客戶端銷燬環境			<-->		??;

	客戶端調用接口,
}
3(頭文件重複包含的解決)
{
#ifndef _SOMEH__
#define _SOMEH__
	內容
#endif
}
4(VS快捷鍵)
{
	Shift + Del;		// 快速刪除一行
	Ctrl + U;		// 讓單詞從小寫變大寫
	Shift + Ctrl + U;	// 讓單詞從大寫變小寫
	F9;			// 加斷點
}
5(數組名做函數參數,參數會退化爲指針)
{
	若有;
	int a[10];
	int num = sizeof(a);	// num值爲整個數組所佔的空間

	若有一函數定義爲	fun(int a[267]), 如下調用;

	fun(a)
	{
		int num = sizeof(a);	// num值既不是nums[10]的空間,也不是nums[267]的空間,而是一個int*型指針變量的空間,因爲在傳參至函數中時,數組名會退化爲指針類型
	}

	並且,無論形參中數組的容量寫多少,都會退化爲指針;

	fun(int nums[267]);		// 實質傳進函數的是int * 類型
	fun(int nums[]);		// 同上
	fun(int nums[][20]);		// 實質上傳的是int [20]型的指針

	對於fun(int nums[][20]),比較特殊,但其實也不特殊,實質上傳遞的也是一個指針,指針的類型是int[20] *型的,即把int[20]當作一個類型的話,即就是這個類型的指針;
	換句話說,這樣傳二維數組時,高層數組的容量是不知道的,因爲只傳了一個指針,而低層數組則被當成了數據類型,函數本身認爲低層數組容量是20;

	在函數的形參列表中一旦出現*或[],默唸三遍“只傳值,不傳類型”
}
6(一級指針的第一座大山:指向數組名的指針)
{
	int a[40];
	printf("%d\n%d\n", a, &a);			// 兩值相同
	printf("%d\n%d\n", a + 1, &a + 1);		// a+1步進4,&a+1步進40

	a代表數組名,&a代表該a[40]整個數組的地址,其值都等於a[40]數組在內存中的首地址;
	但a + 1是以數組內元素的空間步進的,而&a + 1則是以整個數組的容量步進的;

	即a本身的類型是int *, 而&a本身是int[40] * 類型;

	即int a[20]與int a[40]是兩種不同的簡單數據類型,所佔容量不一樣,請看7
}
7(數據類型的本質)
{
	數據類型可理解爲創建變量的模具,本質是固定大小內存塊的別名;
	爲數據指定類型的作用在於,在編譯器創建對象的時候,編譯器知道該爲該變量分配多大的內存;
	可以通過sizeof()函數求出數據類型的大小,以字節爲單位返回unsigned int類型返回值

}
8(void *類型與數據類型封裝)
{
	void * p;
	int a;
	double b;
	struct student c;
	p = &a;
	p = &b;
	p = &c;
	以上語句都合法

	int cltSocket_init(void ** handle);
	void *是API作者用來封裝函數的參數類型的作法;

	void指針的用法,主要是用於將一個不知道數據類型(或者不需要關心其類型)的指針傳進函數,只是用來傳首地址的!!其次是將一個內存地址傳出函數作爲返回值,如下;

	void * getTeacher()
	{
		void * p = malloc(199);
		reutrn p;
	}
}
9(函數本身是一種數據類型嗎?)
{
	要回答這個問題,要認識到函數是什麼;
	從程序設計的角度來講,函數是一個描述某種過程的代碼集合,是對一個過程的描述;
	但是,從內存角度來講,一個自定義函數聲明瞭它自己的時候,程序在運行時就要存儲該函數的代碼,函數本身在靜態區要佔據一定的內存,所以從這個角度講,函數本身也是一種數據類型;
	而函數名本身,就是指向這個函數本身在內存中存儲區域的一個指針;

	如;
	double somefunction(double x);		// 某個二維數學函數的求值函數
	double calculus(double low, double high, double(*fun)(double));
	這個微積分函數的第三個參數就是一個函數指針,即要傳入一個函數的地址;
	函數指針當作形參書寫時以以下格式書寫:
		返回值類型(*函數名)(參數類型);
	如上例中,代表要傳入calculus的第三個參數的,是一個【有double返回值,接受一個double類型參數】的函數的地址,調用時直接傳入函數名即可,如:
		double sum = calculus(5.5, 7.7, somefunction);

}
10(變量與常量的實質)
{
	既能讀又能寫的一塊內存區域,叫做內存對象,就稱爲變量;
	若一旦初始化之後,該內存區域的內容便不可更改,則稱其爲常量;

	變量的本質就是該內存塊的起始地址與該內存塊的容量的記錄器,即一塊內存空間的別名;
	代碼中的變量,只是一個標號,如定義了int a = 10; 程序只存儲10,但不會存儲字母a,這個別名只對人有用,只是爲了讓人去指定一個固定的內存塊,即變量只存在於代碼中,代碼一經編譯,所謂的a就不見了,對於機器來說,這沒有意義,a只對人有意義;
}
11(類型的別名與內存空間/變量的別名)
{
	類型的別名,用typedef來起;
	而變量的別名,在C語言中是沒有的,在C++中有&操作符來取別名,即爲C++中的引用;

	int a = 10;
	int * p = &a;

	*p不能算是變量a的別名,因爲*是運算符,p是一個變量,*p是一個表達式
}

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