oc语言学习之基础知识点介绍(五):OC进阶

一、点语法介绍

/*
 以前封装后,要给属性赋值,必须调用方法
 这样做,有两个缺点:
                1.代码量多,调用方法要写的东西多。
                2.看起来并不像是给属性赋值,也不像取值。

 我们用点语法就可以更好的解决!

    点语法的语法:
                对象.属性;
            注意:这里的属性不需要加_

                对象.属性 = 值;

    点语法的本质:
            其实就是调用getter或者setter方法。

 点语法注意事项:
        1.在类的方法里面如果用self.age 这个是调用方法,self->_age 是直接调用成员变量。
        2.千万记得不要在setter或者getter方法里面用点语法,否则,死循环。
        3.用点语法之前必须保证你的setter和getter方法的方法名符合命名的规范。
 提示:点语法,也可以称之为 语法糖。
        本质可以理解为是编译器的特性。
        因为其他面向对象的语言都是用.来访问属性。
*/

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [Person new];
//        [p setName:@"刘德华"];
        p.name = @"张学友"; //这一句就相当于上一句,编译后也是编译成 [p setName:@"张学友"];
//        [p setAge:16];
        p.age = 16; //这一句就相当于上一句
//        [p setWeight:100];
        p.weight = 100; //这一句就相当于上一句
//        NSLog(@"名字=%@ 年龄:%d",[p name],[p age]);
         NSLog(@"名字=%@ 年龄:%d",p.name,p.age);
    }
    return 0;
}

二、@property和synthesize关键字

/*
 @property
        作用:帮我们生成setter和getter方法的声明。
        语法:
            @property  类型  属性名;
            注意:属性名不加_
如果只用@property关键字的话,在实现类中,setter和getter方法需要自己实现。

既然有关键字可以生成setter和getter方法的声明,肯定就有关键字可以生成setter和getter方法的实现。
 @synthesize:
        作用:自动生成getter和setter方法的实现

        语法:
            @synthesize 特性名(属性名)

    @synthesize做了多少事:
                1.生成getter和setter方法的实现

                2.还会生成一个私有的成员变量,成员变量名字就是特性名

                3.实现的方法里是给自己生成的那个私有成员变量赋值

                4.如果想指定给某个成员变量赋值,就在特性名后面加一个 =  成员变量名;
                        例:@synthesize name = _name;

                5.如果你想过滤,就自己重写

    批量生成方法的实现:
                语法:
                    @synthesize  特性名1,特性名2………………特性名n

    批量生成方法的声明:
                语法:@property  类型  特性名1,特性名2………………特性名n
                例:@property NSString *name,*nickName;

            注意:批量生成时,类型必须一致
*/
#import <Foundation/Foundation.h>
@interface Person : NSObject{
    NSString *_name;
    int _age;
}

//这样就会给_name封装getter和setter的声明
@property NSString *name;
/*
  -(void)setName:(NSString *)name;
  -(NSString *)name;
*/
//这样就会给_age封装getter和setter的声明
@property int age;
/*
 -(void)setAge:(int)age;
 -(int)age;
*/
-(void)sayHi;
@end

//
//  Person.m
//  OC第五天
//
//  Created by iOS001 on 15/11/5.
//
//

#import "Person.h"

@implementation Person

//@synthesize name;//自动生成了_name的getter和setter的实现
//
//@synthesize age;//自动了_age的getter和setter的实现

//@synthesize name = _name;//自动生成了_name的getter和setter的实现
//
//@synthesize age = _age;//自动了_age的getter和setter的实现

@synthesize name = _name,age=_age; //批量操作。

-(void)setAge:(int)age{
    if (age < 0 || age > 120) {
        _age = 18;
    }else{
        _age = age;
    }
}

/*
-(void)setName:(NSString *)name{
    _name = name;
}

-(NSString *)name{
    return _name;
}

-(void)setAge:(int)age{
    _age = age;
}

-(int)age{
    return _age;
}
*/
@end

上面的语法是在Xcode 4.4以前的用法,在现在的新版XCode中,可以不这么复杂。

/*
 @property增强使用:
            用法跟之前的@property用法,完全一样
            但是,它除了能生成声明以外,还能声明实现
            而且,它还能帮我们生成私有的成员变量!
    做的事:1.声明属性的setter和getter方法的声明
                    2.实现属性的setter和getter方法
                    3.生成一个以特性名加下划线的私有成员变量

    注意:如果类的属性中已经存在同名的带下划线的成员变量,那么不会帮我们在生成了,操作的就是这个带下划线的成员变量。

*/

#import <Foundation/Foundation.h>
@interface Person : NSObject{
    NSString *_name;
}
@property NSString *name;

@end

#import "Person.h"

@implementation Person

@end

/*
 [email protected]帮我们生成的实现,是没有任何逻辑过滤,如果我们要过滤,就重写。

 2.如果getter方法和setter方法都有重写的话,那么@property不会帮我们生成私有成员变量了。
    如果非要两个都重写的话,就自己定义一个成员变量。
*/

#import <Foundation/Foundation.h>
@interface Person : NSObject{
    int _age;
}

@property NSString *name;

@property int age;
@end

#import "Person.h"
@implementation Person
-(void)setAge:(int)age{
    if(age<0 ||age>150){
        _age = 16;
    }else{
        _age = age;
    }
}

-(int)age{
    return _age;
}
@end

#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {

        Person *p = [Person new];

        p.name = @"草稚京";

        p.age = -30;

        NSLog(@"p.name=%@    p.age=%d",p.name,p.age);

    }
    return 0;
}

三、动态类型和静态类型的概念

/*
 动态类型:
    简单来说就是编译的时候,并不知道具体是什么类型的对象,直到运行的时候才知道是什么类型的对象
            所以,运行的时候确定了对象的类型,然后才会去找到对应的类型里看有没有这个方法,如果有这个方法就执行,没有这个方法就报错

 静态类型:
    就是编译的时候就知道是什么类型了
        比如说 int  char  float double
        int nums[10];  一旦定义就不可能再调用char *数组,或者改成char *数组

动态类型的好处:
                    1.灵活
                    2.为了实现多态
*/
//比如说我现在有3个类,Person、Student、Teacher,三个类中都有SayHi方法。Student和Teacher是继承并重写了Person类中的SayHi方法。
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
#import "Teacher.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        /*
        Person *p = [Person new]; //动态类型

//      [p study];//因为编译阶段,它并不知道你是什么对象,所以不可能让你调用这个方法
        [p performSelector:@selector(study)];//因为这是一个运行时才绑定的方法
        */
        /*
        printf("请输入序号--0--Person  1--Student  2--Teacher\n");
        int num;
        scanf("%d",&num);
        Person *p;
        switch (num) {
            case 0:
                p = [Person new];
                break;
            case 1:
                p = [Student new];
                break;

            case 2:
                p = [Teacher new];
                break;
            default:
                p = [Person new];
                break;
        }
        [p sayHi];//现在编译器知道是哪个对象的sayHi吗???只能运行时才知道??
        */
    }
    return 0;
}

四、id类型的使用

/*
 动态类型:
        在编译的时候并不知道具体是什么类型的对象,在运行的时候知道是什么类型的对象。
 NSObject:根类。所有的人直接或者间接的继承自NSObject。

 两个检查:
        编译期检查:
                因为OC是动态类型语言,那么也就是说类型只有在运行的时候才会被确定,所以在编译的时候没法检查真正指向的对象是类型,所以更加没法知道你指向的对象类型是否包含某个方法
                检查范围:1.去检查它的指针类型里面是否有这个成员(属性、方法),如果有就让你编译通过,如果没有
                        2.就去父类的父类找,如果有,就编译通过,如果没有,再继续找
                        3.直到找到NSObject都还没有的话,就报错。
            一句话概括:就是只会去赋值号左边的类型里找。

        运行期检查:
                就是运行的时候类型就确定了,所以就可以检查真正的那个对象里面包不包含这个成员了。
                1.先去真正的对象类型里面找,如果找到就执行,如果没找到就继续往父类找。
                2.去父类找,找到就执行,没找到就继续往父类的父类找,找到就执行,没找到继续往上找。
                3.直到找到NSObject还没有,那么就程序运行的时候崩掉(闪退)。

 我希望有一种类型的指针可以指向我任意的对象,并且,我用中括号的方式来调用方法,又不会经过编译期检查(编译时不会报错),有没有呢?

 id类型:
    其实就是一个万能指针,所以任何对象都可以指向。
    非常方便的体现什么叫动态类型。
    任意对象都可以指向!

 好处:灵活,任意类型都可以指向,哪怕上一步指向Student对象,下一步可以立即再指向NSString

 缺点:因为编译器没有检查类型有没有方法,所以如果直接调用可能会报错

 id是万能指针,任意类型的对象都能指向.

 然后用id类型的变量可以调用方法,但是编译器不一定会报错,只能在运行时如果没有才报错。

 id需要注意的地方:
                1.用id类型指向的对象,不能用点语法
                2.那能不能直接调用方法来赋值呢?可以!能不能用方法取值?也可以!
 id的作用:
        1.指向任意类型
        2.当做参数传递
            注意:虽然任意类型的对象都可以传,但是运行时可能会报错
        3.当做返回值返回
             注意:任意类型都可以接收,那么很可能运行时会出问题
*/

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        /*
        Person *p = [Student new]; //动态类型,只有运行的时候才直到指向的是Student对象

        //[p sayHi];//编译器的时候也是去Person找,只不过正好这时候Person有

        [p study]; //此时会报错,因为这时候是编译期检查,像这种中括号调用方法,都是编译期检查
        */

        /*
        id p = [Student new];

        [p study]; //有没有经历运行期检查??肯定有!

        [p sayHi];

        NSLog(@"%@",p);

        p = @"哈哈哈哈哈哈";

        NSLog(@"%@",p);

         p = [Person new];
        */

        id p = [Person new];

        [p study];//运行的时候才知道是Person类型,但是Person及其父类都没有study方法,所以运行报错

        /*
        [p performSelector:@selector(test)]; //编译的时候没法检查

        //[p sayHi];//而是先在真正指向的对象——student里面先找,找到了就执行

//        NSLog(@"%@",p);
//
//        [p study]; //Xcode编译的时候只会根据你的指针类型来检查,而并不会根据你具体指向的对象类型来检查
//
//        NSObject *obj = [Student new];
//
//        NSLog(@"%@",obj);
//
        */
    }
    return 0;
}

五、动态类型和动态方法的检测以及响应方法的方法

   1、态类型的检测

/*

 动态类型检测:我们自己写代码来检测对象是否属于一个类。

 因为我们之前用id类型是可以调用任意方法的,编译器不会报错,但是运行时报错。

 所以我们就在想,能不能在调用方法之前,我们自己写代码判断一下id类型指向的对象是不是某一个类,如果是我才让你调用。

 动态类型检测的方法:
    1)
            语法:[对象  isKindOfClass:Class];
        注意:这个方法是用来检测一个对象是不是右边这个类的对象,或者是这个类子类的对象,如果是则返回YES,如果不是返回NO
            例: [p  isKindOfClass:[Person class] ];
            解释:判断p这个对象是不是Person类的对象,或者是Person子类的对象,如果是返回YES,如果不是返回NO。
        注意:包括子类的子类,子类的子类的子类…………………………

    2)
        [对象  isMemberOfClass:Class];
        判断 对象 是不是某个类的对象,不包括子类。
        跟上面的区别只在于,判断的时候不包括子类。
    总结:isKindOfClass不能确切的确定是哪一个具体的类的对象(因为还能包括子类)。
         isMemberOfClass 可以确切的知道是不是某一个类(因为不包括子类)。

    3)
        注意,接下来是类方法
        [类名  isSubOfClass:Class];
        判断某一个类,是否是另外一个类的子类,包括子类的子类,以及自己类。
        也就是说一个类如果是右边这个的类的本类,或者子类或者子类的子类都会返回YES,否则返回NO。
*/

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
#import "GoodStudent.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        /*
        id obj = [Person new];

        //我们能不能在调用这个方法之前,自己写代码判断一下,obj是不是Student类型,如果是,我就让你调用,不是,就
        //[obj study];//编译不报错,运行报错

        if([obj isKindOfClass:[Student class]]){//判断obj是不是student类型

            //如果是就执行
            [obj study];

        }else{

            NSLog(@"obj不是Student类型");
        }
        */

        //isKindOfClass的用法
        /*
//        id obj = [Person new];

//        BOOL res = [obj isKindOfClass:[Student class] ];
//
//        NSLog(@"%d",res); //0

//        BOOL res = [obj isKindOfClass:[Person class] ];
//
//        NSLog(@"%d",res); //1

//        BOOL res = [obj isKindOfClass:[NSObject class] ];
//
//        NSLog(@"%d",res);//1

        id obj = [GoodStudent new];

        BOOL res = [obj isKindOfClass:[Person class]];

        NSLog(@"%d",res);//也是1
        */

        //isMemberOfClass的用法
        /*
        id obj = [GoodStudent new];

        BOOL res1 = [obj isKindOfClass:[Person class] ];//这种方法包括子类

        BOOL res2 = [obj isMemberOfClass:[Person class] ];//这种方法不包括子类

        NSLog(@"res1=%d   res2=%d",res1,res2);//1   0
        */

        //isSubOfClass的用法(类方法)
        /*
//       BOOL res  = [Student isSubclassOfClass:[Person class]];
//
//        NSLog(@"%d",res);//1

//        BOOL res  = [GoodStudent isSubclassOfClass:[Person class]];
//
//        NSLog(@"%d",res);//1

//        BOOL res  = [Person isSubclassOfClass:[Person class]];
//
//        NSLog(@"%d",res);//1

        //这一句是问Person是Student子类吗?
        BOOL res  = [Person isSubclassOfClass:[Student class]];

        NSLog(@"%d",res);//0
      */
    }
    return 0;
}

2、动态方法的检测

/*
 因为之前用id类型调用方法,可能会出错,所以我们想先判断一下这个类型是不是拥有某个方法。
 之前的做法是,判断一下某个对象是不是某个类的。那能不能具体一点,直接判断一下某个对象有没有某个方法呢?
 动态方法检测!
    1.(重点)
        [对象 respondsToSelector:SEL];
    例:[obj respondsToSelector:@selector(study)]
        这是在判断obj有没有study这个方法,如果有返回YES,如果没有返回NO
    注意:如果传入的是类方法,那么会返回0,因为类方法不属于对象
    2.类方法(用的少)
        [类名 instancesRespondToSelector:SEL];//判断类方法的
        判断某个类是否有某个对象方法,如果有则返回YES,否则返回NO
        跟上面效果一样,只不过这是一个类方法用类名判断

*/

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"
#import "GoodStudent.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        /*
        id obj = [Student new];

        //[obj study];//是不是要在这之前判断一下obj指向的对象有没有study这个方法,如果有才调用
        if( [obj respondsToSelector:@selector(study)] ){
            [obj study];
        }else{
            NSLog(@"没有study方法");
        }
        */

        //respondsToSelcetor的用法
        /*
        id p = [Person new];
        BOOL res = [p respondsToSelector:@selector(clsPerson)];
        NSLog(@"%d",res);//0
        */
//        id obj = [Person new];
//        BOOL res = [Person instancesRespondToSelector:@selector(sayHi)];//只能判断对象方法
//        NSLog(@"%d",res);
    }
    return 0;
}

3、响应方法的方法

/*

 响应方法就叫调用方法。
    以前我们用[]
 现在我们用响应方法的方法:
       [对象  performSelector:SEL];
            调用某个方法,是没有参数的时候
            例: [obj performSelector:@selector(sayHi)];
       [对象 performSelector:SEL withObject:id];
            调用某个方法,是有1个参数的情况
            例:[obj performSelector:@selector(sayName:) withObject:@"刘德华"];
       //最多只有2个参数
       [obj performSelector:(SEL) withObject:(id) withObject:(id)
            这是有两个参数的情况
            例:[obj performSelector:@selector(sayName:andNickName:)
                                                withObject:@"发哥"
                                                withObject:@"花卷"];

*/
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        id obj = [Person new];

        //这个是没参数的时候
//        [obj performSelector:@selector(sayHi)];
//        if([obj respondsToSelector:@selector(sayName:)]){
//            //这个是有1个参数的时候
//            [obj performSelector:@selector(sayName:) withObject:@"刘德华"];
//        }else{
//            NSLog(@"没有这个方法");
//        }

        if([obj respondsToSelector:@selector(sayName:andNickName:)]){
            //这个是有1个参数的时候
            [obj performSelector:@selector(sayName:andNickName:)
                                            withObject:@"发哥"
                                            withObject:@"花卷"];
        }else{
            NSLog(@"没有这个方法");
        }
    }
    return 0;
}

六、构造和重写

1、构造
/*
创建一个对象:
    [类名  new];
 new关键字做了三件事:
            1.开辟堆空间(相当于创建对象)
            2.初始化对象
            3.返回对象(返回堆空间首地址)

 其实new关键字它并不能开辟堆空间和初始化对象
 而是调用了两个方法,一个是alloc,一个是init
 alloc开辟堆空间(创建对象),然后会返回这个对象
 会调用这个alloc返回的对象的init方法,就是初始化对象的
 init方法又会返回这个对象(堆空间地址)
 构造方法是什么?
        构造方法其实就是初始化对象的方法,也就是说init就是我们的构造方法
 [Person new]   相当于 [ [Person alloc] init ];
*/

#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *p = [Person new]; //创建了一个person对象并且初始化
        //其实上面的语句类似于下面的步骤
//        Person *p2 = [Person alloc];//创建对象
//        Person *p3 = [p2 init];//初始化对象
        //上面两句可以合并到一句
        Person *p2 = [[Person alloc] init];
    }
    return 0;
}
2、重写
/*
 init方法会帮我们初始化对象为0,对象类型初始化为nil。
 因为默认的只会帮我们初始化为0,我想以后创建对象,都是初始化为我指定的值。
 那么就需要重写init方法,因为init方法,因为父类是默认初始化为0,我重写就自己重新赋值就好了。
 重写init方法必须符合写法规范
        方法体要遵从以下规则:
                    if( self = [super init] ){
                        //做想初始化的事
                    }
                    return self;

    因为有些属性是父类里面提供初始化的,所以一定要加[super init],因为初始化的时候可能会未知原因出错,所以需要判断一下。

 instancetype是什么?
    之前可以用id作为返回值,但是不安全,因为我可以返回任意类型。
    比如说:我其实想返回一个Person对象,但是你给我返回一个OC字符串。。。。
    那么编译并不会报错,但是运行时可能出现严重的问题!
    所以,问题来了:有没有一种东西,可以让我返回类型,并且安全:意思就是你返回的对象一定是我这个类的。
就要用instancetype
    instancetype还可以代表返回的是本类或者子类
    注意:instancetype只能做方法的返回值,不能做参数,也不能做类型来定义
 总结:instancetype主要是用来返回对象的,而且返回的是本类或子类的对象
*/

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Student.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        /*
        Person *p = [Person new];

        [p sayHi];//null 0
        */

//        Person *p = [Person dedaoPersonInstance];
//
//        [p sayHi];
//
//        //这里得到的究竟是Person呢还是Student??
//        Student *s = [Student dedaoPersonInstance];
//
        //Person *p = [[Person alloc] init];//因为init要返回一个对象,所以用instancetype,因为子类也可能要通过int方法返回对象
        Student *s = [[Student alloc] init];
        [s sayHi];

    }
    return 0;
}

//在Person类的实现类中
+(instancetype)dedaoPersonInstance{
    Person *p = [self new]; //当然可以,谁调用就是谁,self就代表Person
    return p;
//    return @"哈哈哈哈";
}

/**
 *  重写构造方法
 *  返回初始化的对象
 */
-(instancetype)init{
    if(self = [super init]){
        //现在初始化为以下的值了
        _name = @"刘大同";
        _age = 16;
    }
    return self;
}
//在Student实现类中
#import "Student.h"
@implementation Student
-(instancetype)init{
    if(self = [super init]){
        _stuNo = 1;
    }
    return self;
}
-(void)sayHi{
    NSLog(@"name=%@,age=%d,id=%d",_name,_age,_stuNo);
}

@end
3、自定义构造方法
/*
 之前重写构造方法,初始化的值都已经固定写死了,不灵活了
 如果我们想一个对象初始化的时候按照我给的值来初始化,怎么办?
 就要自定义构造方法,自定义的构造方法里面要给参数
 步骤:
        1.是一个对象方法
        2.以initWith开头,后面接XXXXX
        3.有参数(几个参数,根据你想初始化几个值确定)
        4.有返回值,类型是instancetype

    注意:方法体里面也要遵从规范:
                if(self = [super init]){
                    //初始化的语句
                }
                return self;
*/

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {

//        Person *p = [[Person alloc] init];
//
//        [p sayHi];

        //一定要会用,以后也会经常用到
        Person *p = [[Person alloc] initWithName:@"孙悟空" andAge:99];

        [p sayHi];

    }
    return 0;
}

#import "Person.h"

@implementation Person
-(instancetype)initWithName:(NSString *)name andAge:(int)age{
    if(self = [super init]){
        _name = name;
        _age = age;
    }
    return self;
}

+(instancetype)dedaoPersonInstance{

    Person *p = [self new]; //当然可以,谁调用就是谁,self就代表Person
    return p;
//    return @"哈哈哈哈";
}

/**
 *  重写构造方法
 *  返回初始化的对象
 */
-(instancetype)init{
    if(self = [super init]){
        //现在初始化为以下的值了
        _name = @"刘大同";
        _age = 16;
    }
    return self;
}
-(void)sayHi{
    NSLog(@"name=%@  age=%d",_name,_age);
}
@end
时间: 2024-10-03 15:25:04

oc语言学习之基础知识点介绍(五):OC进阶的相关文章

oc语言学习之基础知识点介绍(二):类和对象的进一步介绍

一.类.对象在内存中的存储 /* 内存分区: 栈:局部变量 堆:程序员自己写代码申请开辟的 程序员自己维护,编译器现在帮我们自动优化了,它在合适的给我们加上了释放空间的语句,所以我们现在写的对象不会造成内存泄露 全局区:所有的全局变量和静态变量 常量区:所有的常量 代码区:程序编译后的指令集 类是模板,肯定需要存在内存里面,因为实例化对象的时候需要根据这个模板来创建,那么存在内存里面,存在哪呢?? 类模板存在:全局区! 存的是:类的描述,还有所有的方法实现 每个对象都会有一个系统给我们的isa指

oc语言学习之基础知识点介绍(一):OC介绍

一.第一个OC程序 #import <Foundation/Foundation.h> //导入头文件 int main(int argc, const char * argv[]) { //main函数 @autoreleasepool {//自动释放池,我们现在写代码最好都写这里面 NSLog(@"Hello, World!"); //输出语句 } return 0; //退出程序,返回一个值给系统看 } 二.OC中的字符串 /* 前缀的概念:(了解一下) 提供框架的作

oc语言学习之基础知识点介绍(四):方法的重写、多态以及self、super的介绍

一.方法重写 /* 重写:当子类继承了父类的方法时,如果觉得父类的方法不适合,那么可以对这个方法进行重新实现,那么这个就重写. 注意:也就是说,一定只能发生在父类和子类关系中. 然后是子类重新实现父类的方法,绝对不是再写一个自己类的方法. 代码中原话叫:子类重写父类方法. 因为父类定义的方法不一定适用于子类. 注意:如果有重写,那么调用的是自己重写后的方法,如果没有重写,那么就调用的是父类的方法. 所以我们方法有一个执行的过程: 1.先去自己类里面找这个方法,如果找到就执行. 2.如果没找到,就

c语言学习之基础知识点介绍(三)

本节继续介绍c语言的基础知识点. scanf函数:用来接收用户输入的数据. 语法:scanf("格式化控制符",地址列表); 取地址要用到取地址符:&(shift+7) 例如:int num =0; csanf("%d",&num);printf("num = %d \n",num); 注意:格式化控制符前面要求输入什么类型的数据,那么地址列表那里就必须只能放相应类型变量地址.输入值的时候可以指定输入值的分隔符, 也可以 默认用回

c语言学习之基础知识点介绍(五)

本节主要说关系运算式和逻辑运算式. 一.关系运算式 1.等于(==):判断左边的表达式是否等于右边的表达式 2.大于(>):判断左边的表达式是否大于右边的表达式 3.大于等于(>=):判断左边的表达式是否大于等于右边的表达式 4.小于(<):判断左边的表达式是否小于右边的表达式 5.小于等于(<=):判断左边的表达式是否小于等于右边的表达式 6.不等于(!=):判断左边的表达式是否不等于右边的表达式 //注意:c语言中,关系运算所得结果只有0和1,0代表false(假),1代表tr

c语言学习之基础知识点介绍(一)

本系列是为了学习ios做准备的,也能作为c语言入门的教程看看. printf函数: printf函数作为输出语句,主要的作用个就是输出用户想输出的语句. 例如:printf("我是一个大帅哥~~"); printf("数字1=%d,数字2=%d",10,20);//%d接下来会在一起解释. /* %d:填入int,short型的数据,例如printf("数字1=%d,数字2=%d",10,20); %ld:填入long型的数据,例如printf(

c语言学习之基础知识点介绍(十三):枚举的介绍和使用

一.枚举的介绍 /* 枚举:限制的待选项. 语法: enum 枚举名{ 选项1, 选项2, 选项3, ........ 选项n }; 注意:枚举中,选项之间用 , 隔开,最后一个不用加 , :并且枚举已 ; 结尾. 声明枚举变量: enum 枚举名 变量名 ; 例如:enum qHand qh; 赋值: 1.先声明,后赋值 enum 枚举名 变量名 ; 变量名 = 枚举项; 例如: enum qHand qh; //qh是变量名,enum qHand 是类型 qh = 石头; 2.声明的时候初始

c语言学习之基础知识点介绍(二十):预处理指令

一.预处理指令的介绍 预处理命令:在编译之前触发的一系列操作(命令)就叫预处理命令. 特点:以#开头,不要加分号. #include: 文件包含指令 把指定文件的内容复制到相应的位置 #define: #define 宏名 替换的值; 宏.宏定义或者还叫宏代换. 作用:就是在编译之前把所有用到这个宏的地方,替换成你指定的东西 规范:宏名大写,可以跟变量区分开来 之前学的宏: INT32_MAX INT32_MIN 宏不占据内存空间,只是帮你做简单的替换. 注意: 1.宏只是简单的替换,不参与编译

c语言学习之基础知识点介绍(十):内存空间模型、地址解释及指针变量

一.内存 /* 内存: 存在内存里的. 内存分了N多个小空间,每个小空间1个字节 每个小空间有它自己的地址.每个地址之间差1 int类型占用4个字节,等于占了4个空间(有4个地址),不需要记住4个地址,而记住首地址就行了(因为首地址相当于入口或者生活中的门) 指针: 指针就是地址,地址就是指针. 地址:内存的地址 内存中的地址: 其实也是从1开始编号,然后一直自增 1M内存,1024个地址 0x7fff5fbff7cc:这叫16进制 十进制:逢10进1 有:0 1 2 3 4 5 6 7 8 9