2017-12-12 16:21:21 sz736659711 阅读数 242

官方文档中称oc是一门动态的语言

id类型定义了一个指向通用类型对象的指针。完全可以在声明一个指针变量时使用id作为其类型定义,但这样的话编译器就不能根据指针类型提供相应的信息。

这句话是什么意思呢?

id string = @"Hello,World";

    NSString *string2 = @"Hello";

    NSLog(@"长度:%lu",string2.length);

    NSLog(@"id长度:%lu",[string length]);

当我们定义一个NSString类型时,我们输入string2.时候会提示很多种方法。

而我们定义id类型时,系统会自动调用一个正确的类型给string. 此句代码中,系统会自动给string定为NSString类型。而我们string.的时候不会提示方法。

而我们可以自己输入调用NSString length的方法。 

那么是否会正确调用呢。我们运行后看见答案是

2017-12-12 15:59:27.430766+0800 Class[407:65927] 长度:5

2017-12-12 15:59:27.430811+0800 Class[407:65927] id长度:11


那么说明string是正确实现了NSString类型的方法的。

当我们输入

[someObject removeAllObjects];
不会提示错误!!! 但是由于NSString 无法响应removeAllObjects方法而产生异常错误


我们常用的 alloc init, 实际为  (id)alloc  (id)init;所以会正确返回你定义的类的实例



2016-03-22 15:36:00 chaoguo1234 阅读数 418

在Mac和IPhone上分别运行下面的程序:

        NSLog(@"char size = %lu", sizeof(char));
        NSLog(@"short int size = %lu", sizeof(short));
        NSLog(@"int size = %lu", sizeof(int));
        NSLog(@"long int size = %lu", sizeof(long));
        NSLog(@"long long int size = %lu", sizeof(long long));
        NSLog(@"float size = %lu", sizeof(float));
        NSLog(@"double size = %lu", sizeof(double));
        NSLog(@"pointer size = %lu", sizeof(int *));
        NSLog(@"BOOL size = %lu", sizeof(BOOL));
        NSLog(@"NSInteger size = %lu", sizeof(NSInteger));        

Mac(64位机器)上的输出为:

 

IPhone(64 为机器,不包括IPhone 5以及IPhone 5以下的机器,但是包括SE)上的输出为:

 

下面是IPhone中32位机器的输出(IPhone5及一下机器):

从输出上可以看到,64位机器的Mac和IPhone的数据长度一样,而32位的IPhone数据长度和64位机器大部分相同,不同之处为:

long类型在64位机器上是8字节,在32位机器上是4字节;

指针长度在64位机器上是8字节,在32位机器上是4字节;

NSInteger在64位机器上是8字节,在32位机器上是4字节

2015-08-16 21:06:28 lee89757 阅读数 310

1.    NS的由来:因为Obj-C不支持命名空间,所以为了避免重复,要在类前面加上自己特有的前缀,NS就是next step的意思。

2.    [[alloc] init]对比[new]的优势:就是能够在开辟了内存空间之后,可以自定义init方法来方便我们对开辟的内存空间初始化。

3.    获取字符串长度:length属性,NSUInteger类型,%lu

4.    根据索引获得单个字符:characterAtIndex:index方法,unichar类型,%c。索引是从0开始的,如果给定索引超出范围会导致异常,如果你给入的是一个负数,那么获得的值就是一个乱码。

5.    根据索引获得子串:substringFromIndex:NSUInteger方法,从给定的索引开始(包括索引位置)截取后面的子串;substringToIndex:NSUInteger方法,从头截取到当前的索引之前的字串(不包括索引位置);substringWithRange:NSRange方法,截取所给范围的子串,NSRange是一个结构体,里面有俩NSUInteger,一个是开始索引位置(包含索引位置),一个是截取的长度;

6.    根据字符串获得该字符串在另一个字符串的索引位置:rangOfString:NSString方法,返回一个NSRange数据;可以使用NSStringFromRange:NSRange把一个范围以字符串形式打印;如果你给的字符串不在当前字符串之中,则NSRange.location = -1;NSStringFromRange则会显示{901902910102,0}的结果。NSNotFound如果==NSRange.location;则就代表没有找到;

7.    字符串的判断:判断字符串是否为空:str == nil || str.lenth == 0;判断一个字符串是否以xxx开头:hasPrefix:NSString方法;判断字符串是否以制定的字符串结尾:hasSuffix:NSString方法,在开发中常用于判断文件格式;判断字符串内容是否相等:isEqualToString:NSString*方法,直接用== 符号判断的其实是指针地址;

8.    compare就是isEqualToString的增强版,返回一个enum枚举数据:NSComparisonResult:-1代表升续;0代表相等;1代表降序;按照每个字母Ascii码的值大小;

9.    模拟isEqualToString的内部实现:1.判断两个待比较的指针地址,如相等直接返回true;2.比较每一个字母,当发现不相同的情况返回false;

10. 基本数据类型转换成字符串:都可用用stringWithFormat:方法%d-int;%.nf-小数点保留n位的float;%@-NSString*;%.nf-小数点后保留n位double;%c-char;

11. 字符串转换成基本数据类型:intValue-int;floatValue-float;doubleValue-double;

12. 注意:当你把NSString转换成某种基本的数据类型时一定要确保字符串内的内容正确;

13. 将字符串全部转换成大写:uppercaseString;将字符串全部转换成小写:lowercaseString;将首字母大写:capitalizedString

14. 字符串重组:在字符串末尾拼接新字符串-stringByAppendingString:NSString;在制定的位置拼接字符串-stringByReplacingCharactersInRange:NSRangewithString:NSString*;这个NSRange的location就是开始拼接的位置,length则是开始位置之后会被替换的长度;把字符串中的每个指定字符替换成给定的其他字符:stringByReplacingOccurrencesOfString:NSString* withString:NSString*;

15. 把NSString写入文件:writeToFile:(NSString*)pathatomically:YES ecoding: (NSStringEncoding)NSUTF8StringEncoding error(NSError*);

16. 从文件中获取NSString:stringWithContentsOfFiles:(NSString*)path ecoding: (NSStringEncoding) error: (NSError*)

17. 可变字符串NSMutableString:继承自NSString,拥有NSString的所有属性和方法;

18. 可变字符串的initWithCapacity:NSUInteger传递的大小并不真的限制可变字符串的长度

19. 在可变字符串中setString初始化,appendString末尾拼接,insertString插入字符串,deleteCharactersInRange:NSRange删除给定范围的字符,replaceCharactersInRange:NSRangewithString:NSString用给定字符替换给定范围的字符;这些方法都返回void,都是修改当前调用这些方法的可变字符串对象的

2015-08-15 16:15:38 sdzh2012 阅读数 1963
1、认识指针
#include <stdio.h>
//基本数据类型作为函数参数传递是值传递
//void moveFront(int x ,int y)
//{
//    x  = x + 2;
//}
void test()
{
    //  确定当前坐标
    int x = 20;
    int y = 150;
    printf("%p\n",&x);
    printf("%lu\n",&x);

    *((int *)(0x7fff5fbff76c)) = 22;
    printf("(%d,%d)\n",x,y);
    //    moveFront(x, y);
    //    printf("(%d,%d)\n",x,y);

}

//如果你想访问指针所指向存储空间,就必须使用访问指针所指向的存储空间的操作符
void moveFront(int *x ,int *y)
{
//  x  = x + 2;//此时是改变指针的指向,而不是访问指针所指向的存储空间
    *x  = *x + 2;
}

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

    //  确定当前坐标
    int x = 20;
    int y = 150;
    printf("(%d,%d)\n",x,y);
    moveFront(&x, &y);
    printf("(%d,%d)\n",x,y);

    return 0;
}


2、指针的定义与初始化(重点掌握)


   内存中最小的存储单元:字节,每一个字节在内存中都有一个编号,这编号就是指针
 
  指针:内存地址
  有了指针你就有了打开这块内存钥匙,就可以操作这一块内存
 
  指针变量:存放内存地址的变量
  定义指针:指针所指向数据类型  * 指针变量名称;
 在的定义变量时候,*是一个类型说明符,说明定义这个变量是一个指针变量
  在不是定义的变量的时候,*是一个操作符,访问(读、写)指针所指向的那块存储空
    指针的初始化:
  
    注意点:
    1、只有定义没有初始化指针里面是一个垃圾值,这时候我们成为这个指针为野指针
    2、如果操作一个野指针
       2.1 程序崩溃
       2.2 访问不该你访问存储,操作潜在逻辑错误
    3、不可以使用整形常量赋值一个指针变量
       因为内存是操作系统分配我们的,不是我们随便取的
    4、什么类型的指针,只指向什么类型的变量
    5、多个指针可以指向同一变量
    6、指针的指向是可以改变的


#include <stdio.h>


//指针的定义
void test()
{
    int num = 10;
    
    //  定义一个指针变量
    int *p;
    p = #
    
    *p = 20;
    printf("num = %d\n",num);
}

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


// 先定义在进行初始化
    int num = 10;
//  定义一个指针变量p
    int * p;
    
//    *p = # // p 还有进行初始,不能够访问它所指向存储空间
    p = #//p 指向 num
    *p = 20;
    
    
//  定义指针变量的同时进行初始
    
    int num2 = 20;

    int *p2 = &num2;
    
    *p2 = 40;
    
    printf("%d,%d\n",num2,*p2);
    
// 不可以使用整形常量赋值一个指针变量
// 因为内存是操作系统分配我们的,不是我们随便取的
    
//    int *p3 = 100000;//此处是错误的
//    
//    *p3 = 10;
    
    p2 = #
    
    printf("%p\n",p2);
    
    char c = 'a';
    
    int *pc = &c;
    
    *pc = 10;
    
    printf("%p\n",p2);
    
    
    return 0;
}

3、多级指针


通过指针访问变量称为间接访问。由于指针变量直接指向变量,所以称为“一级指针”。而
如果通过指向指针的指针变量来访问变量则构成“二级指针”。

#include <stdio.h>

void test()
{
    int num = 10;
    
    int *p = #
    
    //  定义一个指针来指向变量p
    //  pp就是一个二级指针
    int **pp = &p;
    
    **pp = 30;
    printf("%d\n",num);
    
    int ***ppp = &pp;
    ***ppp = 50;
    printf("%d\n",num);
    
    //  四级指针
    int ****pppp = &ppp;
    ****pppp = 100;
    printf("%d\n",num);   
}
void readFile(char **error)
{
    *error = "读取错误";   
}

int main(int argc, const char * argv[]) {
  
//    char error[100];
    
    char *error;
    
    readFile(&error);
    
    printf("%s",error);
    
    return 0;
}

4、指针为什么要区分类型

   1、变量的地址是变量所在占存储空间的首地址
   2、指针变量仅仅可以存储一个地址编号,如果没有类型,当通过指针就不知道要访问多少个字节的存储空间
   3、指针区分类型是为了在通过指针访问它所指向的存储空间的时候,能够正确访问
   4、如果通过一个char类型的指针操作一个int的变量,如果值的二进制数据超过1字节,那么就造成数据错误
   5、如果通过一个int 类型的指针操作一个char变量,那么你就会修改了你不该修改的内存,造成程序逻辑错误
#include <stdio.h>
/*
   所有指针类型都是占用八个字节的存储空间
 
 
 */
void testEveryPointerIs8B()
{
    printf("%lu\n",sizeof(int *));
    printf("%lu\n",sizeof(char *));
    printf("%lu\n",sizeof(double *));
    printf("%lu\n",sizeof(float *));
    printf("%lu\n",sizeof(float **));
}



int main(int argc, const char * argv[]) {
    
    int num = 10;
    
    char *cp = #

    
    printf("%d\n",num);
    
    return 0;
}

5、指针运算概述
   指针变量:存放是内存字节的地址编号(无符号的整形数)
   指针:是运算受限的无符号的整形数
   运算运算:
   指针 + 整形数 === 指针变量中值 + sizeof(其所指向数据类型)
   指针 - 整数数 === 指针变量中值 - sizeof(其所指向数据类型)
   pointer1 - pointer2 = (pointer1中值 - pointer2中值) / sizeof(其指向数据类型) 
   赋值运算:
    =
    += 必须是一个整形数
    -= 必须是一个整形数
   比较运算
   ==
   != 
   >
   < 
   >=
   <=
   自增自减
   p++; p = p + 1;
   ++p; p = p + 1;
   --p;
   p--;
 
#include <stdio.h>


//算术运算
void test()
{
    int a = 10;
    
    int *p = &a;
    //  指针+1
    p = p + 1;
    
    
    int nums[5] = {1,2,3,4,5};
    
    int * pointer1 = nums;
    
    int * pointer2 = &nums[4];
    
    size_t size  = pointer2 - pointer1;    
    printf("%lu\n",size);        
    //  pointer1 + pointer2;
    //    pointer2 * pointer1;
    //    pointer1 / pointer2;
    //    pointer1 / 2;
}
//赋值运算
void test1()
{
    int a = 10;
    
    //    int *p = &a;
    
    int nums[] = {1,2,3,4,5};
    
    int *p = nums;
    int *p2 = nums;
    p += 2;
    p = p + 2;
    
    p -= 1;
        
    printf("%d\n",*p);   
}

//关系运算
int main(int argc, const char * argv[]) {
  
    int nums[] = {1,2,3,4,5};
    
    int *p = nums;
    p++;
    int result =  nums == p;
    result = p > nums;
    p--;
    result = p < nums;   
    result = p >= nums;
    result = p <= nums;   
    printf("%d\n",result);   
    return 0;
}
6、指针与一维数组(理解)

 数组像一个指针:访问数组中元素,使用数组与使用指向这个数组的指针是等价
 
 nums[1] ==== p[1]
 nums+1  ==== p + 1;
 
 nums[1] 的本质 *(nums + 1)
 指针 + 整数 =====  指针中的值 + sizeof(所指向的数据类型) * 整数
//    int nums[] = {1,2,3,4,5};
//
//    int *p = nums;
double nums[] = {1.0,2.0,3,4,5};
double * p = nums;
//    printf("%d,%d,%d,%d,%d,%d\n",nums[1],p[1],*(nums + 1),*(p + 1),*(++p),。);
printf("%p\n",nums);
printf("%p\n",nums+2);
printf("%p\n",p);
printf("%p\n",p+2);
  数组不是一个指针
   1、sizeof(array) != sizeof(pointer):当一个数组赋值一个指针变量的时候,那么数组中有些信息就丢失了,比如数组长度,这种现象指针信息遗失
   2、指针的指向是可以改变的,数组的指向是不可以改变
   3、array == &array 数组名就是数组地址,pointer != &pointer : 指针所指向地址不是指针本身地址

#include <stdio.h>
int main(int argc, const char * argv[]) {
    int nums[] = {1,2,3,4,5};
    int *p = nums;
    p = nums;
//    nums = nums + 1;    
     printf("%lu,%lu\n",sizeof(nums),sizeof(p));       
    printf("%p\n",nums);
    printf("%p\n",&nums);      
    printf("%p\n",p);
    printf("%p\n",&p);        
    return 0;
}

7、指针与二维数组
指针数组与二维数组指针变量的区别
应该注意指针数组和二维数组指针变量的区别。这两者虽然都可用来表示二维数组,但是其表示方法和意义是
不同的。
二维数组指针变量是单个的变量,其一般形式中"(*指针变量名)"两边的括号不可少。而指针数组类型表示的
是多个指针(一组有序指针)在一般形式中"*指针数组名"两边不能有括号。例如:
int (*p)[3];
表示一个指向二维数组的指针变量。该二维数组的列数为3或分解为一维数组的长度为3。
int *p[3]
表示p是一个指针数组,有三个下标变量p[0],p[1],p[2]均为指针变量。

#include <stdio.h>

void test()
{
    
    int nums[3][2] = {{1,2},{3,4},{5,6}};   
    int *p = nums[0];    
    printf("%p\n",p);
    printf("%p\n",nums);    
    for (int i = 1; i < 6; i++) {
        printf("%d ",*(p + i));
    }
       
}
/*
  定义指针数组的格式:
  数据类型 * 指针变量名称[指针个数]
 */
void test2()
{
    int nums[3][2] = {{1,2},{3,4},{5,6}};
    
    //    int * p[2] = {nums[0],nums[1]};
    //        p = nums;
    //
    //    printf("%d\n",p[0][1]);
    
    int a = 10;
    int b = 20;
    int c = 30;
    
    int *p = &a;
    
    //    *p === p[1]; 没有这么写的
    
    int *ps[3] = {&a,&b,&c};
    
    printf("%d,%d,%d",*ps[0],*ps[1],*ps[2]);
    
}
/*
  定义一个指向一维数组的指针
  数据类型 (*指针名称)[所指向的一维数组的元素个数]
 
  指针 + 整数 === 指针中的值 + 所指向数据类型的长度 * 整数
 */

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

    int nums[3][2] = {{1,2},{3,4},{5,6}};
    
    int (*ps)[2];
    
    ps = nums;//可以认为ps 与 nums是等价的 
    int num = ps[0][1];
    printf("%d\n",num);   
    printf("%p\n",nums);
    printf("%p\n",nums+1);    
    printf("%p\n",ps);
    printf("%p\n",ps+1);    
    for (int i =0 ; i < 3; i++) {
    
        for (int j = 0; j < 2 ; j++) {
            printf("%d ",ps[i][j]);
        }
        printf("\n");
    }
    
//    nums   nums[0]
    
//    相同点:对应地址都是一样的
//    不同点:指针类型是不同
//    nums + 1 = nums + sizeof(nums[0])
//    nums[0] + 1 = nums + sizeof(int)
    
//   sizeof(nums) 二维数组所用占用存储空间字节数
//   sizeof(nums) / sizeof(int) 二维数组中一共有多少个int的数据
    
    int *p = nums[0];
    for (int i = 0; i < sizeof(nums) / sizeof(int); i++) {
        printf("%d ",p[i]);
    }
    
  
    return 0;
}


2015-10-28 20:30:10 ywm04050712 阅读数 288

1.&是取地址符,可以查看一个变量的地址(内存首地址),*是取值符,输出指针地址用%p

2.打印字节长度

short  b = 12;

short  *p = &b;

printf("sizeB = %lu\n", sizeof(b));

printf("sizeP = %lu\n", sizeof(p));

输出结果:



//不管定义的数据类型是什么,指针变量所占字节都为8,这与操作系统的位数有关,64位的占8个字节,32位的占4个字节。

来看看怎样把64位的操作系统换成32位的

(1)在项目中找"Build Settings"->"Architectures"->第二个"Standard.……",点击"Standard……",在弹出的框里选择32位的系统



(2)不要以为这样就行可以了,回到程序里运行一下就可以看到还有错误的


(3)打开原来的界面,在搜索栏里所搜"gar", 就会出现有关于Object-C一栏,把"yes"改为"no"就行了。

修改前:


修改后:


这样就可以运行程序,输出p的字节长度为4,也就是操作系统所占字节数。

修改后的结果:


(4)最后,换回64位的原路返回就行了!

3.注意区分

int *j = &a;

如果出现*的地方,前面有类型修饰符,此时*仅仅起到标示的作用,告诉编译器这是一个指针变量。

*j = 523;

如果出现*的地方前面没有任何类型修饰符,此时的*代表取值操作符,它会把指针指向的区域取出来。

j ;

如果前面没有*和类型修饰符,那么这个变量就是一个指针变量,它里面存储某一内存地址。






没有更多推荐了,返回首页