第13章 基本的C语言特性
本章将介绍在编写Objective-C程序时并非必须知道的特性。事实上,这些特性大部分来源于基本的C语言。函数、结构、指针、联合和数组之类的特性最好在必须知道时才学习。因为C语言是一门过程式语言,所以有些特性与面向对象编程的思想是相对立的。这些特性也会妨碍Foundation框架实现的策略,比如内存分配方式或处理包含多字节字符的字符串。
注意在C级别有多种使用多字节字符的方式,但是Foundation通过其NSString类提供了比较好的解决方案。
另一方面,也许一些应用程序为了优化要求使用底层方法。比如,如果使用大型的数据数组,可能想要使用C语言的内置数组结构,而不是Foundation的数组对象(详见第15章)。如果使用恰当,函数也可以方便地组合重复使用的操作并将程序模块化。
建议你先浏览本章的内容,然后在读完第二部分之后再学习本章。或者是完全忽略本章。并开始学习第二部分。如果后来需要支持其他人编写的代码,或开始研究Foundation框架的头文件,将接触到本章所讲的一些结构。很多Foundation数据类型,如NSRange、NSPoint和NSRect,都要求对本章所讲的结构有一些基本了解。在这些情况下,可以回到本章,并阅读相关部分以了解所需的概念。
13.1 数组
Objective-C提供了一项功能,它允许用户定义一组有序的数据项,即数组。本节将讲述如何定义和操纵数组。在后面几节中,我们会进一步讨论数组,以阐述它们如何与函数、结构、字符串及指针一起使用。
假设你有一组成绩要录入计算机,并要对这些成绩执行一些操作,比如按升序排列、计算平均值或查找中值。在排序过程中,除非录入所有成绩,否则排序将无法进行。
在Objective-C中,可以定义一个名为grades的变量,它代表的不是一个成绩值,而是一组成绩值。然后通过名为索引或下标的数字来引用其中各个元素。在数学上,有下标的变量i,指的是x集合中的第i个元素;而在Objective-C语言中,类似的符号为:
x[i]
所以表达式
grades[5]
(读做“grades sub 5”)指的是名为grades的数组中索引为5的元素。在Objective-C语言中,数组元素以0索引开头,所以
grades[0]
实际上指的是该数组的第一个元素。
任何一个数组元素都可以用在可用常规变量的地方。比如,可以使用以下语句将数组值赋给另一个变量:
g=grades[50];
此表达式使用grades[50]的值,并将它赋给变量g。更广泛地说,如果将i声明为整型变量,那么语句
g=grades[i];
使用索引为i的grades数组元素的值,并将其指定给g。
通过在等号的左侧指定数组元素,就可以将数值存储到数组元素中。下面的语句
grades[100]=95;
将数值95存储到grades数组中索引为100的元素中。
通过改变作为数组下标的变量值,可以轻松地浏览数组中的元素。因此,如下for循环
for(i=0;i<100;++i)
sum+=grades[i];
依次浏览数组grades的前100个元素(元素0~99),并且将每个成绩相加之和赋给变量sum。当for循环结束时,变量sum包含数组grades的前100个元素值之和(假设在循环开始之前sum值设为0)。
和其他变量类型一样,必须在使用之前先声明数组。数组的声明涉及声明数组所包含元素的数值类型,如int、float或者对象,以及将存储在数组中的最大元素数目。
定义
Fraction*fracts[100];
规定fracts为包含100个分数的数组。通过使用下标0~99,可以有效地引用该数组的元素。
表达式
fracts[2]=[fracts[0]add:fracts[1]];
调用Fraction类的add:方法:将数组fracts的前两个分数相加,并将结果存储到数组第三个位置。
代码清单13-1产生斐波纳契数的前15个值列表,尝试预测输出结果,表中每个数值之间有什么关系?
代码清单13-1
//Program to generate the first 15 Fibonacci numbers
import<Foundation/Foundation.h>
int main(int argc, char*argv[])
{
NSAutoreleasePool*pool=[[NSAutoreleasePool alloc]init];
int Fibonacci[15],i;
Fibonacci[0]=0;/by definition/
Fibonacci[1]=1;/ditto/
for(i=2;i<15;++i)
Fibonacci[i]=Fibonacci[i-2]+Fibonacci[i-1];
for(i=0;i<15;++i)
NSLog(@“i”,Fibonacci[i]);
[pool drain];
return 0;
}
代码清单13-1输出
0
1
1
2
3
5
8
13
21
34
55
89
144
233
377
前两个斐波纳契数,我们称之为F0和F1,分别定义为0和1。此后的每个斐波纳契数Fi都定义为前两个斐波纳契数Fi-2和Fi-1之和。所以,F0和F1数值之和是F2的值。对于前面的程序,通过计算Fibonacci[0]和Fibonacci[1]之和,就可以直接计算出Fibonacci[2]。这个计算公式是在for循环中执行的,它计算出F2到F14的值(或者,相当于Fibonacci[2]到Fibonacci[14]的值)。
13.1.1 数组元素的初始化
在声明变量时可以给它赋初值,也可以给数组元素赋初值。通过简单地列出数组元素的初值,并以第一个元素开始,就可以实现。列表中的值由逗号隔开,并且整个列表放于一对大括号之内。
语句
int integers[5]={0,1,2,3,4};
将0赋给integers[0],1赋给integers[1],2赋给integers[2],依此类推。
字符数组以同样的方式初始化,所以表达式
char letters[5]={‘a’,‘b’,‘c’,‘d’,‘e’};
定义了字符数组letters,并将5个元素分别初始化为字符‘a’、‘b’、‘c’、‘d’和‘e’。
不必完全初始化整个数组。如果指定了较少的初始化值,那么只初始化等量的元素,并且数组中其余元素被设为0。因此,声明
float sample_data[500]={100.0,300.0,500.5};
将数组sample_data的前3个元素初始化为100.0、300.0和500.5,其余497个元素被设为0。
通过将元素编号放在一对大括号中可以以任何顺序初始化指定的数组元素。比如
int x=1233;
int a[]={[9]=x+1,[2]=3,[1]=2,[0]=1};
定义了一个名为a的10个元素数组(根据数组中最大索引得出的),并将数组的最后一个元素初始化为x+1(1234)。此外,它的前3个元素分别被初始化为1、2和3。