C语言基础
C 语言基础
Object-C 语言是C语言的超集,意思就是我们能够将两种语言写在同一个源码文件里。
Object-C语言结构的核心是建立在C语言之上的。所以在学习语言的高级特性之前,掌握C语言基础是非常重要的。
这个模块为C语言提供一个简洁的概述。我们将讨论关于凝视、变量、算数运算符、控制流、简单的数据结构、指针。
这些概念是我们讨论Object-C面向对象特性的基础。
Comments 凝视
在C语言中有两种方式能够提供凝视。行内凝视。以双斜线開始,到本行结束。
块凝视,能够跨越多行,可是必须在 /* 和 */ 之间。
比方:
// This is an inline comment
/* This is a block comment.
It can span multiple lines. */
由于编译器会忽略凝视,这样就能够让我们在代码的旁边加入额外的信息。这样能够帮助我们解释一些easy误解的代码,Object-C代码基本是自解释的。所以您不是非常须要在IOS 和 OS X 应用加入太多的凝视。
Variables 变量
变量是一个容器。他能够存储不同的值。
在C语言中,变量类型是静态的,意思就是您必须清楚的声明。您想存储什么类型的值。声明变量的语法为: ,给变量赋值用=操作符。
假设您想将一个变量转化成还有一个类型,您能够在变量前加入括号,括号里加入新类型。
全部的都在以下的代码中演示了。声明了一个 odometer 变量,能够存储double类型的变量。 (int)odometer 的声明将转化odometer 存储的值 为一个int类型。假设您将代码粘贴在main.m文件里。执行程序。
您将在输出面板中看到NSLog()中的消息。
// main.m
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
double odometer = 9200.8;
int odometerAsInteger = (int)odometer;
NSLog(@"You've driven %.1f miles", odometer); // 9200.8
NSLog(@"You've driven %d miles", odometerAsInteger); // 9200
}
return 0;
}
像double和int一样。C语言定义了非常多原生的数据类型。
一个完整的列表能够在原生模块中找到。并且上面用到的the %.1f 和 %d 格式化符号也有解释。
Constants 常量
常量修饰符是告诉编译器,这个变量是不能被改动的。比方定义一个变量叫pi,假设您试图改动它,将会导致编译器报错。
double const pi = 3.14159;
pi = 42001.0; // Compiler error
这个一般是用在函数的參数中。告诉函数的调用者,他们能够假设传递给函数的參数是不会被改动的。
Arithmetic 算数
我们熟悉的+, -, *, /符号是用来做主要的算数运算符。模运算符(%)被用来返回整数相除的余数。
以下是演示:
NSLog(@"6 + 2 = %d", 6 + 2); // 8
NSLog(@"6 - 2 = %d", 6 - 2); // 4
NSLog(@"6 * 2 = %d", 6 * 2); // 12
NSLog(@"6 / 2 = %d", 6 / 2); // 3
NSLog(@"6 %% 2 = %d", 6 % 2); // 0
当涉及到浮点数或者整数操作时,要特别的小心。具体信息请看整数相除。
当您使用循环时,常常遇到++ 或者–操作符。他是一个从变量中减一或者加一的简易的符号。
int i = 0;
NSLog(@"%d", i); // 0
i++;
NSLog(@"%d", i); // 1
i++;
NSLog(@"%d", i); // 2
Conditionals 条件
像其它的语言一样C语言也提供了标注的if声明。他的主要的语法,以及一个用于描写叙述逻辑运算符的表,例如以下所看到的:
int modelYear = 1990;
if (modelYear < 1967) {
NSLog(@"That car is an antique!!!");
} else if (modelYear <= 1991) {
NSLog(@"That car is a classic!");
} else if (modelYear == 2013) {
NSLog(@"That's a brand new car!");
} else {
NSLog(@"There's nothing special about that car.");
}
Operator Description
a == b Equal to
a != b Not equal to
a > b Greater than
a >= b Greater than or equal to
a < b Less than
a <= b Less than or equal to
!a Logical negation
a && b Logical and
a || b Logical or
C语言也提供了 switch 声明,可是參数仅仅能是整数,不能是浮点数、指针或者其它的Object-C对象。与if条件语句相比較,相当的不灵活。
// Switch statements (only work with integral types)
switch (modelYear) {
case 1987:
NSLog(@"Your car is from 1987.");
break;
case 1988:
NSLog(@"Your car is from 1988.");
break;
case 1989:
case 1990:
NSLog(@"Your car is from 1989 or 1990.");
break;
default:
NSLog(@"I have no idea when your car was made.");
break;
}
Loops 循环
while 和 for 循环能够迭代一些值。相关的break 和continue能够对应使退出循环,或者跳过一个迭代
int modelYear = 1990;
// While loops
int i = 0;
while (i<5) {
if (i == 3) {
NSLog(@"Aborting the while-loop");
break;
}
NSLog(@"Current year: %d", modelYear + i);
i++;
}
// For loops
for (int i=0; i<5; i++) {
if (i == 3) {
NSLog(@"Skipping a for-loop iteration");
continue;
}
NSLog(@"Current year: %d", modelYear + i);
}
如今是合适的时间介绍for-in循环,然而这并非C语言的。这个称为高速枚举语法,由于相比传统的for和while循序。它是一种更加有效的迭代Object-C集合的方法。比方NSSet 和NSArray 。
// For-in loops ("Fast-enumeration," specific to Objective-C)
NSArray *models = @[@"Ford", @"Honda", @"Nissan", @"Porsche"];
for (id model in models) {
NSLog(@"%@", model);
}
Macros 宏指令
Macros are a low-level way to define symbolic constants and space-saving abbreviations. The #define directive maps a macro name to an expansion, which is an arbitrary sequence of characters. Before the compiler tries to parse the code, the preprocessor replaces all occurrences of the macro name with its expansion. In other words, it’s a straightforward search-and-replace:
宏指令是一个定义符号常量和别名的底层方法。
// main.m
import
int main(int argc, const char * argv[]) {
@autoreleasepool {
double angle = PI / 2; // 1.570795
NSLog(@"%f", RAD_TO_DEG(angle)); // 90.0
}
return 0;
}
This code snippet demonstrates the two types of C macros: object-like macros (PI) and function-like macros (RAD_TO_DEG(radians)). The only difference is that the latter is smart enough to accept arguments and alter their expansions accordingly.
Typedef
Typedef能够使我们定义一个新的数据类型或者又一次定义一个已经存在的数据类型。
以下演示一个无符号字符的typeof定义,我们能够使用ColorComponent 就像我们是用char、int、double和其它内建数据类型。
// main.m
import
int main(int argc, const char * argv[]) {
@autoreleasepool {
ColorComponent red = 255;
ColorComponent green = 160;
ColorComponent blue = 0;
NSLog(@"Your paint job is (R: %hhu, G: %hhu, B: %hhu)",
red, green, blue);
}
return 0;
}
typedef 通常被用作将struct或者enum转化成更加方便的数据类型。这个被演示在以下两个段落。
结构体
struct 像一个简单的、原生的C对象。它能够让你聚合一些变量在一个比較复杂的数据结构,可是它不提供面向对象编程的特性,比方方法。比方,以下的代码片段使用struct聚合了组成RGB的元素。
注意。我们通过typeof。能够通过更加有意义的名字获取。
// main.m
import <Foundation/Foundation.h>
typedef struct {
unsigned char red;
unsigned char green;
unsigned char blue;
} Color;
int main(int argc, const char * argv[]) {
@autoreleasepool {
Color carColor = {255, 160, 0};
NSLog(@"Your paint job is (R: %hhu, G: %hhu, B: %hhu)",
carColor.red, carColor.green, carColor.blue);
}
return 0;
}
我们使用了{255, 160, 0}的初始化语法,来初始化新的carColor 结构体。这个复制的顺序和我们定义struct的顺序一样。
并且我们能够通过点语法获取每个域。
枚举
enum 关键字被用于定义枚举类型,他是一个相关常量的集合。
像struct,通过typedef定义个更加有描写叙述性的名字。
// main.m
import <Foundation/Foundation.h>
typedef enum {
FORD,
HONDA,
NISSAN,
PORSCHE
} CarModel;
int main(int argc, const char * argv[]) {
@autoreleasepool {
CarModel myCar = NISSAN;
switch (myCar) {
case FORD:
case PORSCHE:
NSLog(@"You like Western cars?
");
break;
case HONDA:
case NISSAN:
NSLog(@"You like Japanese cars?");
break;
default:
break;
}
}
return 0;
}
以为myCar 变量被定义为CarModel 类型。所以他仅仅能存储四种类型的枚举成员: FORD, HONDA, NISSAN, and PORSCHE。
定义这些在一个枚举类型中,比使用字符串代表各种CarModel更加的可靠。
Cocoa 框架使用大量的枚举定义常量。比方NSSearchPathDirectory 定义OS X使用的 标准文件夹路径。
Ry’s Cocoa的教程。数据存储章节中提供了大量的样例。
原生数组
由于Object-C是C语言的超级,它就能够訪问C语言中的数组。Foundation 提供的NSArray 和 NSMutableArray 比C 语言的数组更加的方便好用。
然而,对性能要求比較高的环境,C语言数组还是非常实用的。
int years[4] = {1968, 1970, 1989, 1999};
years[0] = 1967;
for (int i=0; i<4; i++) {
NSLog(@"The year at index %d is: %d", i, years[i]);
}
years[4] 声明分配了能够存储四个int值得连续内存空间。
我们使用 {1968, …}的初始化语法初始化了数组,我们能够通过传递偏移在方括号里获取数组的元素值。
指针
指针是一个内存地址的引用。
指针删除了一个抽象层、是你能够看到。数值是如何存储的。
这样须要两个工具。
引用操作符能够返回变量内存地址。
这样你就能够创建一个指针。
解引用操作符能够返回内存地址的存储内容。
以下演示了,如何申明、创建、解除指针。注意一个指针就像定义一个通常的变量。可是就是在变量之前加入了*。
int year = 1967; // Define a normal variable
int *pointer; // Declare a pointer that points to an int
pointer = &year; // Find the memory address of the variable
NSLog(@"%d", *pointer); // Dereference the address to get its value
*pointer = 1990; // Assign a new value to the memory address
NSLog(@"%d", year); // Access the value via the variable
指针图形化的表演示样例如以下:
上面的样例,指针仅仅是一个非必须的变量的抽象。他的实际的用处。你能够在附近移动指针。
尤其是遍历数组,一个连续的内存空间。比方线面,通过指针迭代数组元素。
char model[5] = {'H', 'o', 'n', 'd', 'a'};
char *modelPointer = &model[0];
for (int i=0; i<5; i++) {
NSLog(@"Value at memory address %p is %c",
modelPointer, *modelPointer);
modelPointer++;
}
NSLog(@"The first letter is %c", *(modelPointer - 5));
当我们使用指针。++操作符将移动指针到下一个地址,我们能够输出地址通过含有%p修饰符NSLog。
相同,–操作符被用作减指针到之前的地址。
如上所看到的,您能够訪问相对当前地址的不论什么地址。
空指针
空指针是一个特殊的指针,不指向不论什么地址。
C语言中仅仅有一个空指针。他的类型是NULL 宏。主要表示变量为空,变量不能有一个正常的值。比方所看到的,通过空指正置空一个指针。
int year = 1967;
int *pointer = &year;
NSLog(@"%d", *pointer); // Do something with the value
pointer = NULL; // Then invalidate it
我们表示year 为空变量,能够通过设置为0实现,可是,对于year也是一个正常的值,而不是缺少值。
Void 指针
void 类型的指针是一个通用类型。它能够指向不论什么地址。因此,我们须要将void类型的指针转化成非void类型的指针。比方, (int *)申明将指正转化成int类型的指正。
int year = 1967;
void *genericPointer = &year;
int *intPointer = (int *)genericPointer;
NSLog(@"%d", *intPointer);
void 类型指正提供了非常多的灵活性。比方NSString 类定义例如以下方法。将C数组转化成Object-C的字符串。
- (id)initWithBytes:(const void *)bytes
length:(NSUInteger)length
encoding:(NSStringEncoding)encoding
bytes 參数指向C数组的内存第一个地址。length參数执行读取多少字节,encoding 參数如何解析字节。使用void类型的指针,这样bytes參数能够是不论什么字符数组。
Objective-C 中的数组
这是一些背景知识。可是您日常的Object-C开发中并不须要。我们必须理解。Object-C中的每个对象都是通过指针引用的。
比方,NSString 类型变量必须存储一个指针,而不是一个主要的变量。
NSString *model = @"Honda";
空指针在Object-C和C中是不一样的,在C中使用NULL。Object-C定义可自己的宏,nil,他是空。重要经验是,在引用Object-C对象指针中使用nil。而对于C指针使用NULL。
NSString *anObject; // An Objective-C object
anObject = NULL; // This will work
anObject = nil; // But this is preferred
int *aPointer; // A plain old C pointer
aPointer = nil; // Don't do this
aPointer = NULL; // Do this instead
整个Object-C语法都是和指正相关的。
定义了一对象指针之后,您基本就忘记了他是一个指针,由于使用和其它的变量一样。
我们将通过本教程的大量样例理解清楚。
总结
本章主要解说C语言的基础。
主要是想让大家熟悉变量、条件、循环、结构体、枚举、和指针。这些工具是构成不论什么Object-C程序的基础。
Object-C依赖C的这些基础结构。并且给与直接加入C++代码的选择。为了告诉编译器,编译的是C、C++或者Object-C,您能够将源码的文件扩展名改动为.mm。
这个独特的语言特征。打开了整个C/C++的大门,这是对于Object-C开发人员最大的恩惠。比方。您在开发IOS游戏,发现自己须要一个物理引擎,你能够使用注明的Box2D 包。不须要额外的工作。
下一章我们将通过学习函数,结束C语言的学习。在这之后,我们已经准备好学习Object-C类、方法、协议和其它面向对象的内容。
posted on 2017-08-16 20:46 gavanwanggw 阅读(255) 评论(0) 编辑 收藏 举报