Objective-C和C語(yǔ)言的關(guān)系
Objective-C是C語(yǔ)言的嚴(yán)格超集。
任何C語(yǔ)言程序不經(jīng)修改就可以直接通過(guò)Objective-C編譯器儿普,在Objective-C中使用C語(yǔ)言代碼也是完全合法的。Objective-C被描述為蓋在C語(yǔ)言上的薄薄一層,抄因?yàn)镺bjective-C的原意就是在C語(yǔ)言主體上加入面向?qū)ο蟮奶匦?/p>
C介紹
C編譯器:gcc編譯器
查看gcc編譯器版本:gcc -v
C編譯過(guò)程:
gcc hello.c 生成 hello.out
./hello.out
C 存儲(chǔ)類
static
static 存儲(chǔ)類指示編譯器在程序的生命周期內(nèi)保持局部變量的存在,而不需要在每次它進(jìn)入和離開作用域時(shí)進(jìn)行創(chuàng)建和銷毀左权。因此,使用 static 修飾局部變量可以在函數(shù)調(diào)用之間保持局部變量的值痴颊。
static 修飾符也可以應(yīng)用于全局變量赏迟。當(dāng) static 修飾全局變量時(shí),會(huì)使變量的作用域限制在聲明它的文件內(nèi)蠢棱。
全局聲明的一個(gè) static 變量或方法可以被任何函數(shù)或方法調(diào)用锌杀,只要這些方法出現(xiàn)在跟 static 變量或方法同一個(gè)文件中。
extern
extern 存儲(chǔ)類用于提供一個(gè)全局變量的引用裳扯,全局變量對(duì)所有的程序文件都是可見(jiàn)的抛丽。當(dāng)您使用 extern 時(shí)谤职,對(duì)于無(wú)法初始化的變量饰豺,會(huì)把變量名指向一個(gè)之前定義過(guò)的存儲(chǔ)位置。
當(dāng)您有多個(gè)文件且定義了一個(gè)可以在其他文件中使用的全局變量或函數(shù)時(shí)允蜈,可以在其他文件中使用 extern 來(lái)得到已定義的變量或函數(shù)的引用冤吨。可以這么理解饶套,extern 是用來(lái)在另一個(gè)文件中聲明一個(gè)全局變量或函數(shù)漩蟆。
extern 修飾符通常用于當(dāng)有兩個(gè)或多個(gè)文件共享相同的全局變量或函數(shù)的時(shí)候,如下所示:
第一個(gè)文件妓蛮,main.c
#include <stdio.h>
int count ;
extern void write_extern();
int main()
{
count = 5;
write_extern();
}
第二個(gè)文件:support.c
#include <stdio.h>
extern int count;
void write_extern(void)
{
printf("count is %d\n", count);
}
全局變量
全局變量是定義在函數(shù)外部怠李,通常是在程序的頂部。全局變量在整個(gè)程序生命周期內(nèi)都是有效的,在任意的函數(shù)內(nèi)部能訪問(wèn)全局變量捺癞。
預(yù)處理指令
內(nèi)存管理
內(nèi)存5區(qū):
計(jì)算機(jī)中的內(nèi)存是分區(qū)來(lái)管理的夷蚊,程序和程序之間的內(nèi)存是獨(dú)立的,不能互相訪問(wèn)髓介,比如QQ和瀏覽器分別所占的內(nèi)存區(qū)域是不能相互訪問(wèn)的惕鼓。而每個(gè)程序的內(nèi)存也是分區(qū)管理的,一個(gè)應(yīng)用程序所占的內(nèi)存可以分為很多個(gè)區(qū)域唐础,我們需要了解的主要有四個(gè)區(qū)域箱歧,通常叫內(nèi)存四區(qū)
代碼區(qū)
程序被操作系統(tǒng)加載到內(nèi)存的時(shí)候,所有的可執(zhí)行代碼(程序代碼指令一膨、常量字符串等)都加載到代碼區(qū)呀邢,這塊內(nèi)存在程序運(yùn)行期間是不變的。代碼區(qū)是平行的豹绪,里面裝的就是一堆指令驼鹅,在程序運(yùn)行期間是不能改變的。函數(shù)也是代碼的一部分森篷,故函數(shù)都被放在代碼區(qū)输钩,包括main函數(shù)。
注意:"int a = 0;"語(yǔ)句可拆分成"int a;"和"a = 0"仲智,定義變量a的"int a;"語(yǔ)句并不是代碼买乃,它在程序編譯時(shí)就執(zhí)行了,并沒(méi)有放到代碼區(qū)钓辆,放到代碼區(qū)的只有"a = 0"這句剪验。
void test() {
}
void test1() {
}
void (* t1)(void) = test1;
void (* t)(void) = test;
printf("函數(shù)test地址=%p 函數(shù)test1地址=%p\n\n\n", t, t1);
常量區(qū)
c字符串是在常量區(qū)的。
printf("字符串xx地址=%p \n", &"abc");
printf("字符串xx地址=%p \n\n\n", &"12342");
// char cStr[2] = "xx"; &cStr[0]是在棧區(qū)
靜態(tài)區(qū)
靜態(tài)區(qū)存放程序中所有的全局變量和靜態(tài)變量前联。
棧區(qū)
棧(stack)是一種先進(jìn)后出的內(nèi)存結(jié)構(gòu)功戚,所有的自動(dòng)變量、函數(shù)形參都存儲(chǔ)在棧中似嗤,這個(gè)動(dòng)作由編譯器自動(dòng)完成啸臀,我們寫程序時(shí)不需要考慮。棧區(qū)在程序運(yùn)行期間是可以隨時(shí)修改的烁落。當(dāng)一個(gè)自動(dòng)變量超出其作用域時(shí)乘粒,自動(dòng)從棧中彈出。
- 每個(gè)線程都有自己專屬的棧伤塌;
- 棧的最大尺寸固定灯萍,超出則引起棧溢出;(線程棧的默認(rèn)大小是8M)
- 變量離開作用域后棧上的內(nèi)存會(huì)自動(dòng)釋放每聪。
棧是先進(jìn)后出的旦棉,先進(jìn)入的地址較大齿风。后進(jìn)入的地址較小。內(nèi)存溢出后绑洛,后入的先被銷毀
由編譯器自動(dòng)分配釋放 聂宾,存放函數(shù)的參數(shù)值,局部變量的值等诊笤。其操作方式類似于數(shù)據(jù)結(jié)構(gòu)中的棧.
堆區(qū)
堆(heap)和棧一樣系谐,也是一種在程序運(yùn)行過(guò)程中可以隨時(shí)修改的內(nèi)存區(qū)域,但沒(méi)有棧那樣先進(jìn)后出的順序讨跟。更重要的是堆是一個(gè)大容器纪他,它的容量要遠(yuǎn)遠(yuǎn)大于棧。 一般由程序員分配釋放晾匠, 若程序員不釋放茶袒,程序結(jié)束時(shí)可能由OS回收 。注意它與數(shù)據(jù)結(jié)構(gòu)中的堆是兩回事凉馆,分配方式倒是類似于鏈表薪寓。
一般比較復(fù)雜的數(shù)據(jù)類型都是放在堆中。但是在C語(yǔ)言中澜共,堆內(nèi)存空間的申請(qǐng)和釋放需要手動(dòng)通過(guò)代碼來(lái)完成
申請(qǐng)
首先應(yīng)該知道操作系統(tǒng)有一個(gè)記錄空閑內(nèi)存地址的鏈表向叉,當(dāng)系統(tǒng)收到程序的申請(qǐng)時(shí),會(huì)遍歷該鏈表嗦董,尋找第一個(gè)空間大于所申請(qǐng)空間的堆結(jié)點(diǎn)母谎,然后將該結(jié)點(diǎn)從空閑結(jié)點(diǎn)鏈表中刪除,并將該結(jié)點(diǎn)的空間分配給程序京革,另外奇唤,對(duì)于大多數(shù)系統(tǒng),會(huì)在這塊內(nèi)存空間中的首地址處記錄本次分配的大小匹摇,這樣咬扇,代碼中的delete語(yǔ)句才能正確的釋放本內(nèi)存空間。另外廊勃,由于找到的堆結(jié)點(diǎn)的大小不一定正好等于申請(qǐng)的大小懈贺,系統(tǒng)會(huì)自動(dòng)的將多余的那部分重新放入空閑鏈表中。
https://www.cnblogs.com/yif1991/p/5049638.html
https://blog.csdn.net/qianqin_2014/article/details/51114105
局部變量保存在棧中供搀,只有在所在函數(shù)被調(diào)用時(shí)才動(dòng)態(tài)地為變量分配存儲(chǔ)單元隅居。
結(jié)構(gòu)體的全局或靜態(tài)變量也是存在靜態(tài)區(qū)钠至;局部變量在棧區(qū)
源文件轉(zhuǎn)換為可執(zhí)行文件的四步驟
1葛虐、預(yù)處理(preprocessor):對(duì)#include、#define棉钧、#ifdef/#endif屿脐、#ifndef/#endif等進(jìn)行處理,刪除了注釋。 gcc -E a.c a.i
2的诵、編譯(compiler):將源碼編譯為匯編代碼 gcc -c a.i a.s
3万栅、匯編(assembler):將匯編代碼匯編為目標(biāo)代碼 gcc -s a.s a.o
4、鏈接(linker):將目標(biāo)代碼鏈接為可執(zhí)行文件
指針
通過(guò)指針西疤,可以簡(jiǎn)化一些 C 編程任務(wù)的執(zhí)行烦粒,還有一些任務(wù),如動(dòng)態(tài)內(nèi)存分配代赁,沒(méi)有指針是無(wú)法執(zhí)行的扰她。指針是一個(gè)變量,其值為另一個(gè)變量的地址芭碍。在變量聲明的時(shí)候徒役,如果沒(méi)有確切的地址可以賦值,為指針變量賦一個(gè) NULL 值是一個(gè)良好的編程習(xí)慣窖壕。賦為 NULL 值的指針被稱為空指針忧勿。
算術(shù)運(yùn)算
指針在遞增和遞減時(shí)跳躍的字節(jié)數(shù)取決于指針?biāo)赶蜃兞繑?shù)據(jù)類型長(zhǎng)度,比如 int 就是 4 個(gè)字節(jié)瞻讽。
指針數(shù)組
int *ptr[MAX];
把 ptr 聲明為一個(gè)數(shù)組鸳吸,由 MAX 個(gè)整數(shù)指針組成。因此速勇,ptr 中的每個(gè)元素层释,都是一個(gè)指向 int 值的指針
指向指針的指針
是一種多級(jí)間接尋址的形式,或者說(shuō)是一個(gè)指針鏈快集。通常贡羔,一個(gè)指針包含一個(gè)變量的地址。當(dāng)我們定義一個(gè)指向指針的指針時(shí)个初,第一個(gè)指針包含了第二個(gè)指針的地址乖寒,第二個(gè)指針指向包含實(shí)際值的位置。
函數(shù)指針
函數(shù)指針是指向函數(shù)的指針變量院溺。
通常我們說(shuō)的指針變量是指向一個(gè)整型楣嘁、字符型或數(shù)組等變量,而函數(shù)指針是指向函數(shù)珍逸。
函數(shù)指針可以像一般函數(shù)一樣逐虚,用于調(diào)用函數(shù)、傳遞參數(shù)谆膳。
函數(shù)指針變量的聲明:
typedef int (*fun_ptr)(int,int); // 聲明一個(gè)指向同樣參數(shù)叭爱、返回值的函數(shù)指針類型
int max(int x, int y)
{
return x > y ? x : y;
}
/* p 是函數(shù)指針 /
int ( p)(int, int) = & max; // &可以省略
指向結(jié)構(gòu)的指針
struct Books *struct_pointer;
struct_pointer = &Book1;
為了使用指向該結(jié)構(gòu)的指針訪問(wèn)結(jié)構(gòu)的成員,您必須使用 -> 運(yùn)算符漱病,如下所示:
truct_pointer->title;
結(jié)構(gòu)體
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
} book;