07.FreeRTOS列表与列表项

文章目录

  • 07. FreeRTOS列表与列表项
    • 1. 列表和列表项的简介
    • 2. 列表相关API函数
    • 3. 代码验证

07. FreeRTOS列表与列表项

1. 列表和列表项的简介

在这里插入图片描述

列表的定义:

typedef struct xLIST
{listFIRST_LIST_INTEGRITY_CHECK_VALUE      /* 校验值 */volatile UBaseType_t uxNumberOfItems;     /* 列表中列表项的数量 */ListItem_t * configLIST_VOLATILE pxIndex; /* 用于遍历列表 */MiniListItem_t xListEnd;                  /* 最后一个列表项 */listSECOND_LIST_INTEGRITY_CHECK_VALUE     /* 校验值 */
} List_t;

在这里插入图片描述

列表项的定义:

struct xLIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE             /* 用于检测列表项的数据完整性 */configLIST_VOLATILE TickType_t xItemValue;            /* 列表项的值 */struct xLIST_ITEM * configLIST_VOLATILE pxNext;       /* 下一个列表项 */struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;   /* 上一个列表项 */void * pvOwner;                                       /* 列表项的拥有者 */struct xLIST * configLIST_VOLATILE pxContainer;       /* 列表项所在列表 */listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE            /* 用于检测列表项的数据完整性 */
};
typedef struct xLIST_ITEM ListItem_t;                     /* 重定义成 ListItem_t */

在这里插入图片描述

迷你列表项:

struct xMINI_LIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE             /* 用于检测列表项的数据完整性 */configLIST_VOLATILE TickType_t xItemValue;             /* 列表项的值 */struct xLIST_ITEM * configLIST_VOLATILE pxNext;        /* 下一个列表项 */struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;    /* 上一个列表项 */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;             /* 重定义成 MiniListItem_t */

在这里插入图片描述

列表和列表项的关系:

初始状态:

2. 列表相关API函数

函数描述
vListInitialise()初始化列表
vListInitialiseItem()初始化列表项
vListInsertEnd()列表末尾插入列表项
vListInsert()列表插入列表项
uxListRemove()列表移除列表项
  • 函数vListInitialise()

    此函数用于初始化列表,在定义列表之后,需要先对其进行初始化,只有初始化后的列表,才能够正常地被使用。列表初始化的过程,其实就是初始化列表中的成员变量。

    在这里插入图片描述

    在这里插入图片描述

  • 函数vListInitialiseItem()

    此函数用于初始化列表项,在定义列表项之后,也需要先对其进行初始化,只有初始化完的列表项,才能够被正常地使用。列表项初始化的过程,也是初始化列表项中的成员变量。

    在这里插入图片描述
    在这里插入图片描述

  • 函数vListInsert()

    此函数用于将待插入列表的列表项按照列表项值升序排序的顺序,有序地插入到列表中。

    在这里插入图片描述

    插入示意图:

    初始状态列表:
    在这里插入图片描述

    插入40后的列表:
    在这里插入图片描述

    插入60后的列表:
    在这里插入图片描述

    插入50后的列表:

    在这里插入图片描述

    代码具体体现:

    void vListInsert( List_t * const pxList,ListItem_t * const pxNewListItem )
    {ListItem_t * pxIterator;//* 获取列表项的数值依据数值升序排列 */const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;/* Only effective when configASSERT() is also defined, these tests may catch* the list data structures being overwritten in memory.  They will not catch* data errors caused by incorrect configuration or use of FreeRTOS. *///* 检查参数是否正确 */listTEST_LIST_INTEGRITY( pxList );listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );/* Insert the new list item into the list, sorted in xItemValue order.** If the list already contains a list item with the same item value then the* new list item should be placed after it.  This ensures that TCBs which are* stored in ready lists (all of which have the same xItemValue value) get a* share of the CPU.  However, if the xItemValue is the same as the back marker* the iteration loop below will not end.  Therefore the value is checked* first, and the algorithm slightly modified if necessary. *///* 如果待插入列表项的值为最大值 */ if( xValueOfInsertion == portMAX_DELAY ){//* 插入的位置为列表 xListEnd 前面 */ pxIterator = pxList->xListEnd.pxPrevious;}else{/* *** NOTE ************************************************************  If you find your application is crashing here then likely causes are*  listed below.  In addition see https://www.FreeRTOS.org/FAQHelp.html for*  more tips, and ensure configASSERT() is defined!*  https://www.FreeRTOS.org/a00110.html#configASSERT**   1) Stack overflow -*      see https://www.FreeRTOS.org/Stacks-and-stack-overflow-checking.html*   2) Incorrect interrupt priority assignment, especially on Cortex-M*      parts where numerically high priority values denote low actual*      interrupt priorities, which can seem counter intuitive.  See*      https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html and the definition*      of configMAX_SYSCALL_INTERRUPT_PRIORITY on*      https://www.FreeRTOS.org/a00110.html*   3) Calling an API function from within a critical section or when*      the scheduler is suspended, or calling an API function that does*      not end in "FromISR" from an interrupt.*   4) Using a queue or semaphore before it has been initialised or*      before the scheduler has been started (are interrupts firing*      before vTaskStartScheduler() has been called?).*   5) If the FreeRTOS port supports interrupt nesting then ensure that*      the priority of the tick interrupt is at or below*      configMAX_SYSCALL_INTERRUPT_PRIORITY.**********************************************************************///*遍历列表中的列表项,找到插入的位置for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 !e9087 The mini list structure is used as the list end to save RAM.  This is checked and valid. *//*lint !e440 The iterator moves to a different value, not xValueOfInsertion. */{/* There is nothing to do here, just iterating to the wanted* insertion position. */}}//* 将待插入的列表项插入指定位置 */pxNewListItem->pxNext = pxIterator->pxNext;pxNewListItem->pxNext->pxPrevious = pxNewListItem;pxNewListItem->pxPrevious = pxIterator;pxIterator->pxNext = pxNewListItem;/* Remember which list the item is in.  This allows fast removal of the* item later. *///* 更新待插入列表项所在列表 */ pxNewListItem->pxContainer = pxList;//* 更新列表中列表项的数量 */ ( pxList->uxNumberOfItems )++;
    }
    
  • 函数vListInsertEnd()

    此函数用于将待插入列表的列表项插入到列表 pxIndex 指针指向列表项的前面,是一种无序的插入方法。

    在这里插入图片描述

    在这里插入图片描述

    插入示意图:

    插入前:
    在这里插入图片描述

    插入30后的列表项:

    在这里插入图片描述

    插入前:
    在这里插入图片描述

    插入30后的列表项:

    在这里插入图片描述

  • 函数uxListRemove()

    此函数用于将列表项从列表项所在列表中移除.

    在这里插入图片描述
    在这里插入图片描述

    移除列表项2示意图:

    在这里插入图片描述

3. 代码验证

本实验主要实现FreeRTOS的列表项的插入与删除,定义三个任务函数,开始任务用于创建其他任务;任务一用于LED灯闪烁,提示系统正常工作;任务二用于进行列表项的插入与删除。

  • 函数入口:

    用于创建开始任务并开启任务调度

    /*函数入口*/
    void freertos_Dynamic_Create(void)
    {lcd_show_string(10, 10, 220, 32, 32, "STM32", RED);lcd_show_string(10, 47, 220, 24, 24, "Task Create&Delete", LIGHTGREEN);lcd_show_string(15, 80, 110, 16, 16, "Task1: 000", GREEN);lcd_show_string(135, 80, 110, 16, 16, "Task2: 000", GREEN);xTaskCreate((TaskFunction_t        )   start_task,           //指向任务函数的指针(char *                )   "start_task",         //任务名称(configSTACK_DEPTH_TYPE)   START_TASK_STACK_SIZE,//任务堆栈大小,字节为单位(void *                )   NULL,                 //传递给任务函数的参数(UBaseType_t           )   START_TASK_PRIO,      //任务优先级(TaskHandle_t *        )   &start_task_handler    //任务句柄:任务控制块);vTaskStartScheduler();  //开启任务调度
    }
    
  • 开始任务:

    用于创建任务一和任务二

    void start_task(void* pvParamter)
    {taskENTER_CRITICAL();   // 进入临界区 xTaskCreate((TaskFunction_t        )   task1,                 //指向任务函数的指针(char *                )   "task1",               //任务名称(configSTACK_DEPTH_TYPE)   TASK1_TASK_STACK_SIZE, //任务堆栈大小,字节为单位(void *                )   NULL,                  //传递给任务函数的参数(UBaseType_t           )   TASK1_TASK_PRIO,       //任务优先级(TaskHandle_t *        )   &task1_task_handler    //任务句柄:任务控制块);xTaskCreate((TaskFunction_t        )   task2,                 //指向任务函数的指针(char *                )   "task2",               //任务名称(configSTACK_DEPTH_TYPE)   TASK2_TASK_STACK_SIZE, //任务堆栈大小,字节为单位(void *                )   NULL,                  //传递给任务函数的参数(UBaseType_t           )   TASK2_TASK_PRIO,       //任务优先级(TaskHandle_t *        )   &task2_task_handler    //任务句柄:任务控制块);	vTaskDelete(NULL);taskEXIT_CRITICAL();    // 退出临界区 
    }
    
  • 任务一:

    实现LED0每500ms翻转一次

    void task1(void* pvParamter)
    {uint32_t task1_num = 0;while(1){lcd_show_xnum(71, 80, ++task1_num, 3, 16, 0x80, GREEN);LED0_TOGGLE();vTaskDelay(500);}
    }
    
  • 任务二:

    进行列表和列表项的操作

    1. 初始化列表

      vListInitialise(&TestList);	     //初始化列表
      vListInitialiseItem(&ListItem1); //初始化列表项1
      vListInitialiseItem(&ListItem2); //初始化列表项2
      vListInitialiseItem(&ListItem3); //初始化列表项3ListItem1.xItemValue = 40;
      ListItem2.xItemValue = 60;
      ListItem3.xItemValue = 50;
      
      1. 列表初始化
      vListInitialise(&TestList);
      
      • 功能:初始化一个列表 TestList
      • 作用TestList 是一个 FreeRTOS 列表的头部结构体,列表在初始化后将会处于空状态,准备好用于插入或管理列表项。
      1. 列表项初始化
      vListInitialiseItem(&ListItem1);
      vListInitialiseItem(&ListItem2);
      vListInitialiseItem(&ListItem3);
      
      • 功能:初始化三个列表项 ListItem1ListItem2ListItem3
      • 作用:每个列表项结构体在初始化后将会被设置为一个空的列表项,即这些列表项还未插入到任何列表中,且它们的前后指针将指向自身。
      1. 设置列表项值
      ListItem1.xItemValue = 40;
      ListItem2.xItemValue = 60;
      ListItem3.xItemValue = 50;
      
      • 功能:为每个列表项设置一个值,xItemValue
      • 作用xItemValue 是 FreeRTOS 列表项中的一个成员,用于存储与列表项相关的值。这个值可以用来对列表项进行排序或者优先级排序。通常,在 FreeRTOS 中,列表项的值越小,优先级越高。
    2. 打印列表和其他列表项的地址

      /* 第二步:打印列表和其他列表项的地址 */
      printf("/**************第二步:打印列表和列表项的地址**************/\r\n");
      printf("项目\t\t\t地址\r\n");
      printf("TestList\t\t0x%p\t\r\n", &TestList);
      printf("TestList->pxIndex\t0x%p\t\r\n", TestList.pxIndex);
      printf("TestList->xListEnd\t0x%p\t\r\n", (&TestList.xListEnd));
      printf("ListItem1\t\t0x%p\t\r\n", &ListItem1);
      printf("ListItem2\t\t0x%p\t\r\n", &ListItem2);
      printf("ListItem3\t\t0x%p\t\r\n", &ListItem3);
      printf("/**************************结束***************************/\r\n\r\n");
      
      1. 打印列表和列表项地址

        printf("TestList\t\t0x%p\t\r\n", &TestList);
        
        • 功能:打印 TestList 列表头部结构体的地址。
        • 解释&TestListTestList 的内存地址,这个地址指向整个列表结构体。
      2. 打印 TestListpxIndex 成员的地址

        printf("TestList->pxIndex\t0x%p\t\r\n", TestList.pxIndex);
        
        • 功能:打印 TestListpxIndex 成员的地址。
        • 解释pxIndexTestList 列表结构体中的一个成员,通常指向当前列表项的索引。这里打印的是该成员的值,实际上是 TestListpxIndex 成员所指向的地址。
      3. 打印 TestListxListEnd 成员的地址

        printf("TestList->xListEnd\t0x%p\t\r\n", (&TestList.xListEnd));
        
        • 功能:打印 TestListxListEnd 成员的地址。
        • 解释xListEndTestList 列表结构体中的一个成员,表示列表的结束位置。这里打印的是该成员的地址。
      4. 打印列表项地址

        printf("ListItem1\t\t0x%p\t\r\n", &ListItem1);
        printf("ListItem2\t\t0x%p\t\r\n", &ListItem2);
        printf("ListItem3\t\t0x%p\t\r\n", &ListItem3);
        
        • 功能:打印三个列表项的内存地址。
        • 解释&ListItem1&ListItem2&ListItem3 分别是这三个列表项的内存地址,用于调试和验证这些结构体的存储位置。
      5. 实验结果:

        在这里插入图片描述

        在这里插入图片描述

    3. 列表项1插入列表

      /* 第三步:列表项1插入列表 */
      printf("/*****************第三步:列表项1插入列表******************/\r\n");
      vListInsert((List_t*    )&TestList,         /* 列表 */(ListItem_t*)&ListItem1);       /* 列表项 */
      printf("项目\t\t\t\t地址\r\n");
      printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
      printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
      printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
      printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
      printf("/**************************结束***************************/\r\n\r\n");
      

      插入操作

      vListInsert((List_t*)&TestList, (ListItem_t*)&ListItem1);
      
      • 功能:将 ListItem1 插入到 TestList 列表中。
      • 解释vListInsert 是 FreeRTOS 提供的函数,用于将一个列表项插入到指定的列表中。此操作会将 ListItem1 插入到 TestList 中的正确位置,通常是按照 xItemValue 的顺序。

      打印列表项的指针状态

      打印输出语句的目的是验证插入操作后的列表状态。

      printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
      
      • 功能:打印 TestList 列表的 xListEnd 成员的 pxNext 指针的地址。
      • 解释pxNext 指向列表末尾的下一个列表项。在插入操作后,xListEndpxNext 应该指向插入的列表项(ListItem1)。
      printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
      
      • 功能:打印 ListItem1pxNext 指针的地址。
      • 解释pxNextListItem1next 指针。在插入操作后,ListItem1pxNext 应该指向 xListEnd(即列表的末尾)。
      printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
      
      • 功能:打印 TestList 列表的 xListEnd 成员的 pxPrevious 指针的地址。
      • 解释pxPrevious 指向列表末尾的前一个列表项。在插入操作后,xListEndpxPrevious 应该指向 ListItem1
      printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
      
      • 功能:打印 ListItem1pxPrevious 指针的地址。
      • 解释pxPreviousListItem1previous 指针。在插入操作后,ListItem1pxPrevious 应该指向 xListEnd(即列表的末尾)。

      综合分析

      通过这段代码,你可以验证 ListItem1 是否成功插入到 TestList 列表中。插入操作完成后,应该能看到以下情况:

      • TestList->xListEnd->pxNext 应该指向 ListItem1
      • ListItem1->pxNext 应该指向 xListEnd
      • TestList->xListEnd->pxPrevious 应该指向 ListItem1
      • ListItem1->pxPrevious 应该指向 xListEnd

      实验结果

      在这里插入图片描述
      在这里插入图片描述

    4. 列表项2插入列表

      printf("/*****************第四步:列表项2插入列表******************/\r\n");
      vListInsert((List_t*)&TestList, (ListItem_t*)&ListItem2); /* 插入 ListItem2 */
      printf("项目\t\t\t\t地址\r\n");
      printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
      printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
      printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
      printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
      printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
      printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
      printf("/**************************结束***************************/\r\n\r\n");
      

      这段代码的目的是将 ListItem2 插入到 TestList 列表中,并打印出插入操作后的列表状态,以便检查和验证列表结构是否正确更新。具体来说,这里主要关注插入后列表项的连接情况。下面是详细的分析:

      代码功能

      /* 第四步:列表项2插入列表 */
      printf("/*****************第四步:列表项2插入列表******************/\r\n");
      vListInsert((List_t*)&TestList, (ListItem_t*)&ListItem2); /* 插入 ListItem2 到 TestList 列表 */
      printf("项目\t\t\t\t地址\r\n");
      printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
      printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
      printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
      printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
      printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
      printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
      printf("/**************************结束***************************/\r\n\r\n");
      

      插入操作

      vListInsert((List_t*)&TestList, (ListItem_t*)&ListItem2);
      
      • 功能:将 ListItem2 插入到 TestList 列表中。
      • 解释:此操作将 ListItem2 插入到 TestList 列表中的正确位置,通常是按照 xItemValue 的顺序。在插入之前,ListItem1 已经在列表中,ListItem2 会根据它的 xItemValue 值决定它的插入位置。

      打印列表项的指针状态

      打印输出语句的目的是检查 ListItem2 插入后列表项之间的连接状态:

      printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
      
      • 功能:打印 TestListxListEnd 成员的 pxNext 指针的地址。
      • 解释:插入 ListItem2 后,xListEndpxNext 应该指向 ListItem2,因为 ListItem2 将成为列表的新的末尾项。
      printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
      
      • 功能:打印 ListItem1pxNext 指针的地址。
      • 解释:插入 ListItem2 后,ListItem1pxNext 应该指向 ListItem2,因为 ListItem2 将跟在 ListItem1 之后。
      printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
      
      • 功能:打印 ListItem2pxNext 指针的地址。
      • 解释:插入 ListItem2 后,ListItem2pxNext 应该指向 xListEnd,即列表的末尾。
      printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
      
      • 功能:打印 TestListxListEnd 成员的 pxPrevious 指针的地址。
      • 解释:插入 ListItem2 后,xListEndpxPrevious 应该指向 ListItem2,因为 ListItem2 现在是列表的最后一个有效项。
      printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
      
      • 功能:打印 ListItem1pxPrevious 指针的地址。
      • 解释:插入 ListItem2 后,ListItem1pxPrevious 应该指向 xListEnd,因为 ListItem1 之前的项是 ListItem2
      printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
      
      • 功能:打印 ListItem2pxPrevious 指针的地址。
      • 解释:插入 ListItem2 后,ListItem2pxPrevious 应该指向 ListItem1,因为 ListItem1ListItem2 的前一个项。

      综合分析

      在插入 ListItem2 后,

      • TestList->xListEnd->pxNext 应该指向 ListItem1
      • ListItem1->pxNext 应该指向 ListItem2
      • ListItem2->pxNext 应该指向 xListEnd
      • TestList->xListEnd->pxPrevious 应该指向 ListItem2
      • ListItem1->pxPrevious 应该指向 xListEnd
      • ListItem2->pxPrevious 应该指向 ListItem1

      实验结果

      在这里插入图片描述
      在这里插入图片描述

    5. 列表项3插入列表

      在插入 ListItem3TestList 列表中的过程中,我们需要分析其如何影响列表的结构。以下是详细的分析,包括插入 ListItem3 后预期的指针状态。

      列表状态分析

      printf("/*****************第五步:列表项3插入列表******************/\r\n");
      vListInsert((List_t*)&TestList, (ListItem_t*)&ListItem3); /* 插入 ListItem3 */
      printf("项目\t\t\t\t地址\r\n");
      printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
      printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
      printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
      printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
      printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
      printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
      printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
      printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
      printf("/**************************结束***************************/\r\n\r\n");
      

      结果分析:

      1. TestList->xListEnd->pxNext

        • 功能:打印 TestListxListEnd 成员的 pxNext 指针的地址。
        • 预期结果:指向 ListItem1。在插入 ListItem3 后,xListEndpxNext 应指向列表的第一个有效项 ListItem1
      2. ListItem1->pxNext

        • 功能:打印 ListItem1pxNext 指针的地址。
        • 预期结果:指向 ListItem3ListItem1pxNext 应指向 ListItem3,因为 ListItem3 被插入在 ListItem1ListItem2 之间。
      3. ListItem2->pxNext

        • 功能:打印 ListItem2pxNext 指针的地址。
        • 预期结果:指向 TestList->xListEndListItem2 是列表的最后一个有效项,因此它的 pxNext 应指向 xListEnd
      4. ListItem3->pxNext

        • 功能:打印 ListItem3pxNext 指针的地址。
        • 预期结果:指向 ListItem2ListItem3 被插入在 ListItem1ListItem2 之间,因此它的 pxNext 应指向 ListItem2
      5. TestList->xListEnd->pxPrevious

        • 功能:打印 TestListxListEnd 成员的 pxPrevious 指针的地址。
        • 预期结果:指向 ListItem2xListEndpxPrevious 应指向列表的最后一个有效项,即 ListItem2
      6. ListItem1->pxPrevious

        • 功能:打印 ListItem1pxPrevious 指针的地址。
        • 预期结果:指向 xListEnd。在插入 ListItem3 后,ListItem1pxPrevious 应指向 xListEnd,因为 ListItem1 是第一个有效项。
      7. ListItem2->pxPrevious

        • 功能:打印 ListItem2pxPrevious 指针的地址。
        • 预期结果:指向 ListItem3ListItem2pxPrevious 应指向 ListItem3,因为 ListItem3ListItem2 的前一个项。
      8. ListItem3->pxPrevious

        • 功能:打印 ListItem3pxPrevious 指针的地址。
        • 预期结果:指向 ListItem1ListItem3 被插入在 ListItem1ListItem2 之间,因此它的 pxPrevious 应指向 ListItem1

      总结

      在插入 ListItem3 后,

      • TestList->xListEnd->pxNext 应指向 ListItem1
      • ListItem1->pxNext 应指向 ListItem3
      • ListItem3->pxNext 应指向 ListItem2
      • ListItem2->pxNext 应指向 xListEnd
      • TestList->xListEnd->pxPrevious 应指向 ListItem2
      • ListItem1->pxPrevious 应指向 xListEnd
      • ListItem3->pxPrevious 应指向 ListItem1
      • ListItem2->pxPrevious 应指向 ListItem3.

      实验结果

      在这里插入图片描述
      在这里插入图片描述

    6. 移除列表项2

      printf("/*******************第六步:移除列表项2********************/\r\n");
      uxListRemove((ListItem_t*   )&ListItem2);   /* 移除列表项 */
      printf("项目\t\t\t\t地址\r\n");
      printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
      printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
      printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
      printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
      printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
      printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
      printf("/**************************结束***************************/\r\n\r\n");
      

      在调用 uxListRemove 后,ListItem2 将被从列表中断开,列表的其他项应保持连接。

      移除 ListItem2 后的列表状态

      在移除 ListItem2 后,ListItem3ListItem1 之间的连接将直接建立,ListItem2 将不再存在于列表中。具体指针更新如下:

      1. TestList->xListEnd->pxNext

        • 功能:打印 TestListxListEnd 成员的 pxNext 指针的地址。
        • 预期结果:指向 ListItem1xListEndpxNext 应该仍指向列表的第一个有效项 ListItem1
      2. ListItem1->pxNext

        • 功能:打印 ListItem1pxNext 指针的地址。
        • 预期结果:指向 ListItem3
      3. ListItem3->pxNext

        • 功能:打印 ListItem3pxNext 指针的地址。
        • 预期结果:指向 TestList->xListEnd。在 ListItem2 被移除后,ListItem3pxNext 应指向 xListEnd
      4. TestList->xListEnd->pxPrevious

        • 功能:打印 TestListxListEnd 成员的 pxPrevious 指针的地址。
        • 预期结果:指向 ListItem3xListEndpxPrevious 应指向列表的最后一个有效项,即 ListItem3,因为 ListItem2 已被移除。
      5. ListItem1->pxPrevious

        • 功能:打印 ListItem1pxPrevious 指针的地址。
        • 预期结果:指向 TestList->xListEndListItem1pxPrevious 应指向 xListEnd,因为 ListItem1 是列表中的第一个有效项。
      6. ListItem3->pxPrevious

        • 功能:打印 ListItem3pxPrevious 指针的地址。
        • 预期结果:指向 ListItem1ListItem3pxPrevious 应指向 ListItem1,因为ListItem3ListItem1 的下一个有效项。

      总结

      在移除 ListItem2 后,

      • TestList->xListEnd->pxNext 应指向 ListItem1
      • ListItem1->pxNext 应指向 ListItem3
      • ListItem3->pxNext 应指向 xListEnd
      • TestList->xListEnd->pxPrevious 应指向 ListItem3
      • ListItem1->pxPrevious 应指向 xListEnd
      • ListItem3->pxPrevious 应指向 ListItem1

      实验结果

在这里插入图片描述
在这里插入图片描述

  1. 列表末尾添加列表项2

    打印输出分析

    printf("/****************第七步:列表末尾添加列表项2****************/\r\n");
    vListInsertEnd((List_t*)&TestList, (ListItem_t*)&ListItem2); /* 添加 ListItem2 到末尾 */
    printf("项目\t\t\t\t地址\r\n");
    printf("TestList->pxIndex\t\t0x%p\r\n", TestList.pxIndex);
    printf("TestList->xListEnd->pxNext\t0x%p\r\n", (TestList.xListEnd.pxNext));
    printf("ListItem1->pxNext\t\t0x%p\r\n", (ListItem1.pxNext));
    printf("ListItem2->pxNext\t\t0x%p\r\n", (ListItem2.pxNext));
    printf("ListItem3->pxNext\t\t0x%p\r\n", (ListItem3.pxNext));
    printf("TestList->xListEnd->pxPrevious\t0x%p\r\n", (TestList.xListEnd.pxPrevious));
    printf("ListItem1->pxPrevious\t\t0x%p\r\n", (ListItem1.pxPrevious));
    printf("ListItem2->pxPrevious\t\t0x%p\r\n", (ListItem2.pxPrevious));
    printf("ListItem3->pxPrevious\t\t0x%p\r\n", (ListItem3.pxPrevious));
    printf("/************************实验结束***************************/\r\n");
    

    解释每个打印语句的含义:

    1. TestList->pxIndex

      • 功能:打印 TestListpxIndex 成员的地址。
      • 预期结果:应指向 ListItem1pxIndex 通常指向列表中的第一个有效项。
    2. TestList->xListEnd->pxNext

      • 功能:打印 TestListxListEnd 成员的 pxNext 指针的地址。
      • 预期结果:应指向 ListItem1xListEndpxNext 应指向列表的第一个有效项。
    3. ListItem1->pxNext

      • 功能:打印 ListItem1pxNext 指针的地址。
      • 预期结果:应指向 ListItem3ListItem1pxNext 应指向 ListItem3
    4. ListItem2->pxNext

      • 功能:打印 ListItem2pxNext 指针的地址。
      • 预期结果:应指向 TestList->xListEnd。因为 ListItem2 被重新添加到列表的末尾,它的 pxNext 应指向 xListEnd
    5. ListItem3->pxNext

      • 功能:打印 ListItem3pxNext 指针的地址。
      • 预期结果:应指向 ListItem2ListItem3pxNext 应指向 ListItem2,因为 ListItem2 被添加到 ListItem3 的后面。
    6. TestList->xListEnd->pxPrevious

      • 功能:打印 TestListxListEnd 成员的 pxPrevious 指针的地址。
      • 预期结果:应指向 ListItem2xListEndpxPrevious 应指向列表的最后一个有效项,即 ListItem2
    7. ListItem1->pxPrevious

      • 功能:打印 ListItem1pxPrevious 指针的地址。
      • 预期结果:应指向 TestList->xListEnd。因为 ListItem1 是列表中的第一个有效项,它的 pxPrevious 应指向 xListEnd
    8. ListItem2->pxPrevious

      • 功能:打印 ListItem2pxPrevious 指针的地址。
      • 预期结果:应指向 ListItem3。因为 ListItem2 被添加到列表的末尾,它的 pxPrevious 应指向 ListItem3
    9. ListItem3->pxPrevious

      • 功能:打印 ListItem3pxPrevious 指针的地址。
      • 预期结果:应指向 ListItem1。因为 ListItem3 现在是 ListItem2 的前一个项,它的 pxPrevious 应指向 ListItem1

      总结

      在将 ListItem2 添加到列表末尾后,

      • TestList->pxIndex 应指向 ListItem1
      • TestList->xListEnd->pxNext 应指向 ListItem1
      • ListItem1->pxNext 应指向 ListItem3
      • ListItem2->pxNext 应指向 xListEnd
      • ListItem3->pxNext 应指向 ListItem2
      • TestList->xListEnd->pxPrevious 应指向 ListItem2
      • ListItem1->pxPrevious 应指向 xListEnd
      • ListItem2->pxPrevious 应指向 ListItem3
      • ListItem3->pxPrevious 应指向 ListItem1

    实验结果:
    在这里插入图片描述
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/395499.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在百度飞浆中搭建pytorch环境

文章目录 1 先检查创建的环境2 创建虚拟环境3 最终结果 1 先检查创建的环境 选择GPU版本 检查python版本 2 创建虚拟环境 虚拟环境的创建 python3 -m venv env_name # (python3 -m 路径 环境名)激活虚拟环境 source env_name/bin/activate这里注意&#xff0c;同名文件…

sqli靶场复现(1-8关)

目录 1.sqli-labs第二关 1.判断是否存在sql注入 1.1你输入数字值的ID作为参数&#xff0c;我们输入?id1 1.2在数据库可以查看到users下的对应内容 2.联合注入 2.1首先知道表格有几列&#xff0c;如果报错就是超过列数&#xff0c;如果显示正常就是没有超出列数。 2.2得…

PHP全方位多功能投票小程序系统源码

&#x1f31f;【全民参与&#xff0c;决策更精彩】全方位多功能投票小程序大揭秘&#xff01;&#x1f389; &#x1f680; 开篇引入&#xff1a;投票新风尚&#xff0c;尽在指尖 Hey小伙伴们&#xff0c;你是否厌倦了传统的投票方式&#xff0c;觉得它们既繁琐又不够灵活&am…

IO进程----标准IO

目录 IO进程 标准IO 1. 概念&#xff1a; 2. 特点&#xff1a; 3. 缓存区 3.1. 行缓存&#xff1a;和终端操作相关 刷新缓存的条件&#xff1a; 1) 程序正常退出 2) \n刷新 3) 缓存区满刷新 4) 强制刷新 fflush 3.2. 全缓存&#xff1a;和文件操作相关 3.…

sqli-labs闯关1-4

第一关&#xff1a; 这里的输入了 &#xff1f;id1 意思是以GET方式传入id1的参数 就等于SELECT * FROM users WHERE id1 LIMIT 0,1 注意&#xff1a;-- 与-- 空格的区别 在url中输入了--以后&#xff0c;后端数据会变成--空格。在 url中输入 -- 空格 变成 -- 在mysql中&…

使用Go语言实现基于泛型的Jaccard相似度算法

基本原理 跳表&#xff1a; jaccard相似度&#xff1a; jaccard相似度的代码实现&#xff1a; 时间复杂度分析&#xff1a; 快速jaccard算法&#xff1a; 代码实现&#xff0c;这个要求两个集合都是有序的&#xff1a; Jaccard相似度算法的基本实现 算法&#xf…

LeetCode Hot100 排序链表

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4]示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5]示例 3&#xff1a; 输…

工程技术人员职称专业一览表,赶紧收藏!有助评职称、落户

现在很多地区为了引进人才&#xff0c;都会对各类获得中级或高级职称的人才提供一系列优惠政策&#xff0c;比如人才补贴、职称入户等等。 下面小编就来为大家介绍一下中级职称专业一览表&#xff0c;告诉你能以考代评的几个考试&#xff0c;需要评职称、落户的快看过来&#…

【秋招突围】2024届秋招-京东笔试题-第二套

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍭 本次给大家…

PXE:Kickstart自动化安装Linux系统

PXE&#xff1a;工作在 Client/Server模式&#xff0c;允许客户机通过网络从远程服务器下载引导镜像&#xff0c;并加载安装文件或者整个操作系统。 运行 PXE协议需要设置&#xff1a;DHCP服务器和TFTP服务器。DHCP服务器用来给 PXE client&#xff08;将要安装系统的主机&…

【C++二分查找 决策包容性】1300. 转变数组后最接近目标值的数组和

本文涉及的基础知识点 C二分查找 决策包容性 LeetCode1300. 转变数组后最接近目标值的数组和 给你一个整数数组 arr 和一个目标值 target &#xff0c;请你返回一个整数 value &#xff0c;使得将数组中所有大于 value 的值变成 value 后&#xff0c;数组的和最接近 target …

element plus el-select修改后缀图标

使用 element plus 提供的api 默认为&#xff1a; 修改后为&#xff1a; 方法&#xff1a; <el-select v-model"value" placeholder"Select" size"large" style"width: 120px;":teleported"false" :suffix-icon"…

香港电讯为知名地产商构建安全稳定可靠的企业组网

客户背景 客户公司的总部位于香港&#xff0c;专注于房地产、酒店、基础设施及服务、商场等业务。经过多年沉淀&#xff0c;其内地业务不断壮大&#xff0c;拓展至各个地区并覆盖多个城市&#xff0c;原有的网络架构已无法满足客户的业务扩张需求。 客户需求 解决网络速度和稳…

python-约瑟夫环(赛氪OJ)

[题目描述] n 个人&#xff08; 0,1,2,3,4...n−1 &#xff09;&#xff0c;围成一圈&#xff0c;从编号为 k 的人开始报数&#xff0c;报数报到 m 的人出队。 下次从出队的人之后开始重新报数&#xff0c;循环往复&#xff0c;当队伍中只剩最后一个人的时候&#xff0c;那个人…

C++从入门到起飞之——深浅拷贝string类补充 全方位剖析!

​ &#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1、浅拷贝 2、深拷贝 3、现代版写法的拷贝构造和赋值重载 4、再探swap! 5、写实拷贝&#xff…

面试官:怎样设计一个分布式任务调度平台?

大家好&#xff0c;我是君哥。 在工作中&#xff0c;批量任务调度的需求经常会遇到&#xff0c;比如下面的几个场景&#xff1a; 数据迁移&#xff1a;从数据库 A 批量读取数据&#xff0c;加工后把数据写入数据库 B&#xff1b; 消息通知&#xff1a;运营商批量给客户发送短…

同态加密和SEAL库的介绍(二)BFV 基础方案实现

写在前面&#xff1a; 本篇具体讲解如何使用 BFV 加密方案对加密的整数进行简单的计算&#xff08;一个多项式评估&#xff09;&#xff0c;来源是官方提供的示例。BFV 是比较常见的方案&#xff0c;在很多大模型推理的时候&#xff0c;都是将浮点数的权重和输入变换成…

MongoDB学习笔记(三)

使用Python操作MongoDB: 使用管理员用户&#xff1a;

web基础与http协议与配置

目录 一、web基础 1.1 DNS与域名&#xff08;详解看前面章节&#xff09; 1.2 网页的概念&#xff08;HTTP/HTTPS&#xff09; 1.2.1 基本概念 1.2.2 HTML文档结构(了解) 1.2.3 web相关重点 1.2.4 静态资源和动态资源 二、http协议 2.1 概述 2.2 cookie和session&…

云原生真机实验

基于Proxmox VE构建中小企业云计算平台 首先Proxmox VE是什么&#xff1f;能用来做什么&#xff1f; Proxmox VE是一个完整的企业虚拟化开源平台。借助内置的 Web 界面&#xff0c;可以在单个解决方案上轻松管理 VM(开虚拟机的) 和容器、软件定义的存储和网络、高可用性群集以…