IOS基礎學習之C(一)

iOS開發的核心語言是Objective-C,Objective-C是在C語言的基礎加了一層面向對象的語法。為了能夠更好地掌握Objective-C,我們可以先學習C語言,然後在C語言的基礎上升華到Objective-C。

C語言:

是編譯型語言;

*C語言於1972年發明,首次使用是用於重寫UINX操作系統(UNIX以前是用彙編寫的)

*C語言是一門面向過程的語言,非面向對象的語言

++ 特點:

*弱語法;

*提供了34種運算符;

*有豐富的數據類型;整型(int)、float、char、int[]、指針類型(void *)、結構體類型(struct)、共用體類型(union)等;

*允許直接訪問物理地址,對硬體進行操作;最強大的是指針,可通過指針直接訪問內存地址,使用得當,可節省代碼量,優化內存管理、提高性能;

*具有高級語言的功能,又具有低級語言的許多功能能如彙編語言一樣對位(bit)、位元組和地址進行操作(這三者是計算機工作的基本單元);

*高效率的目標代碼;可讀性好,易於調試,修改和移植,代碼質量與彙編相當;

*可移植性好;在一個環境上用C語言編寫的程序,不改動或稍加改動,就可移植到另一個完全不同的環境中;

**不足:

*由於C語言是面向過程的,因此它的數據封裝性差、安全性低,這就是C語言和其他面向對象語言的區別之一。面向對象語言的特性之一就是數據的封裝性;

*語法限制不嚴格,對變數的類型約束不嚴格,對數組下標越界不作檢查等;

+使用:

*由於C語言具有強大的數據處理能力,而且允許直接訪問物理地址,直接對硬體操作,因此它適於編寫系統軟體、圖形處理、單片機程序、嵌入式系統開發甚至是用於科研;

* 很多操作系統的底層都是用C語言寫的,比如android;

*iOS開發中的核心語言是Objective-C(簡稱OC),OC是在C語言的基礎上加了一層面向對象語法;

+標準:1983年美國國家標準局(American National Standards Institute,簡稱ANSI)成立了一個委員會,開始制定C語言標準的工作。1989年C語言標準被批准,這個版本的C語言標準通常被稱為ANSI C;

— Xcode中的C語言是在標準的C 語言上做了一些封裝;

+語法:

[goto語句一般很少使用,會破壞程序的結構;佔位符同android string;%f 默認6位小數;]

函數(方法):

以#開頭為預處理指令;在編譯之前執行的指令;include的作用只是把後面<**>中的內容拷貝到該處;

若導入的文件是系統自帶的文件用<>,自己寫的文件用」";

.h稱為頭文件;用來聲明一些常用的函數;若想使用這些函數,就必須包含這個頭文件;函數具體的實現是放在其他文件的;

一個C程序只有一個入口main函數;

面向過程:就是先分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用函數就可以了;(只寫函數,不使用對象)

一個C程序中一定會有一個main函數,也只能有一個main函數。main函數是整個C程序的入口。main.c的第3行代碼就定義了一個main函數。

main函數的返回值為int類型,接收2個參數,其實可以不寫參數;

main函數沒有寫返回值類型,並不代表函數沒有返回值,而是表示返回值類型為int類型,void才代表函數沒有返回值;可直接寫main(){…}

+運行過程:

目標代碼須和C 語言的函數庫鏈接在一起,找個頭文件中的引用的函數名的實現生成的機器代碼才能運行。

+1+ 編寫程序

C語言源文件的擴展名為」.c」,源文件以ASCII碼形式存儲,不能直接被計算機執行;

+2+ 編譯(VC)[main.c—>main.obj]

1)把C的源程序翻譯成計算機可以識別的二進位形式的目標代碼文件,這個過程稱為編譯,由C的編譯器完成

2)在編譯的同時,還對源程序的語法等進行檢查。若出現語法錯誤,則編譯失敗。如果編譯成功則生成目標文件,目標文件名跟源程序文件名一樣,擴展名為".obj"。比如,mj.c編譯後生成目標文件mj.obj

3)每個源文件是單獨進行編譯的,假如一個項目中有多個.c源文件,編譯成功會生成多個對應的.obj目標。一般情況下,目標文件之間是有關聯的,比如 a.obj 可能會調用 b.obj 中定義的一個函數,因此它們都不能夠單獨被計算機執行,而且目標文件中並不包含程序運行所需要的庫函數等

頭文件不會被編譯;

+3+ 鏈接(VC下)

將所有有關聯的obj目標文件,以及系統提供的C庫函數等組合在一起生成可執行文件的過程,稱為"鏈接"

鏈接生成的可執行文件的文件名跟源程序文件同名,(win下)擴展名為」.exe」,計算機可以直接執行;

+4+ 運行

win下的.exe;Mac下為exec,雙擊即可執行;

函數:

主函數:main;有且只有一個;不論什麼位置,都是從main 開始執行;

自定義函數:

C庫提供的庫函數;

++ 聲明與定義:

在標準C語言中,是從上向下編譯,故只有後面的函數才能調用前面定義過的函數;

[在使用中可將函數名在mian()方法前聲明,在項目開發中,為了分模塊開發,一般會將函數的聲明和定義(實現)分別放在2個文件中,函數聲明放在.h頭文件中,函數定義放在.c源文件中;這樣使項目結構清晰。]

(由於include只是拷貝,可直接include 「header.c」;但不能重複導入頭文件,故一般不這樣寫;」」的方式是先在當前源程序下找,若打不到,再到系統的path中找;<>是只在c語言庫函數文件中找)

—-[函數在整個項目中不允許重複定義,不支持重載]—-

形參和實參:若是基本數據類型作為函數的形參,那就是簡單的傳遞,將實參賦值給了形參b;和b是分別有著不同內存地址的2個變數,因此改變了形參b的值,並不會影響實參a的值。

— printf():

佔位符:

%d 整型,%4d表示佔用4個位置空間;

%s String

%c char 只能表示一個字元,但一個中文至少佔用兩個字元;

%f 浮點數;%.2f表示保留兩位小數;默認六位小數;

%o 以不帶符號的八進位輸出

%x 以不帶符號的十六進位輸出

%e 以標準指數形式輸出單、雙精度數,數字部分小數位為6位

- scanf

阻塞式函數,不輸入不向下執行;

要對變數進行賦值,須使用地址和佔位符;如:int a;scanf(「%d」,&a);

&a表示變數a的地址;

scanf(「%d-%d」,&a,&b);則輸入也須是a-b的形式;

+ 數據類型

結構體,類似class ;共用體很少使用;

int 整型 2個位元組;

float 單精度浮點型 4個位元組

double 雙精度浮點型 8個位元組

char 字元型 1個位元組,同java,只能存儲一個字元(不能是中文,同java);

變數:若未初始化會自動賦值(全局變數會為0(int),但局部變數可能是一個隨機數,必須初始化後再使用,更安全);

類型修飾符:

short 短型;short int =1;限制取值範圍;

long 長型;擴展int的取值範圍;long a=1;等同於 long int a=1;(C中無long型,long只是一個修飾符)

signed 有符號型;signed int a=1;等同於int a=1;可為正數也可為負;

unsigned 無符號型;只能為正數或0;

可同時使用 unsigned long int a=5;

[不同的編譯器,取值範圍不同;]

基本語句(同java)

基本運算(同java)

但由於C沒有boolean故沒有true和false;用1和0來表示true和false;

如:5>4 —> 1; 5<4 —>0;

** 在if語句中,所有非0(包括負數)的值都為真(true)

[NOTE:像a==0這樣的表達式,最好寫成0==a。因為若誤寫成0=a,編譯器會直接報錯,而a=0是不會報錯的。]

** 在C中,可以不保存關係去處的結果;如:a>10;a==0;

** && 與 || 同Java 也是阻斷式的;

+逗號表達式;

返回值為最後一個表達式的值;如:

int e=2,f=4;

int g = (++e,e*f); g—>12; 若int g = ++e,e*f;則相當於g=(++e),值為3;

+sizeof

用於得到數據佔用的位元組長度,返回值為size_t(即unsigned long,可直接使用int);使用 size_t size=sizeof(a);

+ **地址**

* 計算機中的內存是以位元組為單位的存儲空間。內存的每一個位元組都有一個唯一的編號,這個編號就稱為地址。

*凡存放在內存中的程序和數據都有一個地址,也就是說,一個函數也有自己的內存地址。

*當定義一個變數時,系統就分配一個帶有唯一地址的存儲單元來存儲這個變數。變數存儲單元的第一個位元組的地址就是該變數的地址。

*獲取地址: **&**a;

+數組

只能是int a[5];的形式(int[5] a;int[] b;int a[];int i=0;int a[i]均錯誤。int)

[]裡面的個數必須是一個固定值,可以是常量(比如6、8)、常量表達式(比如3+4、5*7)。絕對不能使用變數或者變數表達式來表示元素個數,大多數情況下不要省略元素個數(當數組作為函數的形參和數組初始化時除外)

*一維數組

定義數組時,系統將按照數組類型和個數分配一段連續的存儲空間來存儲數組元素,如int a[3]佔據了連續的6位元組存儲空間(在16位編譯器環境下,一個int類型佔用2個位元組)。要注意的是,數組名代表著整個數組的地址,也就是數組的起始地址。

其實a不算是變數,是個常量,它代表著數組的地址,不能對其賦值[int a[2];a={1,2};//是錯誤的]。]

數組a的地址是ffc1,a[0]的地址是ffc1,a[1]的地址是ffc3,a[2]的地址是ffc5。因此a == &a[0],即第一個元素的地址就是整個數組的地址

[數組名代表的就是數組的地址,也就是第0個元素的地址;]

*初始化:int a[2]={1,2}(可省略size和和第一個元素後的元素);或 a[0]=1,a[1]=[2];

** 一維數組的元素作為函數實參,與同類型的簡單變數作為實參一樣,是單向的值傳遞,即數組元素的值傳給形參,形參的改變不影響實參;

但是,如果一維數組的名字作為函數實參,傳遞的是整個數組,即形參數組和實參數組完全等同,是存放在同一存儲空間的同一個數組。這樣形參數組修改時,實參數組也同時被修改了。形參數組的元素個數可以省略。

[** 此處同java **]

+ 二維數組

是一個特殊的一維數組,元素是一個一維數組;存放的順序是一行行的存;

a[0]、a[1]也是數組,是一維數組,而且a[0]、a[1]就是數組名,因此a[0]、a[1]就代表著這個一維數組的地址;a = a[0][0];

[若只初始化了部分元素,可省略行數,但不能省略列數;]

+ 字元串

沒有String類型,使用字元數組來存儲字元串;

** 字元串可以看做是一個特殊的字元數組,為了跟普通的字元數組區分開來,應該在字元串的尾部添加了一個結束標誌』』。』是一個ASCII碼值為0的字元,是一個空操作符,表示什麼也不幹。所以採用字元數組存放字元串,賦值時應包含結束標誌。

[NOTE:尾部有個』』,如果沒有這個結束標記,說明這個字元數組存儲的並不是字元串]

初始化:一般使用 char s[] =「mj」;會自動在末尾添加』』;

若使用char s[]={『m』,』j』,』』};一定要加』』;否則會造成內存地址錯誤,內存泄露,讀到臟數據;

== puts(s)== 輸出字元串:會從起始地址一直列印到』』止,故若定義時沒有』』,則很可能會出現內存泄露(很危險)

== gets(s)== 輸入字元串:從s的地址開始逐個賦值用戶輸入的字元,並自動加上,故兩個s一起列印,會讀到其他數據(很危險),

(gets一次只能讀取一個字元串,scanf則可以同時讀取多個字元串;

gets可以讀入包含空格、tab的字元串,直到遇到回車為止;scanf不能用來讀取空格、tab

+字元串數組

一維字元給存放一個字元串;

+字元串處理函數

== putchar(『A』)==:輸出一個char字元;

== char c;c=getchar()==:輸入一個char字元;

== strlen(s) ==:測量字元個數,但不包括;

== strcpy(s1,s2)==:將右邊的s2字元串拷貝到字元數組s1中。從s1的首地址開始,逐個字元拷貝,直到拷貝到為止。當然,在s1的尾部肯定會保留一個。[原s1中的內容會被清掉]

== strcat(s1,s2)==:把s2拼接到s1的後面,從首地址開始到第一個』』就認為是字元串末尾,而不管後面是否還有內容如(char s[]={『a』,』』,』b』})[但必須要保證s1有足夠的長度來存儲s2,否則會內存溢出。];

== strcmp(s1,s2)==:根據字元的ASCII碼的大小來比較兩個字元串的大小;大於為1,等於為0,小於為-1;

== strlwr(s)==:將字元串中的大寫轉成小寫;

感謝李明傑老師@M了個J的講解及時詳細的課件(M了個J - 博客園)!


推薦閱讀:

TAG:iOS | iOS開發 | 編程入門指南 |