8086 汇编(十)

cmp指令、jne指令 与 flags寄存器

  • flags寄存器(标记寄存器):CPU 中专门用于存储 逻辑判断 结果的寄存器。不同型号的 CPU,flags寄存器 的位数可能不同(8bit、16bit、32bit、64bit),每种型号的 CPU 都会提供一张 结果状态表,用于说明 flags寄存器 每个bit 所代表的含义。

  • cmp(compare)指令:用于比较两个操作数的大小,并将结果状态记录到 flags寄存器 中。cmp指令 通过对两个操作数做减法,来实现比较功能。

  • jne(jump not equal)指令:判断 flags寄存器 中的对应 bit 的状态,来决定是否跳转到指定的标号处执行指令(一般是当 ZF== 0,即 ZF 为假,转至标号处执行)。

  • 在 Objective-C 中编写的判断语句如下

    int main(int argc, const char * argv[]) {
    
    	int a = 10;
    	if (a == 9) {
    		NSLog(@"a == 9");
    	} else if (a == 10) {
    		NSLog(@"a == 10");
    	} else if (a == 11) {
    		NSLog(@"a == 11");
    	} else {
    		NSLog(@"unknow");
    	}
      
    	return 0;
    }
    
  • 其对应的汇编代码如下

    Test`main:
      0x100000ed0 <+0>:   pushq  %rbp
      0x100000ed1 <+1>:   movq   %rsp, %rbp
      0x100000ed4 <+4>:   subq   $0x20, %rsp
      0x100000ed8 <+8>:   movl   $0x0, -0x4(%rbp)
      0x100000edf <+15>:  movl   %edi, -0x8(%rbp)
      0x100000ee2 <+18>:  movq   %rsi, -0x10(%rbp)
      0x100000ee6 <+22>:  movl   $0xa, -0x14(%rbp)		   ; int a = 10
      0x100000eed <+29>:  cmpl   $0x9, -0x14(%rbp)		   ; if (a == 9)
      0x100000ef1 <+33>:  jne    0x100000f0d               ; <+61> at main.m:16:18,如果 a != 9,则跳转到 0x100000f0d(即<+61>)处执行指令
      0x100000ef7 <+39>:  leaq   0x10a(%rip), %rax         ; @"a == 9"
      0x100000efe <+46>:  movq   %rax, %rdi
      0x100000f01 <+49>:  movb   $0x0, %al
      0x100000f03 <+51>:  callq  0x100000f70               ; symbol stub for: NSLog
      0x100000f08 <+56>:  jmp    0x100000f68               ; <+152> at main.m
      0x100000f0d <+61>:  cmpl   $0xa, -0x14(%rbp)		   ; if (a == 10)
      0x100000f11 <+65>:  jne    0x100000f2d               ; <+93> at main.m:18:18,如果 a != 10,则跳转到 0x0x100000f2d(即<+93>)处执行指令
      0x100000f17 <+71>:  leaq   0x10a(%rip), %rax         ; @"a == 10"
      0x100000f1e <+78>:  movq   %rax, %rdi
      0x100000f21 <+81>:  movb   $0x0, %al
      0x100000f23 <+83>:  callq  0x100000f70               ; symbol stub for: NSLog
      0x100000f28 <+88>:  jmp    0x100000f63               ; <+147> at main.m
      0x100000f2d <+93>:  cmpl   $0xb, -0x14(%rbp) 		   ; if (a == 11)
      0x100000f31 <+97>:  jne    0x100000f4d               ; <+125> at main.m,如果 a != 11,则跳转到 0x100000f4d(即<+125>)处执行指令
      0x100000f37 <+103>: leaq   0x10a(%rip), %rax         ; @"a == 11"
      0x100000f3e <+110>: movq   %rax, %rdi
      0x100000f41 <+113>: movb   $0x0, %al
      0x100000f43 <+115>: callq  0x100000f70               ; symbol stub for: NSLog
      0x100000f48 <+120>: jmp    0x100000f5e               ; <+142> at main.m
      0x100000f4d <+125>: leaq   0x114(%rip), %rax         ; @"unknow"
      0x100000f54 <+132>: movq   %rax, %rdi
      0x100000f57 <+135>: movb   $0x0, %al
      0x100000f59 <+137>: callq  0x100000f70               ; symbol stub for: NSLog
      0x100000f5e <+142>: jmp    0x100000f63               ; <+147> at main.m
      0x100000f63 <+147>: jmp    0x100000f68               ; <+152> at main.m
      0x100000f68 <+152>: xorl   %eax, %eax
      0x100000f6a <+154>: addq   $0x20, %rsp
      0x100000f6e <+158>: popq   %rbp
      0x100000f6f <+159>: retq 
    
  • 汇编指令执行过程中,不同情况下,flags寄存器 对应的值如下(这里只是做一个展示,表明 cmp指令 执行前后,会改变 flags寄存器 中的值,flags寄存器 中每一个 bit 的具体含义,需要查 CPU 的结果状态表 )

    // 在执行比较前,打印 rflags 寄存器的值
    (lldb) po/x $rflags
    0x0000000000000206
    // 在执行比较后(条件不成立),打印 rflags 寄存器的值
    (lldb) po/x $rflags
     0x0000000000000202
    // 在执行比较后(条件成立),打印 rflags 寄存器的值
    (lldb) po/x $rflags
    0x0000000000000246
    

数据结构简介

  • 什么是数据结构
    数据结构是计算机存储以及组织数据的方式。也可以理解为,有一堆数据,他们之间有些特殊的关系。

  • 常见的数据结构(逻辑上)

    1. 线性表(数组、链表、栈、队列)
  • 逻辑结构
    数据结构从逻辑上可以分成下面几种结构:

    1. 集合结构:集合结构里面有很多元素,但是这些元素之间是没有关系的,类似于 Objective-C 里面的 NSSet、NSMutableSet。
      集合结构
    2. 线性结构:线性结构是有顺序的,比如 Objective-C 中的 NSArray、NSMutableArray。
      线性结构
    3. 树状结构:树状结构是一个或多个节点的有限集合。
      如下图所示:A 为根节点。D 是 I、J 的父节点。I、J 是 D 的子节点。I、J 为兄弟节点
      树状结构
    4. 图形结构:图形结构简称图,是一种相对复杂的数据结构,任意两个节点之间都可以关联。
       图形结构
  • 存储结构
    数据结构从存储上可以分成下面几种结构:

    1. 顺序存储结构:这组存储单元的内存地址是连续的。适用于:对数据遍历和查找频繁 && 对数据插入和删除较少 的场合。
      顺序存储结构
    2. 链式存储结构:这组存储单元的内存地址可以是连续的也可以是不连续的,它不要求逻辑上相邻的元素在物理地址上也相邻。适用于:对数据遍历和查找较少 && 对数据插入和删除频繁 的场合。
      链式存储结构
  • 线性表

    1. 线性表就是多个具有相同特性的数据元素(或节点)组成的,有限而且有序的集合(这里是从逻辑上描述线性表)。
    2. 当线性表的节点个数为 0 时,称之为空表
    3. 线性表第一个元素称为首节点,最后一个节点称为尾节点
    4. 比如某个线性表的元素:a0、a1、a2、…、a99。那么 a0、…、a98 都是 a99 的前驱,a98 是 a99 的直接前驱
    5. 比如某个线性表的元素:a0、a1、a2、…、a99。那么 a1、…、a99 都是 a0 的后继,a1 是 a0 的直接后继

    线性表的顺序存储结构:用一组地址连续的存储单元依次存储线性表的数据元素
    线性表的顺序存储结构
    线性表的链式存储结构:用一组任意的存储单元存储线性表中的数据元素,它的存储单元可以是连续的,也可以是不连续的。
    线性表的链式存储结构

用 C语言 写一个 Objective-C 的数组对象(顺序存储结构)

  • 栈(Stack)与堆(Heap)

    1. 栈空间用于存储函数调用过程中的方法调用、参数、局部变量,所需空间由系统自动分配,回收也由系统管理,无需人工干预
      堆空间用于存储动态分配的数据,分配和释放均由程序员控制,有可能产生内存泄漏
    2. 栈空间作为一个严格后进先出的数据结构,可用空间永远都是一块连续的内存区域
      堆空间在不断分配和释放的过程中,可用空间链表频繁更新,造成可用空间逐渐碎片化,每块可用内存空间都很小
    3. 栈空间的默认大小只有几 MB,生长方式是向上的,也就是向着内存地址减小的方向消耗内存空间
      堆空间的理论大小有几 GB,生长方式是向下的,也就是向着内存地址增大的方向消耗内存空间
    4. 栈空间有计算机底层的支持,压栈和出栈都有专门的汇编指令,效率较高
      堆空间通过函数动态开辟,涉及可用空间链表的扫描和调整以及相邻可用空间的合并等操作,效率相对较低

    通过 malloc 函数向操作系统申请堆区的内存空间
    通过 free 函数通知操作系统销毁之前申请的堆区的内存空间
    Objective-C 的 alloc 方法底层,调用的是 C语言的 malloc 函数

  • Objective-C 中的指针

    1. Objective-C 中任何类型的指针,都占用 8Byte 的内存空间
    2. int* 类型的指针,只能指向 int 类型的数据,指针的步长为 4Byte
      long* 类型的指针,只能指向 long 型的数据,指针的步长为 8Byte
      void* 类型的指针,为万能指针,能指向任意类型的数据
    3. Objective-C 中,给指针赋空值,使用 NULL,不是使用 nil
  • 分析 Objective-C 中 NSMutableArray 的属性与方法,规划线性表对象
    1.属性方面:容量(capacity)、长度(length)、指向存储线性表元素的堆内存的指针(value)
    2.方法方面:创建线性表、销毁线性表、清空线性表、获取线性表的属性(capacity、length)、对线性表的增、删、改、查、删除特定值,打印

    线性表对象内存图如下所示:
    线性表对象内存图

  • C语言 创建数组对象方法 listCreat() 分析
    写法一:listCreat() 函数,直接返回 表示数组对象的结构体
    1.这样写不好的地方在于:
    结构体的赋值为深拷贝,在 main 函数中调用 listCreat() 函数后,会再生成一份与 listCreat() 函数内部创建的结构体一模一样的结构体给 main 函数。如果结构体成员很多,会造成内存空间的浪费。
    2.优化思路:
    listCreat() 函数中返回指向结构体的指针,无论结构体的成员有多少个,都只返回 8Byte 的内存地址,从而节省了内存空间。

    // ---------------------------- main.m ----------------------------
    #import <Foundation/Foundation.h>
    #import "HCGLinearList.h"
    
    int main(int argc, const char * argv[]) {
      	@autoreleasepool {
      		LinearList list = listCreat(10);
      		// 输出结果:
      		// list size = 16
      		NSLog(@"list size = %ld", sizeof(list));
      	}
      	return 0;
    }
    
    
    // ---------------------------- HCGLinearList.h ----------------------------
    #ifndef LinearList_h
    #define LinearList_h
    // 定义节点数据的指针
    typedef int* LinearListNodeValue;
    
    // 线性表结构体
    typedef struct {
      	int capacity;               // 容量
      	int length;                 // 长度
      	LinearListNodeValue value;  // 节点数据的指针
    } LinearList;
    
    // 用于创建线性表的函数
    // param0.线性表容量
    // return.线性表结构体
    LinearList listCreat(int capacity);
    
    #endif /* LinearList_h */
    
    
    // ---------------------------- HCGLinearList.c ----------------------------
    #include "HCGLinearList.h"
    
    // 用于创建线性表的函数
    LinearList listCreat(int capacity) {
    	LinearList list;
    	list.capacity = capacity;
    	list.length = 0;
    	list.value = NULL;
    	return list;
    }
    

    写法二:listCreat() 函数,直接在内部创建一个结构体,然后返回指向该结构体的指针
    1.这样写不好的地方在于:如果直接在 listCreat() 函数内部,创建一个结构体,这个结构体相当于 listCreat() 函数的局部变量,此时结构体保存在 listCreat() 函数的栈空间里面。联系前面所学的汇编知识,listCreat() 函数的栈空间,在 istCreat() 函数执行完毕之后,就被释放了。
    2.优化思路:在 listCreat() 函数内部,通过 malloc 函数,在堆区申请内存,存储创建的结构体,并返回指向存储在堆区的结构体的指针

    // ---------------------------- main.m ----------------------------
    #import <Foundation/Foundation.h>
    #import "HCGLinearList.h"
    
    int main(int argc, const char * argv[]) {
    	@autoreleasepool {
    		LinearList* list0 = listCreat(10);
    		LinearList* list1 = listCreat(10);
    		LinearList* list2 = listCreat(10);
    		// 输出结果:(注意,因为函数调用平栈的关系,list1 和 list2 的内存地址完全一样)
         	// list0 = 0x7ffeefbff558, list1 = 0x10052e620, list2 = 0x10052e620
         	NSLog(@"list0 = %p, list1 = %p, list2 = %p", &list0, list1, list2);
    	}
    	return 0;
    }
     
    
    // ---------------------------- HCGLinearList.h ----------------------------
    #ifndef LinearList_h
    #define LinearList_h
    // 定义节点数据的指针
    typedef int* LinearListNodeValue;
    // 线性表结构体
    typedef struct {
     	int capacity;               // 容量
     	int length;                 // 长度
     	LinearListNodeValue value;  // 节点数据的指针
    } LinearList;
    
    // 用于创建线性表的函数
    // param0.线性表容量
    // return.指向 线性表结构体 的指针
    LinearList* listCreat(int capacity);
    
    #endif /* LinearList_h */
     
    
    // ---------------------------- HCGLinearList.c ----------------------------
    #include "HCGLinearList.h"
    
    // 用于创建线性表的函数
    LinearList* listCreat(int capacity) {
     	// 分配线性表结构体的内存空间(在本函数的栈区)
     	LinearList list;
     	list.capacity = capacity;
     	list.length = 0;
     	list.value = NULL;
     	LinearList* pList = &list;
     	return pList;;
    }
    

    写法三:在 listCreat() 函数内部,通过 malloc 函数,在堆区申请内存,存储创建的结构体,并返回指向存储在堆区的结构体的指针

    // ---------------------------- main.m ----------------------------
    #import <Foundation/Foundation.h>
    #import "HCGLinearList.h"
    
    int main(int argc, const char * argv[]) {
     	@autoreleasepool {
         	LinearList* list0 = listCreat(10);
         	LinearList* list1 = listCreat(10);
         	LinearList* list2 = listCreat(10);
         	// 输出结果:
         	// list0 = 0x7ffeefbff558, list1 = 0x10052e620, list2 = 0x100527070
         	NSLog(@"list0 = %p, list1 = %p, list2 = %p", &list0, list1, list2);
     	}
     	return 0;
    }
    // ---------------------------- HCGLinearList.h ----------------------------
    #ifndef LinearList_h
    #define LinearList_h
    
    typedef int* LinearListNodeValue;
    
    // 线性表结构体
    typedef struct {
     	int capacity;               // 容量
     	int length;                 // 长度
     	LinearListNodeValue value;  // 节点数据的指针
    } LinearList;
    
    // 用于创建线性表的函数
    // param0.线性表容量
    LinearList* listCreat(int capacity);
    
    #endif /* LinearList_h */
     
    
    // ---------------------------- HCGLinearList.c ----------------------------
    #include "HCGLinearList.h"
    // 使用 mallc函数 需要导入标准库
    #include <stdlib.h>
    
    // 用于创建线性表的函数
    LinearList* listCreat(int capacity) {
    	// 分配线性表结构体的内存空间(在堆区)
    	LinearList* list = malloc(sizeof(LinearList));
    	// malloc 函数如果遇到内存资源紧张,给不了这么多字节,可能会返回空
     	if (list) {
         	list->capacity = capacity;
         	list->length = 0;
         	// 分配真正存储线性表中元素的内存空间
         	list->value = malloc(capacity * sizeof(LinearListNodeValue));
         	// 对存储元素的内存空间进行初始化
         	for (int i = 0; i < capacity; i++) {
             	list->value[i] = 0x11111111;
         	}
     	}
     	return list;;
    }
    

HCGLinearList 代码(未封装)

  • HCGLinearList.h 文件如下

    #ifndef LinearList_h
    #define LinearList_h
    
    #include <stdio.h>
    
    #pragma mark - 定义线性表结构体
    // 重命名 int 类型
    typedef int LinearListNodeValue;
    
    // 线性表结构体
    typedef struct {
       int capacity;               // 容量
       int length;                 // 长度
       LinearListNodeValue* value; // 节点数据的指针
    } LinearList;
    
    #pragma mark - 创建 销毁 清空
    // 创建线性表
    // param0.线性表容量
    // return.线性表指针
    LinearList* listCreat(int capacity);
    
    // 销毁线性表
    // param0.线性表指针
    void listRelease(LinearList* list);
    
    // 清空线性表
    // param0.线性表指针
    void listClear(LinearList* list);
    
    #pragma mark - 属性获取
    // 获取线性表的长度
    // param0.线性表指针
    // return.线性表长度
    int listLength(LinearList* list);
    
    // 获取线性表容量
    // param0.线性表指针
    // return.线性表容量
    int listCapacity(LinearList* list);
    
    #pragma mark - 增
    // 往线性表中插入数据
    // param0.线性表指针
    // param1.要插入的位置的索引
    // param2.要插入的值
    void listInsert(LinearList* list, int index, LinearListNodeValue value);
    
    // 往线性表中添加数据(添加在表尾)
    void listAdd(LinearList* list, LinearListNodeValue value);
    
    #pragma mark - 删
    // 删除线性表中指定索引位置的元素
    // param0.线性表指针
    // param1.索引
    void listRemove(LinearList* list, int index);
    
    #pragma mark - 改
    // 修改线性表中指定位置的元素为指定的值
    // param0.线性表指针
    // param1.索引
    // param2.值
    void listSet(LinearList* list, int index, LinearListNodeValue value);
    
    #pragma mark - 查
    // 获取线性表指定索引处元素的值
    // param0.线性表指针
    // param1.索引
    // return.元素的值
    LinearListNodeValue listGet(LinearList* list, int index);
    
    #pragma mark - 特殊功能
    // 删除线性表中具有指定值的所有元素
    // param0.线性表指针
    // param1.要删除的值
    void listRemoveValue_1(LinearList* list, LinearListNodeValue value);
    
    // 删除线性表中具有指定值的所有元素
    // param0.线性表指针
    // param1.要删除的值
    void listRemoveValue_2(LinearList* list, LinearListNodeValue value);
    
    // 打印线性表
    // param0.线性表指针
    void listPrint(LinearList* list);
    
    #endif /* LinearList_h */
    
  • HCGLinearList.c 文件如下

    #include "HCGLinearList.h"
        
    // 使用 mallc函数 需要导入
    #include <stdlib.h>
      
    #pragma mark - 创建 销毁 清空
    // 创建线性表
    LinearList* listCreat(int capacity) {
        if (capacity < 0) {
            return NULL;
        }
        // 分配线性表结构体的内存空间(在堆区)
        // malloc函数如果遇到内存资源紧张,给不了这么多字节,可能会返回空
        LinearList* list = malloc(sizeof(LinearList));
        if (list) {
            list->capacity = capacity;
            list->length = 0;
            // 分配存储线性表元素的内存空间
            list->value = malloc(capacity * sizeof(LinearListNodeValue));
            if (!list->value) {
                return NULL;
            }
        }
        return list;;
    }
       
    // 销毁线性表
    void listRelease(LinearList* list) {
        if (NULL == list) {
            return;
        }
        if (list->value) {
            free(list->value);
        }
        free(list);
    }
    
    // 清空线性表
    void listClear(LinearList* list) {
        if (NULL == list) {
            return;
        }
        // 这里不需要对线性表中的元素都置0
        // 只要将线性表的长度置为0,下次使用线性表的时候,就会对之前的数据进行覆盖了
        list->length = 0;
    }
       
    #pragma mark - 属性获取
    // 获取线性表的长度
    int listLength(LinearList* list) {
        if (NULL == list) {
            return 0;
        }
        return list->length;
    }
    
    // 获取线性表容量
    int listCapacity(LinearList* list) {
        if (NULL == list) {
            return 0;
        }
        return list->capacity;
    }
       
    #pragma mark - 增
    // 往线性表中插入数据
    void listInsert(LinearList* list, int index, LinearListNodeValue value) {
        if (NULL == list) {
            return;
        }
        // 可以在表尾进行插入,因此这里的条件是 index > list->length,而不是 index >= list->length
        if (index < 0 || index > list->length) {
            return;
        }
        if (list->length == list->capacity) {
            return;
        }
         
        // 反向for循环挪动数据:从表尾数据开始挪动直到index标识的位置,每个数据依次向后挪动一个步长
        for (int i = list->length - 1; i >= index; i--) {
            list->value[i + 1] = list->value[i];
        }
        // 将新值value插入到index的位置
        list->value[index] = value;
        // 线性表的长度 + 1
        list->length++;
    }
       
    // 往线性表中添加数据(添加在表尾)
    void listAdd(LinearList* list, LinearListNodeValue value) {
        if (NULL == list) {
            return;
        }
        listInsert(list, list->length, value);
    }
        
    #pragma mark - 删
    // 删除线性表中指定索引位置的元素
    void listRemove(LinearList* list, int index) {
        if (NULL == list) {
            return;
        }
        if (index < 0 || index > list->length - 1) {
            return;
        }
        // 反向for循环挪动数据:从(index + 1)标识的位置开始直到表尾,每个数据依次向前挪动一个步长
        for (int i = index + 1; i < list->length; i++) {
            list->value[i - 1] = list->value[i];
        }
        /*
        // 等效写法
        for (int i = index; i < list->length - 1; i++) {
            list->value[i] = list->value[i + 1];
        }
        */
        // 线性表的长度 - 1
        list->length--;
    }
      
    #pragma mark - 改
    // 修改线性表中指定位置的元素为指定的值
    void listSet(LinearList* list, int index, LinearListNodeValue value) {
        if (NULL == list) {
            return;
        }
        if (index < 0 || index > list->length - 1) {
            return;
        }
        list->value[index] = value;
    }
    
    #pragma mark - 查
    // 获取线性表指定索引处元素的值
    LinearListNodeValue listGet(LinearList* list, int index) {
        if (NULL == list) {
            return 0;
        }
        if (index < 0 || index > list->length - 1) {
            return 0;
        }
        return list->value[index];
    }
      
    #pragma mark - 特殊功能
    // 删除线性表中具有指定值的所有元素 - 代码简单,但是效率低(时间复杂度高)
    void listRemoveValue_1(LinearList* list, LinearListNodeValue value) {
        if (NULL == list) {
            return;
        }
        // 遍历所有元素
        for (int i = 0; i <= list->length - 1; i++) {
            while (list->value[i] == value && i <= list->length - 1) {
                listRemove(list, i);
            }
        }
    }
        
    // 删除线性表中具有指定值的所有元素 - 效率较高
    void listRemoveValue_2(LinearList* list, LinearListNodeValue value) {
        if (NULL == list) {
            return;
        }
        // 遍历所有元素
        int removeCount = 0;
        for (int i = 0; i <= list->length - 1; i++) {
            if (list->value[i] == value) {
                removeCount++;
            } else {
                list->value[i - removeCount] = list->value[i];
            }
        }
        // 将长度减去删除的个数
        list->length -= removeCount;
    }
        
    // 打印线性表
    void listPrint(LinearList* list) {
        if (NULL == list) {
            return;
        }
        printf("list{\n");
        printf("\tlength = %d;\n", list->length);
        printf("\tcapacity = %d;\n", list->capacity);
        printf("\tvalue = [");
        for (int i = 0; i <= list->length - 1; i++) {
            printf("%d", list->value[i]);
            if (i <= list->length - 2) {
                printf(",");
            }
        }
        printf("];\n\t}\n\n");
    }
    
  • 在 main.m 中简单测试如下

    #import <Foundation/Foundation.h>
    #import "HCGLinearList.h"
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            // 创建 LinearList
            LinearList* list = listCreat(10);
            // 添加数据
            listAdd(list, 10);
            listAdd(list, 10);
            listAdd(list, 10);
            listAdd(list, 66);
            listAdd(list, 66);
            // 插入数据
            listInsert(list, 1, 20);
            listInsert(list, 2, 30);
            // 打印 1
            listPrint(list);
            
            // 修改数据
            listSet(list, 3, 40);
            // 删除数据
            listRemove(list, listLength(list) - 1);
            // 打印 2
            listPrint(list);
            
            // 移除所有为值 10 的数据
            listRemoveValue_2(list, 10);
            // 打印 3
            listPrint(list);
            
            // 销毁 LinearList
            listRelease(list);
            list = NULL;
        }
        return 0;
    }
    

    测试结果如下

    // 打印 1
    list{
    	length = 7;
    	capacity = 10;
    	value = [10,20,30,10,10,66,66];
    	}
    // 打印 2
    list{
    	length = 6;
    	capacity = 10;
    	value = [10,20,30,40,10,66];
    	}
    // 打印3
    list{
    	length = 4;
    	capacity = 10;
    	value = [20,30,40,66];
    	}
    

注意

  • 凡是指针类型定义出来的变量,里面保存的值,都会被当做地址值来处理。

    int a = 10;
    int b = 11;
    int* p0 = &a;
    int* p1 = &b;
     
    *p0 = 0;
    *p1 = 1;
    printf("a = %d, b = %d", a, b);
    // 输出结果
    // a = 0, b = 1
    
    // 变量 p2 里面存储的是 p0 指针往下移动 sizeof(int) * 1 个 Byte 处的地址
    int* p2 = p0 + 1;
     
    // 变量 p3 里面存储的是 p1 指针往上移动 sizeof(int) * 1 个 Byte 出的地址
    int* p3 = p1 - 1;
    
  • void 有空的意思,也有无类型的意思,因此 void* 的指针不能 + 或 -

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值