第六部分
- #define久又、#undef
- 條件編譯 #ifdef、#endif效五、#else地消、#ifndef
#define、#undef
預(yù)處理程序語(yǔ)句使用井號(hào)(#)標(biāo)記畏妖,這個(gè)符號(hào)(#)必須是一行中的第一個(gè)非空格字符脉执,但是#號(hào)后面可以允許多個(gè)空格。
#define通常放在程序的開(kāi)始戒劫,但在#import或include之后半夷。但這不是必須的,它可以放在程序的任何地方迅细。但在使用它之前巫橄,它必須已經(jīng)定義了。
如果使用#define定義了一個(gè)宏疯攒,可以使用#undef取消定義嗦随。
#define IPAD 1
//取消定義
#undef IPAD
條件編譯 #ifdef、#endif敬尺、#else枚尼、#ifndef
#ifdef、#endif砂吞、#else署恍、#ifndef
#ifndef:如果沒(méi)有定義...
- 使用條件編譯定義一些參數(shù),可以讓程序在不同系統(tǒng)上編譯運(yùn)行蜻直。因?yàn)椴煌到y(tǒng)可能有時(shí)候參數(shù)會(huì)不同盯质。
例子,通過(guò)判斷是否定義了IPAD來(lái)定義不同的kImageFile:
#ifdef IPAD
# define kImageFile @"barnHD.png"
#else
# define kImageFile @"barn.png"
#endif
#define IPAD 1
或者
#define IPAD 就足夠滿足定義了IPAD了
- 還有其他一些作用概而,比如調(diào)試程序呼巷。
這里沒(méi)看懂?赎瑰?王悍?
#ifdef DEBUG
NSLog(@"ssss");
#endif
#if、#else餐曼、#elif(相當(dāng)于else if)
- 這幾個(gè)就相當(dāng)于if else 語(yǔ)句压储,只不過(guò)是預(yù)處理語(yǔ)句形式的條件編譯鲜漩。語(yǔ)法使用和if-else語(yǔ)句相同
#if MAC_OC < 10.5
#define MAC xxx
#endif
- 特殊運(yùn)算符:defined (name)
#if defined(IPAD) 等于 #ifdef IPAD
#if !defined(IPAD) 等于 #ifndef IPAD
第七部分
- 數(shù)組
- 塊(Blocks)
- 結(jié)構(gòu)體
- 結(jié)構(gòu)體指針
- 箭頭運(yùn)算符(->)
數(shù)組
1. 數(shù)組的聲明
數(shù)組的聲明涉及數(shù)組所包含元素的數(shù)值類(lèi)型,如int集惋、float或者對(duì)象孕似,以及將存儲(chǔ)在數(shù)組中的最大元素?cái)?shù)目。也就是說(shuō)刮刑,對(duì)象類(lèi)型也可以作為數(shù)組的元素類(lèi)型喉祭。
int array[100];
float array1[2][3];
NSString *strArray[100];//NSString *作為數(shù)組的元素類(lèi)型
NSString *str[100] = {@"sdf",@"sdfs"};
2. 數(shù)組的初始化
- 正如在聲明數(shù)組的時(shí)候可以給它賦初值一樣,也可以在聲明數(shù)組的時(shí)候給數(shù)組元素賦初值为朋。
int array[4] = {0,1,2,3};
char charArray[5] = {'a','b','c','d','e'};
- 不必完全初始化整個(gè)數(shù)組臂拓,可以指定少數(shù)值,然后數(shù)組剩余的會(huì)自動(dòng)被設(shè)為0习寸。
float array[100] = {100.1,20.4,2003.1};
- 可以不顯式地指定數(shù)組的大小胶惰,但是必須初始化數(shù)組的每個(gè)元素。
int array[] = {0,1,2,3,4,5,6};
但是不能下面這樣初始化霞溪,這樣初始化是錯(cuò)誤的盲链。不指定數(shù)組個(gè)數(shù)時(shí)泵督,必須同時(shí)初始化。
int array[];
array = {0,1,2,3,4,5,6};
3. 二維數(shù)組的初始化
- 第一種,使用花括號(hào)和逗號(hào)隔開(kāi)每行的元素衩侥。注意花括號(hào)和逗號(hào)的使用蹬屹。
int array2[3][4] = {
{1,2,3,4},
{1,2,3,4},
{1,2,3,4}
};
- 第二種柏蘑,不使用花括號(hào)狂窑。
int array2[3][4] = {1,2,3,4,1,2,3,4,1,2,3,4};
- 第三種,與一維數(shù)組相同染厅,不必完全初始化所有元素痘绎。
注意:代碼中兩種初始化的數(shù)組元素是不同的(使用花括號(hào),初始化的是每一行)
int array2[3][4] = {
{1,2},
{1,2,3},
{1,2}
};
int array2[3][4] = {1,2,3,4,1};
塊(Blocks)
塊是Apple公司對(duì)C語(yǔ)言的一種擴(kuò)展肖粮。
- 可以給塊傳遞參數(shù)孤页,正如給函數(shù)傳遞一樣;
- 塊也具有返回值涩馆,正如函數(shù)的返回值一樣行施;
- 與函數(shù)不同的是,塊定義在函數(shù)或方法的內(nèi)部魂那,并且能夠訪問(wèn)在++函數(shù)或者方法范圍內(nèi)++塊之外的所有變量蛾号。就是說(shuō),塊可以訪問(wèn)外部變量涯雅,但是不能超過(guò)塊所在的函數(shù)或方法的范圍须教。一般來(lái)講,這些變量可以在塊內(nèi)部被訪問(wèn),但是不能再塊內(nèi)部被修改轻腺。除非使用塊修改器。
//無(wú)返回值划乖,無(wú)參數(shù)
void (^printMessage)(void) = ^(void){
NSLog(@"xxxxx");
};
//有返回值贬养,兩個(gè)參數(shù)
int (^calculate) (int,int) = ^(int x, int y){
return x+y;
};
結(jié)構(gòu)體
結(jié)構(gòu)體是另一種組合元素的工具。
結(jié)構(gòu)體的定義琴庵、聲明和初始化
- 結(jié)構(gòu)體的定義
//正常定義
struct date{
int month;
int day;
int year;
};
//結(jié)合typedef的定義
typedef struct date{
int month;
int day;
int year;
}Date;
- 結(jié)構(gòu)體的變量聲明
//正常聲明
struct date today;
struct date tomorrow;
//typedef了別名的聲明
Date yesterday;
//在定義結(jié)構(gòu)體的時(shí)候误算,直接聲明變量
struct date{
int month;
int day;
int year;
}everyday;
注意:上面的today、tomorrow迷殿、everyday是一個(gè)結(jié)構(gòu)體變量儿礼,而不是一個(gè)對(duì)象。
3.結(jié)構(gòu)體變量的初始化
- 初始化方法和數(shù)組相同庆寺。將結(jié)構(gòu)體的元素放到一對(duì)花括號(hào)內(nèi)蚊夫。
struct date today = {1,2,3};
Date tomorrow = {1,2,3};
- 在定義結(jié)構(gòu)體的時(shí)候,直接聲明并初始化變量
struct date{
int month;
int day;
int year;
}everyday = {1,2,3};
- 使用點(diǎn)語(yǔ)法初始化結(jié)構(gòu)體變量懦尝。是的知纷,結(jié)構(gòu)體變量可以使用點(diǎn)語(yǔ)法,這點(diǎn)跟操作對(duì)象的屬性一樣(它的本質(zhì)是存取方法)陵霉。編譯器在遇到點(diǎn)運(yùn)算符的時(shí)候琅轧,會(huì)判斷左邊是一個(gè)對(duì)象還是一個(gè)結(jié)構(gòu)體。結(jié)構(gòu)體的點(diǎn)語(yǔ)法也有存值和取值的操作踊挠。
today.month = 1;
today.day = 2;
today.year = 3;
- 可以使用點(diǎn)語(yǔ)法乍桂,任意順序初始化結(jié)構(gòu)體變量。
struct date today = {.month=1,.today=1,.year=1};
//只將year設(shè)為1
Date tomorrow = {.year=1};
結(jié)構(gòu)體中的結(jié)構(gòu)體
CGPoint效床、CGSize睹酌、CGRect都是結(jié)構(gòu)體。
- CGPoint用于描述(x,y)點(diǎn)扁凛。
在Apple的CGGeometry.h的頭文件中的定義:
struct CGPoint {
CGFloat x;
CGFloat y;
};
typedef struct CGPoint CGPoint;
注意:CGFloat是由typedef定義的基本浮點(diǎn)數(shù)據(jù)類(lèi)型忍疾。
- CGSize用于描述寬和高。
在Apple的CGGeometry.h的頭文件中的定義:
struct CGSize {
CGFloat width;
CGFloat height;
};
typedef struct CGSize CGSize;
- CGRect用于描述包含一個(gè)原點(diǎn)(一個(gè)CGPoint)和尺寸(一個(gè)CGSize)的矩形谨朝。
在Apple的CGGeometry.h的頭文件中的定義:
struct CGRect {
CGPoint origin;
CGSize size;
};
typedef struct CGRect CGRect;
4.它們的初始化
CGRect rect = CGRectMake(0, 0, 5, 34);
CGSize size;
size.width = 1;
size.height = 1;
CGPoint point = CGPointMake(10, 11);
結(jié)構(gòu)體數(shù)組
struct date{
int month;
int day;
int year;
}everyday[100];
struct date today[11];
結(jié)構(gòu)體指針
在使用結(jié)構(gòu)體定義鏈表或者是樹(shù)的時(shí)候卤妒,我們需要指針來(lái)操作鏈表或樹(shù)的節(jié)點(diǎn),所以在聲明一個(gè)鏈表或樹(shù)的時(shí)候字币,我們用指針來(lái)聲明则披。
- 鏈表的結(jié)構(gòu)體定義
typedef struct ListNode{
int value;
struct ListNode *next;
}ListNode;
- 鏈表的結(jié)構(gòu)體聲明。(定義的結(jié)構(gòu)體指針只是說(shuō)明這個(gè)指針是指向這個(gè)結(jié)構(gòu)的洗出,但并未給結(jié)構(gòu)體分配內(nèi)存空間士复,這就類(lèi)似于聲明,只是告訴系統(tǒng)我這個(gè)指針是干什么用的。所以需要使用malloc)
ListNode *head;
head = (ListNode *)malloc(sizeof(ListNode));//分配內(nèi)存
head->value = 1;
head->next = nil;
注意阱洪,這里使用的是箭頭操作符(左邊的操作數(shù)是指針時(shí)便贵,才能使用箭頭操作符。->指向的是冗荸,指針?biāo)赶虻膶?duì)象的成員承璃。)
其實(shí)上面的聲明和這個(gè)是相同的:
ListNode head = {1,nil};
ListNode *pHead = &head;(head取地址)
(*pHead).value = 1;
注意:點(diǎn)運(yùn)算符比取內(nèi)容運(yùn)算符高*蚌本,所以這里要加上括號(hào)盔粹。
(pHead).value 就相當(dāng)于 head->value*
箭頭運(yùn)算符(->)
C語(yǔ)言:存取結(jié)構(gòu)體成員的點(diǎn)運(yùn)算符(.)和箭頭運(yùn)算符(->)的區(qū)別
- 點(diǎn)操作符和箭頭操作符的異同點(diǎn)
相同點(diǎn):兩個(gè)都是二元操作符,其右操作符是成員的名稱程癌。
不同點(diǎn):點(diǎn)操作符左邊的操作數(shù)是一個(gè)“結(jié)果為結(jié)構(gòu)”的表達(dá)式舷嗡;箭頭操作符左邊的操作數(shù)是一個(gè)指向結(jié)構(gòu)的指針。
也就是說(shuō)嵌莉,箭頭操作符的左邊必須是一個(gè)指針进萄。箭頭操作符指向的是,指針?biāo)赶虻膶?duì)象的成員烦秩。
因?yàn)辄c(diǎn)操作符不能使用于指針垮斯,所以在鏈表的結(jié)構(gòu)體中,使用箭頭操作符只祠。具體看結(jié)構(gòu)體指針的使用兜蠕。
第八部分
- C語(yǔ)言中的字符串
- 指針
C語(yǔ)言中的字符串
在C語(yǔ)言中,字符串實(shí)際上是使用 null 字符 '\0' 終止的一維字符數(shù)組抛寝。因此熊杨,一個(gè)以 null 結(jié)尾的字符串,包含了組成字符串的字符盗舰。
下面的聲明和初始化創(chuàng)建了一個(gè) "Hello" 字符串晶府。由于在數(shù)組的末尾存儲(chǔ)了空字符,所以字符數(shù)組的大小比單詞 "Hello" 的字符數(shù)多一個(gè)钻趋。
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
其實(shí)川陆,您不需要把 null 字符放在字符串常量的末尾。C 編譯器會(huì)在初始化數(shù)組時(shí)蛮位,自動(dòng)把 '\0' 放在字符串的末尾较沪。
依據(jù)數(shù)組初始化規(guī)則,您可以把上面的語(yǔ)句寫(xiě)成以下語(yǔ)句:
char greeting[] = "Hello";
但以下聲明是錯(cuò)誤的:
char greeting[];
greeting = "Hello";
但是以下聲明是錯(cuò)誤的:
char greeting[];
greeting = "Hello";
指針
指針實(shí)際上就是內(nèi)存地址失仁。
- 可以將指針作為參數(shù)傳遞給方法或函數(shù)尸曼,也可以讓函數(shù)或方法返回指針;
- alloc和init返回的就是指針萄焦;
例子:使用方法交換兩個(gè)數(shù)字控轿,這里傳的就是指針
//交換兩個(gè)數(shù)字
void exchange(int *a, int *b){
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main (int argc,char* argv[]){
@autoreleasepool{
int a = 1;
int b = 2;
exchange(&a,&b);
}
}
指針與數(shù)組
oc編譯器將沒(méi)有下標(biāo)的數(shù)組名看作是指向數(shù)組第一個(gè)元素的指針。
- 在下面的例子里:首先定義了一個(gè)int類(lèi)型的指針,然后將數(shù)組的第一個(gè)元素的指針和第二個(gè)元素的指針賦給它茬射。*value就等于value[0],*(value+i)就等于value[i]鹦蠕。
int value[100];
int *valuePtr;//int類(lèi)型的指針
valuePtr = value;
*valuePtr = 1;
valuePtr = value+1;
*valuePtr = 2;
NSLog(@"%d,%d",value[0],value[1]);//輸出1,2
- 利用指針求一個(gè)數(shù)組的和
int arraySum(int array[],int n){
int sum = 0 ,*ptr;
int *arrayEnd = array + n;//注意躲株,這里是數(shù)組的最后一個(gè)元素“之后”的指針
for ( ptr = array ; ptr < arrayEnd ; ptr++ ) {
sum += *ptr;
}
return sum;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
int number[10] = {1,2,3,4,5,6,7,8,9,10};
int result = arraySum(number,10);
NSLog(@"%d",result);
}
return 0;
}
在這里片部,我們發(fā)現(xiàn),給函數(shù)傳遞數(shù)組作為參數(shù)的時(shí)候霜定,傳遞的是數(shù)組名稱(實(shí)際上,傳遞的就是數(shù)組的首元素指針)廊鸥。
字符串指針
- 利用char數(shù)組復(fù)制字符串望浩。字符數(shù)組可以用字符串賦值,char from[] = "hello,world";換句話說(shuō)惰说,字符數(shù)組就是C風(fēng)格的字符串磨德。
void copyString(char to[],char from[]){
int i;
for ( i = 0 ; from[i] != '\0' ; i++ ) {
to[i] = from[i];
}
to[i] = '\0';
NSLog(@"%s",to);
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
char from[] = "hello,world";
char to[50];
copyString(to, from);
}
return 0;
}
- 利用指針復(fù)制字符串。注意吆视,這里傳的是指針典挑,不是數(shù)組。
void copyString(char *to,char *from){
for ( ; *from != '\0' ; to++,from++ ) {
*to = *from;
}
*to = '\0';
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
char from[] = "hello,world";
char to[50];
copyString(to, from);
NSLog(@"%s",to);
copyString(to, "hello,world");
NSLog(@"%s",to);
}
return 0;
}
注意:
- "hello,world"是C風(fēng)格的字符串啦吧,不是字符串對(duì)象您觉,字符串對(duì)象前面有@符號(hào),這兩種類(lèi)型不能互相轉(zhuǎn)換授滓。
- 字符數(shù)組 char a[] = "ssdaf dfa"; 字符數(shù)組就是C風(fēng)格的字符串琳水。
- 如果一個(gè)函數(shù)需要傳入一個(gè)char類(lèi)型的數(shù)組,你可以傳入一個(gè)字符數(shù)組般堆,或者是一個(gè)字符串在孝,而不能是字符串對(duì)象。
- 上面的copyString(to, "hello,world"); 表明淮摔,在傳遞字符串的時(shí)候私沮,實(shí)際上傳遞的也是指向字符串的指針。
可以這樣寫(xiě)一個(gè)字符指針和橙。在oc中仔燕,只要用到字符串(不是字符串對(duì)象),就會(huì)產(chǎn)生指向該字符串的指針胃碾。
char *textPtr = "hello,world";
第九部分
- sizeof運(yùn)算符
- 庫(kù)函數(shù)malloc
- 一些工作原理
sizeof運(yùn)算符
sizeof運(yùn)算符用來(lái)確定數(shù)據(jù)類(lèi)型或者是對(duì)象的大小涨享;
sizeof返回的是字節(jié)大小;
sizeof運(yùn)算符的參數(shù)可以是變量仆百、數(shù)組名稱厕隧、基本數(shù)據(jù)類(lèi)型名稱、對(duì)象、派生數(shù)據(jù)類(lèi)型名稱吁讨、表達(dá)式髓迎。
獲取對(duì)象的大小,要帶上星號(hào)建丧,否則返回的是指針大信帕洹:sizeof(對(duì)象)*
假設(shè)*myFract是一個(gè)Fraction的對(duì)象,它包含兩個(gè)int實(shí)例變量翎朱。那么橄维,表達(dá)式sizeof(myFract)返回的是4,在任何使用4個(gè)字節(jié)表示指針的系統(tǒng)上都會(huì)返回4拴曲,這是因?yàn)閟izeof(myFract)表示的是指針大小争舞。要獲得實(shí)際存儲(chǔ)Fraction對(duì)象實(shí)例的數(shù)據(jù)結(jié)構(gòu)大小,要這樣寫(xiě):
sizeof(*myFract)
malloc
malloc用來(lái)實(shí)現(xiàn)動(dòng)態(tài)分配內(nèi)存澈灼。
一些工作原理
1. 實(shí)例變量實(shí)際上存儲(chǔ)在結(jié)構(gòu)中
定義一個(gè)新類(lèi)和它的實(shí)例變量時(shí)竞川,這些實(shí)例變量實(shí)際上存放在一個(gè)結(jié)構(gòu)中。這就說(shuō)明了可以如何處理對(duì)象叁熔,對(duì)象實(shí)際上是結(jié)構(gòu)委乌,結(jié)構(gòu)中的成員是實(shí)例變量。所以繼承的實(shí)例變量加上你再類(lèi)中添加的變量就組成了一個(gè)結(jié)構(gòu)荣回。使用alloc分配對(duì)象時(shí)遭贸,系統(tǒng)預(yù)留了足夠的空間來(lái)存儲(chǔ)這些結(jié)構(gòu)。
結(jié)構(gòu)中有一個(gè)從根對(duì)象繼承的成員驹马,名為isa革砸,它用來(lái)確定對(duì)象所屬的類(lèi),它是結(jié)構(gòu)的一部分糯累,所以由對(duì)象攜帶算利。這樣,運(yùn)行時(shí)系統(tǒng)只需通過(guò)查看isa成員泳姐,就可以確定對(duì)象所屬的類(lèi)效拭。
2. 對(duì)象變量實(shí)際上是指針
Fraction *myFract;
事實(shí)上是定義了一個(gè)名為myFract的指針變量。這個(gè)變量定義為指向Fraction類(lèi)型的數(shù)據(jù)胖秒。
myFract = [Fraction alloc];
上面是在為Fraction對(duì)象的新勢(shì)力分配內(nèi)存(即存放結(jié)構(gòu)的空間)缎患,然后使用結(jié)構(gòu)的指針,并將指針變量myFract存儲(chǔ)在其中阎肝。
3. id類(lèi)型是通用指針類(lèi)型
- 因?yàn)橥ㄟ^(guò)指針(也就是內(nèi)存地址)來(lái)引用對(duì)象挤渔,所以可以自由地將它們?cè)趇d變量之間來(lái)回賦值。
- 返回id類(lèi)型值的方法风题,只是返回的某對(duì)象的指針判导。
- 因?yàn)閷?duì)象攜帶者isa成員嫉父,所以系統(tǒng)總是能確定id類(lèi)型變量所屬的類(lèi)。
完