objective-c是C 语言的超级,直接使用了 C 语言的数组。
定义数组
语法格式:type array[length]
,其中的 length 可以是个固定的整数也可以是整数变量或表达式。
定义数组时,如果没有对数组进行初始化,系统对数组元素赋值为默认的初始值。赋初始值的规则如下:
- 所有整型(包括字符型)的数组元素,系统默认赋值为0;
- 所有浮点型的数组元素,系统默认赋值为0.0;
- 所有指针型的数组元素,系统默认赋值为空
定义数组后,数组中元素在内存中是连续存放的。如定义 int arr[5]; 在内存中的存放机制如下图:
数组的初始化
语法格式为:type arrayName[length]={ele1,ele2,ele3,……,eleN};
说明:
- int arr[5]={3,2,1};//赋值时可以不全部赋值,前面给出的是前3个元素的初始值,其他为默认的初始值
- int arr2[]={1,3,5,7,9};// 所有元素都指定了初始值,可以省略掉长度
数组的使用
最常用的用法就是访问数组元素,包括对数组元素进行赋值和取出数组元素的值。数组初始化完成后,不能重新对数组本身赋值。如下代码是错误的:
arr={2,3};// 不能对数组本身赋值
objective-c 的数组索引从0开始。
数组下标越界的问题:
如果访问数组元素时,指定的数组元素索引号<0,或者>=数组长度,程序将出现无法预知的错误。因此,要避免数组索引越界的情况出现。
计算数组的长度的方法:
使用 sizeof 函数来计算:sizeof( 数组变量)/sizeof( 数组变量[0])
上面 的公式将返回数组元素的个数。
示例代码:
#import <Foundation/Foundation.h>
int main(int argc , char * argv[])
{
@autoreleasepool{
int len = 5;
// 定义数组,不执行初始化。系统为数组元素指定默认的初始值。
int arr[len];
// 定义数组时,指定长度,并完整地指定了数组的5个元素。
int arr2[5] = {2, 3, 40 , 300, 100};
// 只指定前面3个数组元素的值,后面2个数组元素默认为0。
int arr3[5] = {2, 3, 40};
// 数组长度为3。
int arr4[] = {2, 3 , 40};
// 定义长度为4的指针类型数组,所有数组元素默认为空。
NSDate * arr5[4];
// 定义指针类型的数组,指定每个数组元素的值,系统推断数组长度为3。
char * arr6[] = {"李刚", "fkjava.org", "crazyit.org"};
// 定义长度为4的数组,后面2个数组元素为空
NSString * arr7[4] = {@"疯狂iOS讲义" , @"疯狂Ajax讲义"};
// 输出arr6数组的第二个元素,将输出字符串"fkjava.org"
NSLog(@"%s" , arr6[1]);
// arr6的第一个数组元素赋值
arr6[0] = "Spring";
// 访问数组元素的索引与数组长度相同,编译器会生成警告,运行的结果是不可预期的。
NSLog(@"%d" , arr[5]);
// 遍历元素为基本类型的数组元素
for (int i = 0, length = sizeof(arr2) / sizeof(arr2[0]);
i < length ; i ++)
{
NSLog(@"arr2[%d] : %d" , i , arr2[i]);
}
// 遍历元素为指针类型的数组元素
for (int i = 0, length = sizeof(arr7) / sizeof(arr7[0]);
i < length ; i ++)
{
NSLog(@"arr7[%d] : %@" , i , arr7[i]);
}
//对数组元素进行赋值
arr[0] = 42;
arr[1] = 341;
// 采用遍历方式来输出数组元素
for(int i = 0 , length = sizeof(arr) / sizeof(arr[0]);
i < length; i++)
{
NSLog(@"arr[%d]: %d" , i , arr[i]);
}
}
}
多维数组
先看二维数组,语法格式:type arrayName[length][length]
,例如:float arr[2][3];
二维数组的本质依然是一维数组,只不过它的数组元素又是一维数组。
float arr[3][4]数组在内存中的存放示意图如下图:
类似的三维数组。
int arr[2][3][2] 在内存中的存储示意图。
示例代码:
#import <Foundation/Foundation.h>
int main(int argc , char * argv[])
{
@autoreleasepool{
// 定义、并初始化二维数组
int arr1[3][4] = {
// 下面定义了3个元素,每个元素都是长度为4的一维数组
{2, 20 , 10 , 4},
{4 , 100, 20 , 34},
{5 , 12 , -12 , -34}
};
// 采用循环来遍历二维数组
for(int i = 0 ,length = sizeof(arr1) / sizeof(arr1[0]);
i < length ; i++)
{
for(int j = 0 , len = sizeof(arr1[i]) / sizeof(arr1[i][0]);
j < len ; j++)
{
printf("%d\t" , arr1[i][j]);
}
printf("\n");
}
NSLog(@"-----------------------------");
// 定义并初始化二维数组
int arr2[3][4] = {
// 下面定义了3个元素,每个元素都是长度为4的一维数组
// 但初始化为4的数组时,都只初始化第一个元素,其他元素使用默认初始值
{2, 12},
{4},
{5}
};
// 采用循环来遍历二维数组
for(int i = 0 ,length = sizeof(arr2) / sizeof(arr2[0]);
i < length ; i++)
{
for(int j = 0 , len = sizeof(arr2[i]) / sizeof(arr2[i][0]);
j < len ; j++)
{
printf("%d\t" , arr2[i][j]);
}
printf("\n");
}
NSLog(@"-----------------------------");
// 定义并初始化二维数组
int arr2x[3][4] = {
// 下面只定义了1个元素,其他元素采用默认初始化
// 但初始化为4的数组时,只初始化第2个元素,其他元素使用默认初始值
{2 , 12},
};
// 采用循环来遍历二维数组
for(int i = 0 ,length = sizeof(arr2x) / sizeof(arr2x[0]);
i < length ; i++)
{
for(int j = 0 , len = sizeof(arr2x[i]) / sizeof(arr2x[i][0]);
j < len ; j++)
{
printf("%d\t" , arr2x[i][j]);
}
printf("\n");
}
NSLog(@"-----------------------------");
// 定义、并初始化二维数组,省略二维数组的长度
int arr3[][4] = {
// 下面定义了3个元素,每个元素都是长度为4的一维数组
{2, 20 },
{4 , 100, 20},
{5}
};
for(int i = 0 ,length = sizeof(arr3) / sizeof(arr3[0]);
i < length ; i++)
{
for(int j = 0 , len = sizeof(arr3[i]) / sizeof(arr3[i][0]);
j < len ; j++)
{
printf("%d\t" , arr3[i][j]);
}
printf("\n");
}
NSLog(@"-----------------------------");
// 定义并初始化二维数组
int arr4[3][4] = {
// 由于本身指定了二维数组是一个长度为3的数组,
// 且每个数组元素都长度为4的一维数组
// 因此可以直接给出12个数组元素
2, 20 , 10 , 4,
4 , 100, 20 , 34,
5 , 12 , -12 , -34
};
for(int i = 0 ,length = sizeof(arr4) / sizeof(arr4[0]);
i < length ; i++)
{
for(int j = 0 , len = sizeof(arr4[i]) / sizeof(arr4[i][0]);
j < len ; j++)
{
printf("%d\t" , arr4[i][j]);
}
printf("\n");
}
NSLog(@"-----------------------------");
int arr5[][4] = {
// 由于已经指定了二维数组的数组元素为长度为4的一维数组
// 系统将会根据给出的元素个数(5个)推断出二维数组的长度为2
2, 20 , 10 , 4, 4
};
for(int i = 0 ,length = sizeof(arr5) / sizeof(arr5[0]);
i < length ; i++)
{
for(int j = 0 , len = sizeof(arr5[i]) / sizeof(arr5[i][0]);
j < len ; j++)
{
printf("%d\t" , arr5[i][j]);
}
printf("\n");
}
}
}
printf() 函数和 NSLog() 函数的区别:
- printf() 用于输出 C 格式的字符串。printf 的第一个参数只需使用一个双引号引起来的字符串即可,而NSLog需要使用@前缀。
- NSLog() 函数主要用于记录日志,输出时会自动添加日期,时间,输出程序,并自动换行,而 printf 没有这些。
字符数组,字符串与结束标志
普通字符数组与其他的数组并没有本质区别。示例:
// 定义并初始化字符数组
char cArr[] = {'I', ' ' , 'l' , 'o'
, 'v' , 'e' , ' ' , 'i' , 'O' , 'S'};
// 遍历、并输出字符数组
for(int i = 0 , length = sizeof(cArr)/sizeof(cArr[0]);
i < length ; i ++)
{
NSLog(@"%c" , cArr[i]);
}
特别说明:C 并无真正的字符串支持
C 语言(OC是 C 语言的超集)用字符数组来保存字符串的。字符串的长度并不总是根数组长度相等。
C 是如何确定一个字符串结束的呢?
C 语言提供了‘\0’作为字符串的结束标志。就是说即使一个字符数组长度为100,但它的第8个字符为‘\0’,系统将认为该字符串只包含9个字符。在字符数组中使用‘\0’后,数组长度就没那么重要了。‘\0’代表 ASCII 码为0的字符。代表什么都不是的字符,它的作用仅仅是代表一个字符串的结束。
printf("hello,objective-c");
这句代码表面上没有用\0,实际系统会自动在底层的字符数组的最后一位添加\0结束标志。C风格的字符串都是这样的情况。
使用字符数组来保存字符串的2种形式
- 定义一个字符数组,不指定长度,直接用字符串对其执行初始化,让系统根据其长度决定
char str[] = "I love iOS";
- 如果字符串数组可能保存多个字符串,那就要定义该字符串数组的长度比最长的字符串至少长一个字符。
char str2[20] = "I love iOS";
可以看出,C 语言完全允许直接通过字符串给字符数组赋值。
输出字符串和字符串函数
C语言提供一些常用的标准函数来处理 C 字符串。alaigle总结的比较全,这里贴出链接。不再详述。参加链接:C语言字符串处理函数
示例代码:
char s1[30] = "hello";
// 将",fkjava.org"字符串复制到s字符串的后面。
strcat(s1 , ", fkjava.org");
printf("%s\n" , s1);
// 使用strlen获取字符串的长度
NSLog(@"s1字符串的长度为:%zu" , strlen(s1));
// 定义一个字符数组
char s2[40];
// 不能直接对已有的字符数组赋值,只能用strcpy将已有的字符串复制到s2中。
strcpy(s2 , s1);
NSLog(@"%s" , s2);
在使用 objective-c 的时候尽量使用更为强大 OC 字符串——NSString对象。