my_print中的强转:
在 C 语言中,结构体的第一个成员会放置在结构体的开始位置,而且结构体的布局是按照成员定义的顺序进行的。因此,在你的代码中,Student
结构体的第一个成员变量就是 LinkNode
类型的 node
。
通过将 LinkNode *data
强制转换为 Student *student
,可以将 Student
结构体的地址赋给指针 student
,从而正确地访问和操作 Student
结构体中的字段。
请注意,强制类型转换只是告诉编译器将某个指针视为另一种类型的指针,但它并不改变实际的内存布局或数据类型。因此,当你确保 LinkNode
结构体是作为 Student
结构体的第一个成员时,并且两者的大小和布局相同,强制类型转换是合法的。
然而,在进行强制类型转换时,请务必确保 LinkNode
指针指向的实际数据类型是 Student
,否则会导致访问错误的内存位置。如果无法确定类型或存在不确定性,最好使用更通用的方式来处理节点的内容。
LinkNode* pCurrent = &(list->head);与LinkNode* tmp = list->head.next;的区别:
第一个取得的是链表头节点指针 LinkNode*
的地址,并把它赋给了pCurrent 指针,然后通过pCurrent->next可以访问到下一个结点
在删除操作里要操作的是结点,在插入操作里操作的也是结点,所以用这个。而且注意传入的参数是LinkNode*类型的,要传入Student的Student.node。
第二个取得的是链表中第一个数据节点的指针 LinkNode*
。
最大的区别就是第一个取得就是头结点,让指针就从头结点开始,第二个就是直接从头结点的下一个数据结点开始。因为.next对应的就是LinkNode*类型的,所以从视觉效果上来看&(list->head)这俩有区别,但实质上都是一样的。
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
typedef struct LinkNode {//链表结点
struct LinkNode* next;
}LinkNode;
typedef struct LinkList {//链表结构体
struct LinkNode head;
int size;
}LinkList;
typedef struct Student {
LinkNode node;
int age;
char name[64];
}Student;
LinkList* Init_Linklist() {//初始化链表
LinkList* list = (LinkList*)malloc(sizeof(LinkList));//分配内存空间
list->head.next = NULL;//头结点默认指向NULL
list->size = 0;
return list;
}
void insert_list_by_position(LinkList* list, int position, LinkNode* data){
if (list == NULL) {
return;
}
if (data == NULL) {
return;
}
if (position<0|| position>list->size) {
position = list->size;
}
LinkNode* tmp = &(list->head);
for (int i = 0; i < position - 1;i++) {
tmp = tmp->next;
}
data->next = tmp->next;
tmp->next = data;
list->size++;
}
void insert_list(LinkList* list,LinkNode* data) {//尾插法
if (list == NULL) {
return;
}
if (data == NULL) {
return;
}
LinkNode* tmp = &(list->head);
while (tmp->next != NULL) {
tmp = tmp->next;
}
data->next = NULL;
tmp->next = data;
list->size++;
}
void remove_linklist(LinkList* list, int pos)
{
if (pos < 0 || pos >= list->size)
{
return;
}
if (list != NULL)
{
LinkNode* pCurrent = &(list->head);//得到了头结点的指针
for (int i = 0; i < pos; i++)
{
pCurrent = pCurrent->next; // 找到当前下标的指针
}
// pCurrent 是pos位置的前驱节点,将pos位置的指针删除掉,就相当于是
// pos的前驱节点指向pos的下一个节点,因为不是自己开辟的内存,不需要释放内存
pCurrent->next = pCurrent->next->next;
list->size--;
}
return;
}
void my_print(LinkList* list) {
LinkNode* tmp = list->head.next;
while (tmp!=NULL) {
Student* p = (Student*)tmp;
printf("age = %d,name = %s\n",p->age,p->name);
tmp = tmp->next;
}
}
int main() {
LinkList* a = Init_Linklist();
Student s1, s2, s3, s4, s5,s6;
s6.age = 0;
strcpy_s(s6.name, "666");
s1.age = 10;
strcpy_s(s1.name,"aaa");
s2.age = 20;
strcpy_s(s2.name, "bbb");
s3.age = 30;
strcpy_s(s3.name, "ccc");
s4.age = 40;
strcpy_s(s4.name, "ddd");
s5.age = 50;
strcpy_s(s5.name, "eee");
insert_list(a,&(s1.node));
insert_list(a, &(s2.node));
insert_list(a, &(s3.node));
insert_list(a, &(s4.node));
insert_list(a, &(s5.node));
my_print(a);
printf("------------------\n");
insert_list_by_position(a,3, &(s6.node));
my_print(a);
printf("------------------\n");
remove_linklist(a,2);
my_print(a);
return 0;
}