深究C语言4.链表和结构体

简介: 链表和结构体算是比较难的东西了,而且,这些还是为了后面学数据结构打基础,可谓是承上启下的作用,一定要把它学好。

链表和结构体算是比较难的东西了,而且,这些还是为了后面学数据结构打基础,可谓是承上启下的作用,一定要把它学好。


首先要说一下的就是,结构体与指针的联系是比较多的,也就是说,你的指针方面的知识是必须也要过关的。


9ed6a5cb72234d3789e02805d065854a.png


我们现在一点一点慢慢来吧。


一,结构体


一,结构体的定义


/

struct s {
  int i;
  char c;
};


struct s是类型名,还未定义变量,i和c都是结构体的成员变量。要知道的是,结构体是一种自定义类型,(可以往前面看一看我的初始C语言2.C语言的四种结构)。所以说,struct s只是类型名,并不是说这是一个结构体的名字叫做s,我这时候还没有定义新的结构体变量名。结构体类型的定义记得要加分号;


可以在之后再去定义,也可以直接就在花括号的分号后面加上变量名。(可定义多个)


struct s {
  int i;
  char c;
}s1,s2;


也可以定义一种叫做匿名结构体的结构体。


struct {
  int i;
  char c;
};


就是不给变量名的结构体


下面是我在csdn上找到的别人的对匿名结构体运用的博文。大家可以看一下。(3条消息) 匿名结构体与匿名联合体_kuikuitage的博客-CSDN博客_匿名结构体


#include <stdio.h>    
struct person    
{    
    char    *name;    
    char     gender;    
    int      age;    
    int      weight;    
    struct  
    {    
        int  area_code;    
        long phone_number;    
    };   
};    
int main(void)    
{  
    struct person jim = {"jim", 'F', 28, 65, {21, 58545566}};  
    printf("%d\n", jim.area_code);       
}   
1#include <stdio.h>    
struct person    
{    
    char    *name;    
    char     gender;    
    int      age;    
    int      weight;    
    struct  
    {    
        int  area_code;    
        long phone_number;    
    };   
};    
int main(void)    
{  
    struct person jim = {"jim", 'F', 28, 65, {21, 58545566}};  
    printf("%d\n", jim.area_code);       
}   
如果不使用匿名结构体,则上述例子对应的代码如下:
#include <stdio.h>    
struct phone  
{  
    int  area_code;  
    long phone_number;  
};  
struct person    
{    
    char        *name;    
    char         gender;    
    int          age;    
    int          weight;    
    struct phone office;  
};    
int main(void)    
{  
    struct person jim = {"jim", 'F', 28, 65, {21, 58545566}};  
    printf("%d\n", jim.office.area_code);       
}   
对比上述两个例子可以看出:
使用匿名结构体,结构体对象 jim 可以通过 jim.area_code 直接访问匿名结构体成员变量 area_code,代码相对比较简洁
反之则必须通过 jim.office.area_code 来访问结构体成员变量


二,结构体的概念


1.


结构类型是一种允许程序员把一些数据分量聚合成一个整体的数据类型。一个结构体中包含的每个数据分量都有名字,这些数据分量被称为结构成员或者结构分量。


结构成员可以是C语言中的任意变量类型。


2.


C语言中把结构的定义看作一条语句。


3.


与数组相比,结构提供了一种更便利的手段,将不同类型的数据组织在一起。增加了可读性,使程序更加清晰。


4.


结构体是可以嵌套定义的,不像函数,函数是不能嵌套定义的。但是,在定义嵌套的结构类型时,必须先定义成员的结构类型,再去定义主结构类型。


e96eaeccf3e3474e97d026d21642b9bd.jpg


注意,这个是有先后之分的。


5.


关键字struct和结构名s必须联合使用,因为他们只有合起来以后才能表示一个变量名。


6.


C语言规定,结构体类型变量的存储布局按照其类型定义中的成员的顺序先后排列。


给你们看两个例子。


#define _CRT_SECURE_NO_WARNINGS 1
//输出平均分最高的学生信息
#include<stdio.h>
struct student {
  int num;
  char name[10];
  int computer, english, math;
  double average;
};
int main() {
  int i, n;
  //定义结构变量
  struct student max, stu;
  printf("Input n:");
  scanf("%d",&n);
  printf("Input the student's information:");
  //这里与已知长度和数据的数组的选择法排序不同,这里数据都是未知的。
  for (i = 1; i <= n; i++) {
    printf("NO.%d:",i);
    scanf("%d%s%d%d%d",&stu.num,stu.name,&stu.math,&stu.english,&stu.computer);
    stu.average = (stu.math + stu.english + stu.computer) / 3.0;
    if (i == 1) {
      max = stu;
    }
    else if (max.average < stu.average)
      max = stu;
  }
  printf("num:%d,name:%s.average:%2lf\n",max.num,max.name,max.average);
  return 0;


#include <stdio.h>
#define MAXN 10
struct student{
    int num;
    char name[20];
    int score;
    char grade;
};
int set_grade( struct student *p, int n );
int main()
{   struct student stu[MAXN], *ptr;
    int n, i, count;
    ptr = stu;
    scanf("%d\n", &n);
    for(i = 0; i < n; i++){
       scanf("%d%s%d", &stu[i].num, stu[i].name, &stu[i].score);
    } 
   count = set_grade(ptr, n);
   printf("The count for failed (<60): %d\n", count);
   printf("The grades:\n"); 
   for(i = 0; i < n; i++)
       printf("%d %s %c\n", stu[i].num, stu[i].name, stu[i].grade);
    return 0; 
}
int set_grade( struct student *p, int n ){
  int count=0; 
  for(int i=0;i<n;i++){
    if((p->score)<60){
      count++;
      p->grade='D';
    }else if(p->score>=60 && p->score<=69){
      p->grade='C';
    }else if(p->score>=70 && p->score<=84)
      p->grade='B';
    else
      p->grade='A'; 
    p++;
  }
  return count;
}


三,结构变量的使用


1.结构变量的操作符‘->’和‘.’


‘->’是指针操作结构变量时的操作符,而‘.’是普通变量操作结构变量的操作符。


由于结构成员运算符的优先级属于最高级别,所以一般情况下都是优先执行。


2.结构变量的赋值


如果两个两个结构变量具有相同的类型,则允许将一个结构变量的值直接赋给另一个结构变量。


这是结构中唯一的整体操作方式。


3cdce5623c634d84b9f17f23326b5589.jpg


即,只有相同结构类型的变量之间才可以直接赋值。


3.结构变量作为函数参数


特点:可以传递多个数据且参数形式较简单,但是,对于成员较多的大型结构,参数传递时所进行的结构数据复制使得效率较低。


这个时候更合适的方法就是定义一个结构体指针,把指针作为参数就好了


4.结构指针


指针可以指向任何一种类型的变量。结构指针的值实际上时结构变量的首地址。即第一个成员的地址。


c748e87ce521416d90ba4fa1777305ce.jpg


5.结构体的大小


d29da7a04e394b5f8b9a695114e27a6e.png


这就涉及一个叫做对齐数的概念了。


(3条消息) C语言之内存对齐数_微风-CSDN博客_c语言内存对齐

https://blog.csdn.net/qq_34328833/article/details/51352663?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163991575616780265494360%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163991575616780265494360&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-51352663.pc_search_result_cache&utm_term=%E5%AF%B9%E9%BD%90%E6%95%B0&spm=1018.2226.3001.4187

这个我看过还不错,你们可以看看。


二,动态内存分配


一,动态内存管理函数


cd593e99f217456a91dbcca90dba7000.png


1.malloc函数


9946954acabe4d75bd056b456fb8eda2.png


malloc函数后面的参数是要分配的长度(字节),返回值是void*类型,故,使用的时候还需要强制类型转换。


2.calloc函数


e8c22fffed7e46b5a5d36c32e0a4c110.png


这里的num指的是分配size个字节的空间,分配了num个。(连续空间)


3.free函数


d746d9cfec0f418eb5ce8b53b501ea54.png


free函数的作用是释放之前分配给指针变量ptr的动态空间,但是指针变量ptr不会自动变为空指针,还是指向之前指向的地方。故,释放完之后,如果还会用到ptr指针,记得要置空,不然ptr就是野指针。  


注意事项:


1.记得每次动态申请完空间后都要释放空间。


2.动态内存分配中得到的是一个没有名字,只有首地址的连续空间,相当于一个无名的一维数组。


3.malloc对所分配的存储块不做任何操作。但是calloc会自动将整个区域进行初始化为0。


4.动态内存分配的是堆区的空间,要么操作者释放,要么程序结束时系统将其释放。


二,内存处理函数


1.memcpy函数


0c75d269a66e410b8a47b49b59614918.png


num指的是长度(字节),destination指的是目的地,source指的是用来传递的变量地址。


在C语言规定中,memcpy应该是拷贝内存不重叠的内存。


2.memmove函数


c61922e8da7d437d9eacc6c4e8980aa4.png


跟上面是差不多的,两者到底有什么差别?我之前写过一个模拟实现他们的章节,可以去看看。


三,链表


一,链表的定义和使用


1.链表是结构体最重要的应用,


它是一种非固定长度的数据结构,是一种动态存储技术,只能作顺序访问,不能作随机访问。数组在结构体中 易浪费空间且不便于操作。


结构体的自引用


结构体的自引用不是在结构体中再引用一个自己,而是引用一个同类型的结构体指针(这个也就是 链表的表现形式)


2.链表的建立


1)申请内存m:内存分为两部分,一部分叫做数据域,另一部分叫做指针域,这里的域就是存储的地方,数据域存放一些普通数据,而指针域存放的是一个指针,该指针指向下一个链表节点的首地址。


2)将数据存储进去


3)若当前是第一个节点,则将m的地址保存在指针head中,否则将m的首地址保存在上一个结点的指针域中。


4)重复上述过程,直到数据存储完毕,在最后一个节点的指针域存储结束标志NULL;


4f3e369bbeec40448db1278b53497a0f.png


再来两个题看看


1.


//求单链表结点的阶乘和
#include <stdio.h>
#include <stdlib.h>
typedef struct Node* PtrToNode;
struct Node {
    int Data; /* 存储结点数据 */
    PtrToNode Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */
int FactorialSum(List L);
#define _CRT_SECURE_NO_WARNINGS 1
int FactorialSum(List L) {
  int sum = 0;
  PtrToNode p;
  for (p = L; p; p = p->next) {
    int fact = 1;
    for (i = 1; i <= p->date; i++) {
      fact *= i;
    }
    sum += fact;
  }
  return sum;
}
int main()
{
    int N, i;
    List L, p;
    scanf("%d", &N);
    L = NULL;
    for (i = 0; i < N; i++) {
        p = (List)malloc(sizeof(struct Node));
        scanf("%d", &p->Data);
        p->Next = L;  L = p;
    }
    printf("%d\n", FactorialSum(L));
    return 0;
}


2.


//建立学生信息链表
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stud_node {
  int    num;
  char   name[20];
  int    score;
  struct stud_node* next;
};
struct stud_node* head, * tail;
void input();
int main()
{
  struct stud_node* p;
  head = tail = NULL;
  input();
  for (p = head; p != NULL; p = p->next)
    printf("%d %s %d\n", p->num, p->name, p->score);
  return 0;
}
void input() {
  struct stud_node* p;
  int x;
  scanf("%d", &x);
  while (x) {
    p = (struct stud_node*)malloc(sizeof(struct stud_node));
    p->num = x;
    scanf("%s%d",p->name, &p->score);
    p->next = NULL;
    if (head == NULL)
      head = p;
    else
      tail->next = p;
    tail = p;
    scanf("%d", &x);
  }
}


3.


//建立一个有N个学生信息数据的链表
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#define N 4
struct student {
  //数据域
  int num;
  char name[20];
  char sex;
  int score;
  //指针域
  struct student* next;
};
int main() {
  //定义指针变量
  struct student* head, * p, * q;
  //定义结点大小
  p = (struct student*)malloc(sizeof(struct student));
  //初始化结点
  scanf("%d%s%c%d",&p->num,p->name,&p->sex,&p->score);
  //将第一个结点的地址给head。
  head = p;
    head->next=NULL;
  //用一个for循环,初始化所有的结点,即整个链表。
  for (int i = 0; i < N; i++) {
    //要重新定义第二个结点,然后初始化
    q = (struct student*)malloc(sizeof(struct student));
    scanf("%d%s%c%d", &q->num, q->name, &q->sex, &q->score);
    //让前一个结点的指针域指向下一个结点的地址
    p->next = q;
    //再让p指向已定义好的结点,q指针继续去处理下一个结点。
    p = q;
  }
  //循环结束后,最后一个结点的指针域为空。
  p->next = NULL;
  //用一个for循环输出所有结点中的信息
  for (p = head; p; p = p->next) {
    printf("%d %s %c %d\n",p->num,p->name,p->sex,p->score);
  }
  return 0;
}


4.


//链表的比较及排序
#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<stdlib.h>
#define N 10
struct student {
  int num;
  int score;
  struct student* next;
};
int main() {
  struct student* head, * p, * q, * k;
  k = (struct student*)malloc(sizeof(struct student));
  //以后内存函数的使用都要判断一下,是否开辟成功,如果未开辟成功,则结束进程
  if (!k)
    exit(1);
  scanf("%d%d",&k->num,&k->score);
  //初始化第一个结点,因为结点是不连续的,仅仅是靠指针域中的地址来进行联系,所以,这既是第一个结点,也是最后一个结点,对指针域进行初始化
  k->next = NULL;
  head = k;
  //接下来对后面的N-1个结点进行定义初始化
  //这一整个片段是很关键的一环,写的是真的好,主要是我没见过
  for (int i = 1; i < N; i++) {
    k = (struct student*)malloc(sizeof(struct student));
    //判断语句
    if (!k)
      exit(1);
    scanf("%d%d", &k->num, &k->score);
    //让p指向第一个结点
    p = head;
    q = NULL;
        //插入操作
    //此时的while起一个比较的作用(升序)
    while (p && (p->num <= k->num)) {
      q = p;
      p = p->next;
    }
    if (p == head) {
      k->next = head;
      head = k;
    }
    else {
      k->next = q->next;
      q->next = k;
    }
  }
  /*首先,让p指向第一个结点,k指向的是一个新结点,二者相比较,如果k指向的结点大于p指向的,先把初始结点的地址给q,p就指向下一位,
  执行else语句。即在q指向的结点后面插入k指向的结点。
  如果p指向的结点数据大于k指向的结点数据,则将k指向的结点插到第一个结点前面,也就是插到相比较结点的前面。
    交换完数据以后,利用for循环再次重新定义一个新节点,再次进行比较。
  */
    free(k);//一定要记得释放申请的内存
  //输出整个的链表
  for (p = head; p; p = p->next) {
    printf("%d  %d\n", p->num,p->score);
  }
  return 0;
}


总结一下上面的几道题,


链表的建立方式有两种,一种是用for循环,先定义一个头节点,再用for循环继续创造后续节点,另一种就是用while循环,在其中设置一个撒谎分支结构,当定义的节点是第一个时,和不是第一个时。


//定义指针变量
  struct student* head, * p, * q;
  //定义结点大小
  p = (struct student*)malloc(sizeof(struct student));
  //初始化结点
  scanf("%d%s%c%d",&p->num,p->name,&p->sex,&p->score);
  //将第一个结点的地址给head。
  head = p;
    head->next=NULL;
  //用一个for循环,初始化所有的结点,即整个链表。
  for (int i = 0; i < N; i++) {
    //要重新定义第二个结点,然后初始化
    q = (struct student*)malloc(sizeof(struct student));
    scanf("%d%s%c%d", &q->num, q->name, &q->sex, &q->score);
    //让前一个结点的指针域指向下一个结点的地址
    p->next = q;
    //再让p指向已定义好的结点,q指针继续去处理下一个结点。
    p = q;
  }
  //循环结束后,最后一个结点的指针域为空。
  p->next = NULL;


void input() {
  struct stud_node* p;
  int x;
  scanf("%d", &x);
  while (x) {
    p = (struct stud_node*)malloc(sizeof(struct stud_node));
    p->num = x;
    scanf("%s%d",p->name, &p->score);
    p->next = NULL;
    if (head == NULL)
      head = p;
    else
      tail->next = p;
    tail = p;
    scanf("%d", &x);
  }
}


要分清这两种方法该怎样的时候要怎么样。


3.逆序链表


http://hi.csdn.net/attachment/201010/23/0_1287825676duab.gif

http://hi.csdn.net/attachment/201010/23/0_1287825676duab.gif

932ca7ae171743348d67acae7507af52.png


#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
typedef struct tagListNode {
    int data;
    struct tagListNode* next;
}ListNode, * List;
void PrintList(List head);
List ReverseList(List head);
int main()
{
    //分配链表头结点
    ListNode* head;
    head = (ListNode*)malloc(sizeof(ListNode));
    head->next = NULL;
    head->data = -1;
    //将[1,10]加入链表
    int i;
    ListNode* p, * q;
    p = head;
    for (int i = 1; i <= 10; i++)
    {
        q = (ListNode*)malloc(sizeof(ListNode));
        q->data = i;
        q->next = NULL;
        p->next = q;
        p = q;
    }
    PrintList(head);           /*输出原始链表*/
    head = ReverseList(head);  /*逆序链表*/
    PrintList(head);           /*输出逆序后的链表*/
    return 0;
}
List ReverseList(List head)
{
    if (head->next == NULL || head->next->next == NULL)
    {
        return head;   /*链表为空或只有一个元素则直接返回*/
    }
    ListNode* t = NULL,
        * p = head->next,
        * q = head->next->next;
    while (q != NULL)
    {
        t = q->next;
        q->next = p;
        p = q;
        q = t;
    }
    /*此时q指向原始链表最后一个元素,也是逆转后的链表的表头元素*/
    head->next->next = NULL;  /*设置链表尾*/
    //这个地方就是一个知识点了,链表的第一个元素是元节点,即头节点的下一个,故,链表逆序时,头节点不变。
    head->next = p;           /*调整链表头*/
    return head;
}
void PrintList(List head)
{
    ListNode* p = head->next;
    //或者用个for循环,遍历
    while (p != NULL)
    {
        printf("%d ", p->data);
        p = p->next;
    }
    printf("/n");
}


4.链表的增删查操作


确实,这些操作都比较简单,直接给个柔和在一起的题,慢慢去磨吧。


#define _CRT_SECURE_NO_WARNINGS 1
//建立链表,查找值为x的结点并删除这个结点,x的值从键盘输入。
#include<stdio.h>
#include<stdlib.h>
//先定义结构体类型
struct node {
  int date;
  struct node* next;
};
//函数声明
struct node* create_number(int);
struct node* find(struct node *, int);
struct node* Delete(struct node *, struct node * );
void out_list(struct node*);
int main() {
  //建议还是初始化一下
  struct node* head=NULL, * p=NULL;
  int n, x;
  n = x = 0;
  printf("Create List,Enter n:");
  scanf("%d", &n);
  head = create_number(n);
  printf("List:");
    out_list(head);
  printf("x:");
    scanf("%d", &x);
    p = find(head, x);
    head = Delete(head, p);
    printf("Result:");
    out_list(head);
  return 0;
}
//创造结点的函数
struct node* create_number(int n) {//n代表准备创造结点的个数
  //创造结点时,至少需要三个指针变量,head固定在首结点,p和k用于创造新结点
  int i;
  struct node* head=NULL, * k=NULL, * p=NULL;
  if (n < 1) {
    return NULL;
  }
  else {
    k = (struct node*)malloc(sizeof(struct node));
    //判断是否申请成功
    if (!k)
      exit(1);
    k->date = 1;//初始化第一个数据
    //第一个结点,也是最后一个,这个操作相当于给指针域初始化
    k->next = NULL;
    head = k;
    p = k;
    for (i = 2; i <= n; i++) {
      k = (struct node*)malloc(sizeof(struct node));
      if (!k)
        exit(1);
      k->date = i;
      //初始化
      k->next = NULL;
      p->next = k;
      p = k;
    }
    return head;
  }
}
//查找函数
struct node* find(struct node* head, int x) {//头指针和待查找的元素
  //另外定义一个指针去遍历,从而保证head指针不被改变
  struct node* p = head;
  while (p && p->date != x) {
    p = p->next;
  }
  if (!p)
    return NULL;
  else
    return p;
}
//删除函数
struct node* Delete(struct node* head, struct node* p) {
  struct node* q;
  if (!p)
    return head;
  //如果p不为空,判断p指向结点的位置,从而进行删除操作
  if (p = head)
    head = head->next;
  else {
    q = head;
    while (q->next != p)
      q = q->next;
    q->next = p->next;
  }
  //别忘了释放空间
  free(p);
  return head;
}
//输出函数
void out_list(struct node* head) {
  //另外定义变量去遍历
  struct node* p;
  if (!head) {
    p = head;
    while (!p) {
      printf("%d", p->date);
      p = p->next;
    }
  }
  else
    printf("不存在\n");
  putchar('\n');
}


其实要写还能写好多,我想了想,还是不写太多了,还不如接着再写一章,希望大家能从中学到东西。

目录
相关文章
|
29天前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
133 14
|
1月前
|
存储 编译器 C语言
【C语言】结构体详解 -《探索C语言的 “小宇宙” 》
结构体通过`struct`关键字定义。定义结构体时,需要指定结构体的名称以及结构体内部的成员变量。
160 10
|
1月前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
442 6
|
2月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
71 5
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
161 13
|
2月前
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
2月前
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
73 11
|
2月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
61 4
|
2月前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
116 4
|
3月前
|
存储 C语言
如何在 C 语言中实现结构体的深拷贝
在C语言中实现结构体的深拷贝,需要手动分配内存并逐个复制成员变量,确保新结构体与原结构体完全独立,避免浅拷贝导致的数据共享问题。具体方法包括使用 `malloc` 分配内存和 `memcpy` 或手动赋值。
92 10