1.寫出下面代碼的運行結果
? ? int array[5] = {1, 2, 3, 4, 5};int *p = &array[0];
? ? int max = Max(*p++, 1);
? ? printf("%d ,%d", max, *p);
? ? 答案:1,2
? ? #define Max(X, Y) ((X) > (Y) ? (X) : (Y)) 對于++、--在宏定義當中使用最容易產生副作用
2.define 定義的宏和const 定義的常量的區別
? ? ?#define定義的宏,程序在預處理階段將宏定義內容僅進行了替換,因此程序運行時,常量表中沒有用 ? ? #define所定義的宏,系統并不會為它分配內存,而且在編譯時不會檢查數據類型,出錯的概率要大一些。
? ? const 定義的常量,在程序運行的時候是存放在常量表中,系統會為它分配內存,而且在編譯時進行數據類型檢查。
? ? #define 定義的表達式時要注意“邊緣效應”,例如如下定義:
? ? #define N 2+3 // 我們預想的 N 值是5,我們這樣使用N
? ? int a = N / 2 ; // 我們預想的 a 的值是2.5,可實際上 a 的值是3.5
3.strcpy , memcpy , sprintf 使用注意事項
? ? strcpy 是一個字符串拷貝函數,原型為:strcpy ( char destr, const char str ) ,結束標志為?‘\0’ ,由于拷貝的長度不是我們控制的,所以拷貝容易出錯。
? ? Memcpy 是一個內存拷貝函數,函數原型為:memcpy (char destrc , const char str, unsigned int len ),講長度為 len 的一段內存,從str 拷貝到 destrc 中去,這個函數的長度可控,但是會有內存讀寫錯誤,(比如 len 的長度大于要拷貝的空間或者目的空間)
? ? sprintf 是一個格式化函數,將一段數據從通過特定的格式,格式化到一個字符串緩沖區中去。sprintf 格式化的函數的長度不可控制,有可能格式化后的字符串會超出緩沖區的大小,造成溢出。
4.static 關鍵字的作用
? ? · 隱藏。編譯多個文件時,所有未加 static 前綴的全局變量和函數都全局可見。
? ? · 保持變量內容的持久。全局變量和 static 變量都存儲在靜態存儲區,程序開始運行就初始化,只初始化一次。static 控制了變量的作用范圍。
? ? · 默認初始化為0。在靜態數據區,內存中的所有字節都是0x00,全局變量和 static 變量都是默認初始化為0。
5.static 關鍵字的區別
? ? · 全局變量方面:static 全局變量只初始化一次,防止在其他文件單元中被引用;
? ? · 局部變量方面:static 局部變量只被初始化一次,下一次依據上一次結果的值;
? ? · 函數方面 :static 函數在內存中只有一份,普通函數在每個被調用中維持一份拷貝
6.關鍵字 const
? ? · int const a ;const int a :作用一樣,a 是一個常整型數
? ? · int const * a ;const int * a :a 是一個指向常整型數的指針(整型數不可變,指針可變)
? ? · int * const a :a 是一個指向整型數的常指針(整型數可變,指針不可變)
? ? · int const *const a :是一個指向常整型數的常指針(指針、整型數均不可變)
7.堆和棧
? ? · 管理方式:
? ? ? ? 棧:由編譯器自動管理,無需我們手工控制
? ? ? ? 堆:釋放工作由程序員控制,容易產生內存泄漏(memory leak)。
? ? · 申請大小:
? ? ? ? 棧:在 Windows 下,棧是向低地址擴展的數據結構,是一塊連續的內存區域,即棧頂的地址和棧的最大容量是系統預先規定好的,在 Windows 下棧的大小是2M (也有的說是 1 M ),如果申請的空間超過棧的剩余空間時,將提示 overflow。因此能從棧獲取的空間比較小。
? ? ? ? 堆:是向高地址擴展的數據結構,是不連續的內存區域。這是由于系統是用鏈表存儲空閑的內存地址的,自然不連續,而鏈表的遍歷方式是由低地址向高地址。堆得大小受限于計算機系統中有效的虛擬內存,所以堆獲得的空間比較靈活,也比較大。
? ? · 碎片問題:
? ? ? ? 棧:不存在該問題,因為棧是先進后出的隊列,他們是如此一一對應,以至于沒有一個內存塊從棧中間彈出
? ? ? ? 堆:頻繁的 new/delete 勢必造成空間的不連續,從而造成大量的碎片,使程序效率降低
? ? · 分配方式:
? ? ? ? 棧:有2種方式:靜態和動態分配。靜態分配是由編譯器完成的,比如局部變量的分配。動態分配由 alloc 函數進行分配,但棧的動態分配和棧不同,是由編譯器進行釋放,無需程序員手工實現
? ? ? ? 堆:只有動態分配
? ? · 分配效率:
? ? ? ? 棧:是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,所以效率比較高
? ? ? ? 堆:是C/C++ 函數庫提供的,機制很復雜
8.引用和指針的區別
? ? · 指針指向一塊內存,內容存儲所指內存的地址;引用是某塊內存的別名。
? ? · 指針使用時需(*),引用不需要。
? ? · 引用只在定義時被初始化,之后不可變;指針可變。
? ? · 引用沒有const。
? ? · 引用不能為空。
? ? · sizeof 引用得到的是所指向變量(對象)的大小,sizeof 指針是指針本身的大小。
? ? · 引用 ++ 為引用對象自己 ++ ,指針 ++ 是指向對象后面的內存。
? ? · 程序需要為指針分配內存區域,引用不需要。
9.用變量 a 給出下面的定義
? ? · 一個有10個整型數的數組:
? ? ? int a [10]
? ? · 一個有10個指針的數組,該指針是一個指向一個整型數的:
? ? ? int * a [10]
? ? · 一個指向10個整數數組的指針:
? ? ? int ( * ) a [10]
? ? · 一個指向函數的指針,該函數有一個整型參數并返回一個整型數:
? ? ? int ( * ) a ( int )
? ? · 一個有10個指針的數組,該指針指向一個函數,該函數有一個整型參數并返回一個整型參數
? ? ? int ( * a [10] ) ( int )
10.寫出以下代碼的輸出
? ? int a [5] = {1, 2, 3, 4, 5} ;
? ? int *ptr = ( int *) ( &a + 1) ;
? ? printf ("%d, %d ",*( a + 1) , *(ptr + 1));
? ? 參考答案:2,隨機值
? ? 分析:
? ? ? ? a 代表有 5 個元素的數組首地址,a[ 5 ] 的元素分別是1,2,3,4,5。a + 1 表示數據首地址加 1,即 a[ 1 ],值為2。但這里是&a + 1,因為 a 代表的是整個數組,它的空間大小為5 * sizeof ( int ),因此 &a + 1就是 a + 5。a 是個常量指針,指向當前數組的首地址,,指針 + 1就是移動sizeof( int )個字節。因此 ptr 是指向 int * 類型的指針,而 ptr 指向的就是 a + 5,那么 ptr +1 也相當于 a + 6,所以最后的 *( ptr +1)就是一個隨機值了。而 *( ptr - 1 )就相當于 a + 4,對應值為5。
11.內存分區情況
? ? · 代碼區:存放函數二進制代碼
? ? · 數據區:系統運行時申請內存并初始化,系統退出時由系統釋放,存放全局變量、靜態變量、常量
? ? · 堆區:通過 malloc 等函數或 new 等操作符動態申請得到,需程序員手動申請和釋放
? ? · 棧區:函數模塊申請,函數結束時由系統自動釋放,存放局部變量、函數參數
12.用NSLog輸出一個浮點類型,結果四舍五入,并保留一位小數
? ? float money = 1.011;
? ? NSLog ( @"%.1f", money ) ;
13.指針和數組的區別
? ? · 數組可以申請在棧區和數據區;指針可以指向任意類型的內存塊。sizeof 作用于數組時,得到是數組所占的內存大小;作用于指針時,得到的都是4個字節的大小
? ? · 數組名表示數組首地址,是常量指針,不可修改指向;普通指針的值可以改變
? ? · 用字符串初始化字符數組是將字符串的內容拷貝到字符數組中;用字符串初始化字符指針是將字符串的首地址賦給指針,也就是指向了該字符串