结构体中的链表指针以及->的含义,内存角度理解最易懂

本文详细解析了C/C++中结构体的定义与初始化,以及如何使用指针操作结构体成员变量。通过实例说明了指针指向结构体的具体方式,并解释了如何通过指针访问结构体内的数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

struct Node 
{
    int a,b;
};


上面定义了这样一个结构体

struct Node t = {1,2};

我们需要先理解这句话的含义。这样进行一个初始化,那么{1, 2},你可以认为是内存中的某块区域已经分配给你了,其中的值就是{1, 2}。而前面的t呢,就是这结构体的副本了,你可以认为t就是这个结构体。


struct Node *p;

这里和上面就不一样了。他是一个指针了。而且是一个指向的类型被限定为Node的指针。指针的意思就是指向哪一块内存区域。


我们这里要做的就是让他指向上面那个结构体。

还记得取地址符吗?我们可以通过它来获取结构体的在内存中的位置。&t

所以p直接指向这个地址就可以了 。

p = &t;

为什么可以这样做呢?就需要理解指针了。当你定义了一个指针后,上面的p就是指向的地址,p*就是内存地址中的值了。


那么现在p就指向{1, 2}的那快内存空间了。怎么从中取出这两个数呢?

p -> a;

这个就是{1, 2}中的1了。

其实就是p->a中包含了两个指向。p是指向{1,2}的那块区域,->a又是指向这块区域中的1。(这里我思考了一会,发现结构体中的 int没有用指针的形式定义,所以p->a就是直接指向1了。


所以->其实也相当于指针,只不过指向的是结构体自身的元素在内存中的位置



#include <stdio.h> #include <stdlib.h> // (3) 定义字符型单链表结构体 typedef struct LNode { char data; // 存储字符数据 struct LNode* next; // 后继指针 } LNode, *LinkList; // (4) 尾插法创建链表(带内存分配检查) void CreateList_R(LinkList* L) { *L = (LinkList)malloc(sizeof(LNode)); if (!*L) exit(1); // 内存分配检查 (*L)->next = NULL; LNode* r = *L; // 尾指针 char input; printf("输入字符(空格分隔,#结束):\n"); while (1) { scanf(" %c", &input); // 跳过空白符 if (input == '#') break; LNode* p = (LNode*)malloc(sizeof(LNode)); if (!p) exit(1); // 内存分配检查 p->data = input; p->next = NULL; r->next = p; // 尾插操作 r = p; // 更新尾指针 } } // (4) 打印链表 void PrintLinkList(LinkList L) { LNode* p = L->next; // 跳过头节点 while (p) { printf("%c -> ", p->data); p = p->next; } printf("NULL\n"); } // (5) 转置链表(迭代法) void ReverseList(LinkList* L) { LNode* pre = NULL; LNode* cur = (*L)->next; // 跳过头节点 LNode* next = NULL; while (cur) { next = cur->next; // 保存后继 cur->next = pre; // 反转链接 pre = cur; // 前移指针 cur = next; } (*L)->next = pre; // 头节点指向新首元节点 } // 内存释放 void FreeList(LinkList L) { LNode* p; while (L) { p = L; L = L->next; free(p); } } int main() { LinkList L; // 创建链表 CreateList_R(&L); printf("\n原始链表:"); PrintLinkList(L); // 转置链表 ReverseList(&L); printf("转置链表:"); PrintLinkList(L); // 释放内存 FreeList(L); return 0; }可以再易懂一点吗
03-08
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> // 用户角色枚举 typedef enum { ROLE_ADMIN, ROLE_OPERATOR, ROLE_FINANCE } UserRole; // 权限标志位(使用位域优化存储) typedef struct { unsigned int manage_users : 1; // 用户管理权限 unsigned int manage_products : 1; // 农产品管理 unsigned int manage_members : 1; // 社员管理 unsigned int manage_inventory : 1; // 库存管理 unsigned int manage_sales : 1; // 销售管理 unsigned int manage_finance : 1; // 财务管理 } Permissions; // 用户结构体 typedef struct User { int user_id; // 用户ID char username[50]; // 用户名 char password[50]; // 密码 UserRole role; // 用户角色 Permissions permissions;// 具体权限 struct User* next; // 链表指针 } User; // 全局用户链表 User* user_list = NULL; // 初始化默认用户(管理员) void init_default_users() { User* admin = (User*)malloc(sizeof(User)); admin->user_id = 1001; strcpy(admin->username, "admin"); strcpy(admin->password, "123456"); admin->role = ROLE_ADMIN; admin->permissions.manage_users = 1; admin->permissions.manage_products = 1; admin->permissions.manage_members = 1; admin->permissions.manage_inventory = 1; admin->permissions.manage_sales = 1; admin->permissions.manage_finance = 1; admin->next = NULL; user_list = admin; } // 创建新用户 User* create_user(int id, const char* name, const char* pwd, UserRole role) { User* new_user = (User*)malloc(sizeof(User)); new_user->user_id = id; strncpy(new_user->username, name, 49); strncpy(new_user->password, pwd, 49); new_user->role = role; // 根据角色设置默认权限 switch(role) { case ROLE_ADMIN: new_user->permissions.manage_users = 1; new_user->permissions.manage_products = 1; new_user->permissions.manage_members = 1; new_user->permissions.manage_inventory = 1; new_user->permissions.manage_sales = 1; new_user->permissions.manage_finance = 1; break; case ROLE_OPERATOR: new_user->permissions.manage_products = 1; new_user->permissions.manage_members = 1; new_user->permissions.manage_inventory = 1; new_user->permissions.manage_sales = 1; break; case ROLE_FINANCE: new_user->permissions.manage_finance = 1; break; } new_user->next = NULL; return new_user; } // 用户登录验证 User* user_login(const char* username, const char* password) { User* current = user_list; while(current) { if(strcmp(current->username, username) == 0 && strcmp(current->password, password) == 0) { return current; } current = current->next; } return NULL; } // 打印用户信息 void print_user(User* user) { printf("\n=== 用户详情 ===\n"); printf("用户ID: %d\n", user->user_id); printf("用户名: %s\n", user->username); printf("角色: %s\n", user->role == ROLE_ADMIN ? "管理员" : user->role == ROLE_OPERATOR ? "操作员" : "财务人员"); printf("权限清单:\n"); if(user->permissions.manage_users) printf(" - 用户管理\n"); if(user->permissions.manage_products) printf(" - 农产品管理\n"); if(user->permissions.manage_members) printf(" - 社员管理\n"); if(user->permissions.manage_inventory) printf(" - 库存管理\n"); if(user->permissions.manage_sales) printf(" - 销售管理\n"); if(user->permissions.manage_finance) printf(" - 财务管理\n"); } int main() { init_default_users(); // 测试登录 User* current = user_login("admin", "123456"); if(current) { print_user(current); } else { printf("登录失败!\n"); } return 0; }根据这个用户结构体写出有关管理员的函数
05-30
任务描述 假设初始状态下可用的内存空间为55MB,并有如下的请求序列: 作业1申请15MB 作业2申请30MB 作业1释放15MB 作业3分配8MB 作业4分配6MB 作业2释放30MB 请采用首次适应算法进行内存块的分配和回收,并打印出空闲内存分区链的情况 相关知识 为了完成本关任务,你需要掌握使用首次适应算法进行内存块的分配与回收。 内存分配 空闲分区链按地址递增的顺序链接。在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区。然后再按照作业的大小,从该分区中划出一块内存空间,分配给请求者,余下的空闲分区仍留在空闲链中。若从链首到链尾都找不到一个能满足要求的分区,则表明系统没有足够大的内存分配给该进程,内存分配失败返回。 内存回收 当进程运行完毕释放内存时,系统根据回收区的首址,从空闲区链(表)中找到相应的插入点,此时可能出现以下四种情况之一: (1) 回收区与插入点的前一个空闲分区F1相邻接,此时应将回收区与插入点的前一分区合并,不必为回收分区分配新表项,而只需修改其前一分区F1的大小。 (2) 回收分区与插入点的后一空闲分区F2相邻接,此时也可将两分区合并,形成新的空闲分区,但用回收区的首址作为新空闲区的首址,大小为两者之和。 (3) 回收区同时与插入点的前、后两个分区F1和F2邻接,此时将三个分区合并,使用F1的表项和F1的首址,取消F2的表项,大小为三者之和。 (4) 回收区前后没有空闲分区。这时应为回收区单独建立一个新表项,填写回收区的首址和大小,并根据其首址插入到空闲链中的适当位置 编程要求 空闲分区采用带头结点的双向链表来管理,主函数、链表初始化函数和打印函数已实现,只需要补充首次适应算法分配内存的函数 first_fit以及内存回收的函数recycle()即可。 bool first_fit(int id,int m_size)//使用首次适应算法给作业分配内存,id为作业号,m_size为作业大小 void recycle(int id)//回收内存,id为释放内存的作业号 测试说明 平台会对你编写的代码进行测试: 预期输出: 开始你的任务吧,祝你成功!#include <stdio.h> #include <stdlib.h> const int Max_length=55;//内存 struct areaNode//管理分区的结构体 { int ID;//分区号 int size;//分区大小 int address;//分区地址 int flag;//使用状态,0为未占用,1为已占用 }; typedef struct DuNode//双向链表结点 { struct areaNode data;//数据域 struct DuNode *prior;//指针域 struct DuNode *next; }*DuLinkList; DuLinkList m_head = new DuNode, m_last = new DuNode;//双向链表首尾指针 void init()//分区链表初始化 { m_head->prior = NULL; m_head->next = m_last; m_last->prior = m_head; m_last->next = NULL; m_head->data.size = 0; m_last->data.address = 0; m_last->data.size = Max_length; m_last->data.ID = 0; m_last->data.flag = 0; } void show() { DuNode *p = m_head->next;//指向空闲区队列的首地址 printf("+++++++++++++++++++++++++++++++++++++++\n"); while (p) { printf("分区号:"); if (p->data.ID == 0) printf("FREE\n"); else printf("%d\n",p->data.ID); printf("分区起始地址:%d\n",p->data.address); printf("分区大小:%d\n",p->data.size); printf("分区状态:"); if (p->data.flag) printf("已被占用\n"); else printf("空闲\n");
04-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值