以下轉自一位學長的C語言筆記。。。。
有些是從其他資料裡找的。希望對大家有用。
1.運算式的值:運算式有運算式的值,它是無名的,短暫的。
2.case 常量(不可以是運算)
3.資料區(棧,靜態區,堆)和代碼區
4.sizeof與數組(下邊的說明不考慮機器或者平台等因素).
一.
int i[10];
int *p
p=i;
上邊sizeof(i)為40.但是sizeof(p)是4.原因:數組名不是指標.
二.
數組的大小:
sizeof(i)/sizeof(i[0]);
前者為40,後者為4,於是就是10個.
三.
如果把數組名作為參數傳給函數,那麼函數的形參一定是指標了.於是在函數內就無法算出來數組的大小了.因為sizeof(這個參數)是4.所以我覺得很多函數需要傳size進去.而不是函數內計算大小.
5.const
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前兩個的作用是一樣:a是一個常整型數。第三個意味著a是一個指向常整型數的指標(也就是,整型數是不可修改的,但指標可以)。第四個意思a是一個指向整型數的常指標(也就是說,指標指向的整型數是可以修改的,但指標是不可修改的)。最後一個意味著a是一個指向常整型數的常指標(也就是說,指標和所指向的整型數都是不可修改的)。
6.typedef的陷阱:
typedef char * pstr;
/*若我們這樣使用:*/
int mystrcmp(const pstr, const pstr);
/*我們希望表達的是:*/
int mystrcmp( const char*, const char* );
/*(即 2個指向常量的char指標)*/
/*可它被解釋為:
int mystrcmp( char* const, char* const ) ;
/*(2個指向char的常指標)*/
分析:
const修飾的是pstr,而pstr被定義為char *,而不是char。
應修改為:
typedef const char* cpstr;
int myctrcmp( cpstr, cpstr);
7.複雜指標解析
比如int (*(*func)[5][6])[7][8];
func是指向三維數組的指標,這類數組的大元素是具有5X6個int元素的二維數組,而指向三維數組的指標又是另一個三維指標數組的元素。
8.為什麼會有匿名結構體呢?
為了不想讓其他人再聲明該類型的變數.
9.struct的大小
struct{
char ch;
int i;
float f;
char ch2;
}a;
struct{
char ch;
char ch2;
float f;
int i;
}b;
sizeof(a)==16
sizeof(b)==12
為什麼成員一樣,但是順序不同,占的空間不一樣呢?
a的儲存:ch,_,_,_(補了三個位元組),i,float f,ch2,_,_,_
b的儲存:ch,ch2,_,_f,i
得出結論,用成員中占最大位元組的類型為單位,然後填充變數.要是填得下就填,填不下就新找個該單位填.如b的儲存ch,ch2,放到四位元組的記憶體,還空兩個位置.
再一個結論:聲明struct 的時候要注意成員的先後順序.
10.malloc和calloc
一.malloc(大小),calloc(個數,每個的大小)用哪個更好?
用calloc好.
原因:因為大小雖然可以個數*每個的大小得出來.但是要使這個值很大很大怎麼辦?所以分開寫(calloc)比計算這個大小(malloc)要好.這個原因是個人認為.但是應該用calloc的結論非個人認為.
二.malloc(0)
雖然申請0大小的記憶體,但是結果是malloc返回的結果並不等於NULL,就是說它是有返回記憶體的.有多大?忘了...
11.FILE指標
一.
當使用檔案指標的時候,指標指的是一個結構體,該結構體除了包含各種各樣的和該檔案相關的資訊,還指著一個buffer,而該buffer和檔案又有一個有時讀入有時寫入的流.
就是說,fopen,不單單返回了一個檔案指標,而是構建了整個讀取檔案的環境.
二.檔案的文本方式與二進位方式.
假設123,文本方式用每個字的ASCII值表示'49','50','51'
二進位方式則一個位元組就可以表示了1111011.
使用場合:一個是方便人類,一個方便電腦
另外,附一個ASCII編碼錶的連結http://www.blabla.cn/ref/ascii.html
12.預先處理
一.
不要忽視宏定義中的空格:
#define f (x) (x) +1 //實際上是把f 定義成了(x) (x)+1
對於不帶參的宏,若宏值多於一項,一定要使用括弧
#define MAX (M+N)
要給每個參數加上括弧,否則可能影響計算的優先順序
#define abs(x) (x>=0)?x:-x
z =abs(a+b); /*相當於 z= (a+b>=0)?a+b:-a+b
//修改後:
#define abs(x) ((x)>=0?(x): -(x))
盡量用typedef而不是宏定義去定義類型。
二.
用typedef和宏都可以定義新類型.那麼哪個更好.
答:typedef更好.
原因:int* a,b; a和b的類型,a是指標,b是整形.同樣的,用宏定義出來的新類型,使用的時候也會出現這樣不知道是新類型指標還是新類型的情況.
三.
由於標頭檔包含可以嵌套,那麼C檔案就有可能多次包含同一個標頭檔,就可能出現重複定義的問題
通過條件編譯開關來避免重複包含
例如
#ifndef __headerfileXXX__
#define __headerfileXXX__
…
檔案內容
…
#endif
四.
#include “xxxx.h”
到本級目錄去找和到系統預設目錄去找。
#include <xxxx.h>
到系統預設目錄。
13.常用庫函數(總結略,舉assert為例)
診斷函數(assert.h)
測試一個條件test ,當結果為假時使程式終止,為真時沒反應 。
不要將assert函數用於程式的執行邏輯中,它僅用於調試。
即:程式的 if( 條件 ) 語句不可用 assert( 條件 ) 來替代。
如果在程式開始加入代碼:
#define NDEBUG
則該程式中的assert函數全部失效,不必逐一刪除。(有待驗證.因為我實驗了怎麼不管用)
14.關鍵字static的作用是什嗎?
在C語言中,關鍵字static有三個明顯的作用:
在函數體,一個被聲明為靜態變數在這一函數被調用過程中維持其值不變。
在模組內(但在函數體外),一個被聲明為靜態變數可以被模組內所用函數訪問,但不能被模組外其它函數訪問。它是一個本地的全域變數。
在模組內,一個被聲明為靜態函數只可被這一模組內的其它函數調用。那就是,這個函數被限制在聲明它的模組的本地範圍內使用。
15.竟然允許這樣使用指標:
#include "stdio.h"
void main()
{
int a = 1234;
// 0x0012ff7c是&a的值。
int *p =( (int*)0x0012ff7c );
printf("&a = %x/n",&a);
printf("a = %d/n*p = %d/n",a,*p);
}
16.最後.留個題目.
不申請新的空間,對數組進行逆序.