[C.C++] C语言初识2

348 0
Honkers 2025-5-1 07:26:16 | 显示全部楼层 |阅读模式

一、结构体

1.1:概念

1.1.1:为了将不同的数据整合成一个有机整体,以便于引用

1.1.2: C与C++

C语言面向过程 C++面向对象

1.1.3:定义方法1(仅声明)

  1. struct 结构名{
  2. 类型说明符 成员名;
  3. ....
  4. (成员列表)
  5. };
  6. struct student {
  7. int num;
  8. char name[10];
  9. char sex;
  10. int age;
  11. float score;
  12. char addr[30];
  13. };
复制代码

1.1.4:定义方法2(声明的同时定义变量)

  1. struct 结构名{
  2. 类型说明符 成员名;
  3. ....
  4. (成员列表)
  5. }变量名列表;
  6. struct student {
  7. int num;
  8. char name[10];
  9. char sex;
  10. int age;
  11. float score;
  12. char addr[30];
  13. }student1,student2;
复制代码

1.1.5:结构体变量的大小

1.1.5.1:例子1
  1. struct student {
  2. int num;
  3. char name[10];
  4. char sex;
  5. int age;
  6. float score;
  7. char addr[30];
  8. }student1,student2;
  9. int main() {
  10. printf("%d", sizeof(student1));
  11. return 0;
  12. }
  13. 结果:
  14. 56
复制代码
1.1.5.2:例子2
  1. struct student {
  2. int num;
  3. char name[10];
  4. char sex[5];
  5. int age;
  6. float score;
  7. char addr[30];
  8. }student1,student2;
  9. int main() {
  10. printf("%d", sizeof(student1));
  11. return 0;
  12. }
  13. 输出:
  14. 60
复制代码
1.1.5.3:分析过程

1.1.5.4:总结
  • 对齐的是当前结构体中最大的数据类型的字节量:

    • 比如最大的是double,那就是要对齐8字节
    • 比如最大的是Int,那就是对齐4字节
  • 当遇到数组时,要不要和下一项进行合并,要不要和下下一项进行合并,诸如此类的问题,遵循一个原则:
    合并,直到下一个数据本身就对齐

    • 比如例子2,因为char [10] 和char [5]都没对齐,所以合并,但int age 是对齐的,所以要在这之前进行补齐

1.1.6:定义方法3(无结构体名,直接定义变量)

  1. struct {
  2. int num;
  3. char name[10];
  4. char sex[5];
  5. int age;
  6. float score;
  7. char addr[30];
  8. }student1,student2;
复制代码

1.1.7:定义变量

    1. struct 结构体名 变量名
    复制代码
  • struct student 是结构体类型

    1. sizeof(student) 是错误的
    2. sizeof(struct student) 是正确的
    复制代码

1.2:结构体变量的使用以及初始化

1.2.1:不能将结构体变量作为一个整体输入和输出

1.2.2:正确使用格式是: 结构体变量.成员

  • “.”是成员运算符,在所有运算符中优先级最高;所以可以将

    结构体变量.成员 看作一个整体

  • 例子

    1. struct {
    2. int num;
    3. char name[10];
    4. char sex[5];
    5. int age;
    6. float score;
    7. char addr[30];
    8. }student1,student2;
    9. struct data {
    10. int year;
    11. int month;
    12. int day;
    13. };
    14. struct people {
    15. int num;
    16. char name[20];
    17. struct data birthday;
    18. float score;
    19. }boy1,boy2;
    20. int main() {
    21. //printf("%d", sizeof(student1));
    22. printf("please input num:");
    23. scanf("%d", &boy1.num);
    24. printf("please input name:");
    25. scanf("%s", &boy1.name);
    26. printf("please input birthday:");
    27. scanf("%d%d%d", &boy1.birthday.year, &boy1.birthday.month, &boy1.birthday.day);
    28. printf("please input score:");
    29. scanf("%f", &boy1.score);
    30. printf("学号:%d\t姓名:%s\t生日:%d-%d-%d\t成绩:%f\n", boy1.num, boy1.name, boy1.birthday.year, boy1.birthday.month, boy1.birthday.day, boy1.score);
    31. boy2 = boy1;
    32. printf("%p\n", &boy1);
    33. printf("%p\n", &boy1.birthday);
    34. printf("%p\n", &boy2);
    35. return 0;
    36. }
    37. 输入:
    38. please input num:521
    39. please input name:liukai
    40. please input birthday:2001 6 8
    41. please input score:542.35
    42. 输出:
    43. 学号:521 姓名:liukai 生日:2001-6-8 成绩:542.349976
    44. 00007FF630BCD7A0
    45. 00007FF62A41D7B8
    46. 00007FF630BCD760
    47. 分析:可以看出结构体变量可以和其他变量一样进行成员赋值和变量之间的赋值
    复制代码

1.2.3:结构体变量初始化

1.2.3.1:定义时初始化
  1. struct data {
  2. int year;
  3. int month;
  4. int day;
  5. };
  6. struct people {
  7. int num;
  8. char name[20];
  9. struct data birthday;
  10. float score;
  11. }boy1 = { 123,"liukai",{2001,6,11},963.256 }, boy2 ;
  12. int main() {
  13. //printf("%d", sizeof(student1));
  14. //printf("please input num:");
  15. //scanf("%d", &boy1.num);
  16. //printf("please input name:");
  17. //scanf("%s", &boy1.name);
  18. //printf("please input birthday:");
  19. //scanf("%d%d%d", &boy1.birthday.year, &boy1.birthday.month, &boy1.birthday.day);
  20. //printf("please input score:");
  21. //scanf("%f", &boy1.score);
  22. printf("学号:%d\t姓名:%s\t生日:%d-%d-%d\t成绩:%f\n", boy1.num, boy1.name, boy1.birthday.year, boy1.birthday.month, boy1.birthday.day, boy1.score);
  23. boy2 = boy1;
  24. printf("%p\n", &boy1);
  25. printf("%p\n", &boy1.birthday);
  26. printf("%p\n", &boy2);
  27. return 0;
  28. }
  29. 分析:需要值得注意的是,嵌套结构体的初始化要拿个{}括起来;
  30. 在初始化嵌套结构体时,花括号的作用主要有两个:
  31. 1、区分嵌套结构体的初始化值和外层结构体的其他成员初始化值,
  32. 2、以及明确嵌套结构体自身成员的初始化顺序。
复制代码
1.2.3.2:常见错误
  1. //只能在定义的时候进行整个初始化
  2. case1:
  3. struct people {
  4. int num;
  5. char name[20];
  6. struct data birthday;
  7. float score;
  8. }boy1 = { 123,"liukai",{2001,6,11},963.256 }, boy2 ;
  9. case2:
  10. struct people boy3 = { 123,"liukai",{2001,6,11},963.256 }
  11. case3:
  12. struct people boy[2] = { { 123,"liukai",{2001,6,11},963.256 } ,{ 123,"liukai",{2001,6,11},963.256 } };
  13. //这种定义之后再进行整个初始化的行为是错的
  14. struct people boy[2];
  15. boy[0] = { 123,"liukai",{2001,6,11},963.256 };
  16. printf("学号:%d\t姓名:%s\t生日:%d-%d-%d\t成绩:%f\n", boy[0].num, boy[0].name, boy[0].birthday.year, boy[0].birthday.month, boy[0].birthday.day, boy[0].score);
  17. 分析:
  18. 后续试图通过 boy[0] = { 123,"liukai",{2001,6,11},963.256 };C 语言中,结构体变量初始化通常需要在定义时进行,或使用循环等逐个成员赋值的方式。
复制代码

1.3:结构体数组

1.3.1:定义

一个学生有好几个属性,但现在有十个学生;此时用的数组就是结构体数组。

1.3.2:初始化

  1. struct people boy[2] = { { 123,"liukai",{2001,6,11},963.256 } ,{ 123,"liukai",{2001,6,11},963.256 } };
复制代码
  1. struct people {
  2. int num;
  3. char name[20];
  4. struct data birthday;
  5. float score;
  6. }boy[2] = { { 123,"liukai",{2001,6,11},963.256 } ,{ 123,"liukai",{2001,6,11},963.256 } };
复制代码

1.4:指向结构体类型数据的指针

1.4.1:定义

    1. struct 结构名 *结构体指针变量
    复制代码
  • 和结构体变量一样,也可以在定义结构体时直接进行声明定义

1.4.2:访问成员方式

  • 结构指针变量->成员名

  • *(结构指针变量).成员名

  1. struct data {
  2. int year;
  3. int month;
  4. int day;
  5. };
  6. struct people {
  7. int num;
  8. char name[20];
  9. struct data birthday;
  10. float score;
  11. }boy[2] = { { 1234,"liukai",{2001,6,11},963.256 } ,{ 123,"liukai",{2001,6,11},963.256 } };
  12. struct people *pboy=&boy[1];
  13. printf("%d-%d-%d\n", pboy->birthday.year, pboy->birthday.month, pboy->birthday.day);
  14. 分析:
  15. 1、在pboy->birthday.year中,第二个地方使用.而不是->是因为birthday是结构体people中的一个成员,它本身是一个结构体类型(struct data),而不是一个指针。
  16. 2、*pboy.birthday.year这种写法也是错误的,必须是(*pboy).birthday.year
  17. 2.1、在C语言中,成员访问运算符->和.的优先级高于解引用运算符*。
  18. 2.2、表达式*pboy.birthday.year会被错误地解析,因为编译器会优先处理.运算符。编译器会先尝试访问pboy这个指针对象的birthday成员,而不是首先解引用指针。
复制代码

1.5:结构体做函数参数

1.5.1:用结构体变量做函数参数

  1. void dayin(struct people boy )
  2. {
  3. printf("%d", boy.num);
  4. }
复制代码

1.5.2:用结构体变量指针做函数参数

  1. void dayin(struct people *boy )
  2. {
  3. printf("%d", boy->num);
  4. }
复制代码

二:链表

2.1:动态存储分配


541069.png&pos_id=img-blXEHShX-1745762881147)

2.1.1: malloc

2.1.2: free

2.2:链表

2.2.1:概念

  • 链表是一种常见的数据结构,是动态的进行存储分配的一种结构

  • 链表的组成

    • 头指针:存储一个地址,该地址指向第一个元素

    • 结点:用户需要的实际数据和链接结点的指针

2.2.2:静态链表的建立

  1. struct score {
  2. int math;
  3. int english;
  4. };
  5. struct student {
  6. int num;
  7. struct score scr;
  8. struct student* next;
  9. };
  10. int main() {
  11. struct student stu1, stu2, * head,*temp;
  12. head = &stu1;
  13. stu1.next = &stu2;
  14. stu2.next = NULL;
  15. stu1.num = 1;
  16. stu1.scr.math = 100;
  17. stu1.scr.english = 10;
  18. stu2.num = 2;
  19. stu2.scr.math = 99;
  20. stu2.scr.english = 9;
  21. temp = head;
  22. while (temp != NULL) {
  23. printf("%d-",temp->num);
  24. printf("%d-",temp->scr.math);
  25. printf("%d\n", temp->scr.english);
  26. temp = temp->next;
  27. }
  28. return 0;
  29. }
复制代码

2.2.3:动态链表的建立

首先是当前结点的建立

case1:结束结点

case2:头节点

case3:后续节点

  • 所谓动态链表的建立指的是在程序执行过程中,从无到有的建立起一个链表,即一个一个的开辟结点空间和输入结点数据,并建立起前后链接的关系
  1. #define _CRT_SECURE_NO_WARNINGS // 必须放在第一行!
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. struct score {
  5. int math;
  6. int english;
  7. };
  8. struct student {
  9. int num;
  10. struct score scr;
  11. struct student* next;
  12. };
  13. struct student* creat() {
  14. int n = 0;
  15. struct student* head, * p,*tail;
  16. head = p = tail = NULL;
  17. while (1) {
  18. //创建节点
  19. p = (struct student*)malloc(sizeof(struct student));
  20. //赋初始值
  21. printf("input your num:");
  22. scanf("%d", &p->num);
  23. printf("input your math:");
  24. scanf("%d", &p->scr.math);
  25. printf("input your english:");
  26. scanf("%d", &p->scr.english);
  27. p->next = NULL;
  28. //判断结束条件
  29. if (p->num == 0) {
  30. printf("input ending!\n");
  31. return head;
  32. }
  33. //全局增加
  34. n++;
  35. //指针移动
  36. if (n == 1) {
  37. head = p;
  38. tail = p;
  39. }
  40. else {
  41. tail->next = p;
  42. tail = p;
  43. }
  44. }
  45. }
  46. int main() {
  47. struct student* head, * p;
  48. head = p = NULL;
  49. head = p = creat();
  50. while (p != NULL) {
  51. printf("num-%d math-%d english-%d\n", p->num, p->scr.math, p->scr.english);
  52. p = p->next;
  53. }
  54. printf("out ending!\n");
  55. return 0;
  56. }
  57. 需要注意的点:
  58. 1、结点初始化的流程:
  59. p = (struct student*)malloc(sizeof(struct student));//创建结点空间并返回指针
  60. printf("please input num:\n");//输入成员值
  61. scanf("%d", &(p->num));
  62. printf("please input math:\n");
  63. scanf("%d", &(p->scr.math));
  64. printf("please input english:\n");
  65. scanf("%d", &(p->scr.english));
  66. p->next = NULL;//next指针初始化为空
  67. 2、如果是第一个结点;//头尾指针均指向头节点
  68. head = p;
  69. tail = p;
  70. 如果不是第一个结点://链接尾指针节点和当前初始化的结点,并且更新tail指针
  71. tail->next = p;
  72. tail = p;
  73. 3、在&(p->scr.math)中,括号()是为了改变运算顺序,确保p->scr.math先被解析为一个完整的表达式,然后再取它的地址。
  74. 在&p->scr.math中,->运算符的优先级高于&,所以p->scr.math也会先被解析为一个完整的表达式,然后再取它的地址。
  75. 4、malloc的返回值是void*,必须要加一个强制转换
  76. 5、总结流程:
  77. 开始:
  78. 5.1:初始化变量:
  79. n = 0(全局变量,记录节点数)。
  80. head = NULL(头指针初始化为NULL)。
  81. tail = NULL(尾指针初始化为NULL)。
  82. 5.2:循环开始:
  83. 5.2.1:创建新节点p,并初始化成员值及next指针。
  84. 5.2.2:判断当前节点是否为结束节点:
  85. 是:跳出循环。
  86. 否:继续下一步。
  87. 5.2.3:n++(节点计数加1)。
  88. 5.2.4:判断是否为第一个节点:
  89. 是:
  90. head = p(设置头指针为当前节点)。
  91. tail = p(设置尾指针为当前节点)。
  92. 跳回循环开始。
  93. 否:
  94. 更新尾指针:tail->next = p(将新节点链接到尾部)。
  95. 更新尾指针为当前节点:tail = p。
  96. 跳回循环开始
  97. 6、一定记得加入头文件stdlib
复制代码

2.2.4: 为什么要进行malloc动态分配内存

如果使用如下代码:

  1. struct student* creat() {
  2. int n = 0;
  3. struct student* head, * p,*tail;
  4. head = p = tail = NULL;
  5. while (1) {
  6. //创建节点
  7. struct student stu;
  8. p = &stu;
  9. //p = (struct student*)malloc(sizeof(struct student));
  10. //赋初始值
  11. printf("input your num:");
  12. scanf("%d", &p->num);
  13. printf("input your math:");
  14. scanf("%d", &p->scr.math);
  15. printf("input your english:");
  16. scanf("%d", &p->scr.english);
  17. p->next = NULL;
  18. //判断结束条件
  19. if (p->num == 0) {
  20. printf("input ending!\n");
  21. return head;
  22. }
  23. //全局增加
  24. n++;
  25. //指针移动
  26. if (n == 1) {
  27. head = p;
  28. tail = p;
  29. }
  30. else {
  31. tail->next = p;
  32. tail = p;
  33. }
  34. }
  35. }
复制代码
  1. 用上述代码分析如下:
  2. 调用 creat() 函数时:
  3. +-------------------+
  4. | creat() 栈帧 |
  5. | (局部变量 stu) |
  6. | stu --> 数据 |
  7. +-------------------+
  8. 函数返回后:
  9. +-------------------+
  10. | creat() 栈帧 | --> 已被销毁
  11. +-------------------+
  12. head 指向已销毁的 stu
复制代码
  1. 用malloc分析:
  2. 调用 creat() 函数时:
  3. +--------------------------------+
  4. | creat() 栈帧 |
  5. | |
  6. | head --> [堆内存] --> 节点1 |
  7. | tail --> [堆内存] --> 节点1 |
  8. | p --> [堆内存] --> 节点1 |
  9. | |
  10. | 节点1 --> 节点2 --> ... |
  11. | |
  12. +--------------------------------+
  13. 函数返回后:
  14. +--------------------------------+
  15. | main() 栈帧 |
  16. | |
  17. | head --> [堆内存] --> 节点1 |
  18. | p --> [堆内存] --> 节点1 |
  19. | |
  20. | 节点1 --> 节点2 --> ... |
  21. | |
  22. +--------------------------------+
  23. 内存释放:
  24. +--------------------------------+
  25. | main() 栈帧 |
  26. | |
  27. | 调用 free(head) |
  28. | |
  29. | head --> NULL |
  30. | p --> NULL |
  31. | |
  32. +--------------------------------+
复制代码
特性栈内存堆内存
管理方式编译器自动管理程序员手动管理
分配效率高效(通过指针调整)相对低效(涉及更多的内存管理操作)
生命周期与作用域绑定程序员控制
使用场景局部变量、短期存储动态数据结构、长期存储
风险无(编译器处理)内存泄漏、悬空指针

2.2.5:链表结点的删除

case1: head为空,,即链表为空

case2:删除头节点,只需要移动head指针

case3:删除后面结点,需要移动q->next指针(一定要确保p不为NULL)

case4:未找到删除结点

case3和case4需要通过一个while去遍历,再利用一个if判断排除case4

  1. struct student* delete(struct student *head,int delete_num) {
  2. if (head == NULL) {
  3. printf("list is empty!\n");
  4. return NULL;
  5. }
  6. if (head->num == delete_num) {
  7. head = head->next;
  8. return head;
  9. }
  10. else {
  11. struct student* p=head->next;
  12. struct student* q = head;
  13. if (p == NULL) {
  14. printf("delete error!\n");
  15. return head;
  16. }
  17. while (p->num != delete_num&&p->next!=NULL) {
  18. q = p;
  19. p = p->next;
  20. }
  21. if (p->num == delete_num) {//这种情况包含了p->next!=NULL和p->next==NULL两种情况,但处理步骤是相同的
  22. q->next = p->next;
  23. }
  24. else {//这种情况只包含了一种情况p->num != delete_num&&p->next==NULL,说明未找到
  25. printf("delete fail!!\n");
  26. }
  27. }
  28. return head;
  29. }
  30. int delete_num;
  31. printf("please input delete_num:");
  32. scanf("%d", &delete_num);
  33. head=delete(head,delete_num);
  34. 分析:
  35. 1、注意要返回head指针
  36. 2、如果删除的是头指针要进行特殊处理
  37. 3、q指针的含义是要删除节点的前一个指针,p是要删除的当前指针
  38. 4、要考虑到未找到删除结点的情况,即p->num!=XX&&p->next==NULL
  39. 5、head为NULL则直接返回
复制代码

2.2.6:动态链表的插入

case1: head为空,说明链表为空,直接令head=add_node

case2: 插入第一个结点,需要改变add_node->next指针,再令head=add_node

case3: 插入中间结点。需要改变q,p的值(一定要确保p不为NULL)

case4:插入表尾结点,只需要改变p->next=add_node

case3和case4需要通过一个while去遍历,再利用一个if判断排除case4

  1. struct student* add(struct student* head, struct student* add_node) {
  2. if (head == NULL) {
  3. return add_node;
  4. }
  5. if (head->num > add_node->num) {
  6. add_node->next = head;
  7. return add_node;
  8. }
  9. struct student* q, * p;
  10. q = head;
  11. p = head->next;
  12. if (p == NULL) {
  13. head->next = add_node;
  14. return head;
  15. }
  16. while (p->num < add_node->num&&p->next!=NULL) {
  17. q = p;
  18. p = p->next;
  19. }
  20. if (p->num > add_node->num) {
  21. q->next = add_node;
  22. add_node->next = p;
  23. }
  24. else {
  25. p->next = add_node;
  26. }
  27. return head;
  28. }
  29. struct student* padd_node;
  30. padd_node = (struct student*)malloc(sizeof(struct student));
  31. printf("please input add_node num:");
  32. scanf("%d", &padd_node->num);
  33. printf("please input add_node math:");
  34. scanf("%d", &padd_node->scr.math);
  35. printf("please input add_node english:");
  36. scanf("%d", &padd_node->scr.english);
  37. padd_node->next = NULL;
  38. head = add(head, padd_node);
复制代码

2.2.7:链表的查找

case1: head为空,直接返回null

case2:能找到

case3:到末尾了找不到返回NULL

case2和case3还是通过一个while先进行一个遍历,再根据一个if来进行区别

  1. struct student* search(struct student* head, int search_num) {
  2. struct student * p = head;
  3. if (head == NULL) {
  4. return NULL;
  5. }
  6. while (p->num != search_num&&p->next!=NULL) {
  7. p = p->next;
  8. }
  9. if (p->num == search_num) {
  10. return p;
  11. }
  12. else {
  13. return NULL;
  14. }
  15. }
  16. struct student* psearch;
  17. int search_num;
  18. printf("please input search_num:");
  19. scanf("%d", &search_num);
  20. psearch = search(head, search_num);
  21. if (psearch != NULL) {
  22. printf("num-%d math-%d english-%d\n", psearch->num, psearch->scr.math, psearch->scr.english);
  23. }
  24. else {
  25. printf("search error!!\n");
  26. }
复制代码

2.2.8:链表一系列操作完整代码(第一份代码有BUG,分析两份代码)

  1. #define _CRT_SECURE_NO_WARNINGS // 必须放在第一行!
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. struct score {
  5. int math;
  6. int english;
  7. };
  8. struct student {
  9. int num;
  10. struct score scr;
  11. struct student* next;
  12. };
  13. struct student* creat() {
  14. int n = 0;
  15. struct student* head, * p,*tail;
  16. head = p = tail = NULL;
  17. while (1) {
  18. //创建节点
  19. p = (struct student*)malloc(sizeof(struct student));
  20. //赋初始值
  21. printf("input your num:");
  22. scanf("%d", &p->num);
  23. printf("input your math:");
  24. scanf("%d", &p->scr.math);
  25. printf("input your english:");
  26. scanf("%d", &p->scr.english);
  27. p->next = NULL;
  28. //判断结束条件
  29. if (p->num == 0) {
  30. printf("input ending!\n");
  31. return head;
  32. }
  33. //全局增加
  34. n++;
  35. //指针移动
  36. if (n == 1) {
  37. head = p;
  38. tail = p;
  39. }
  40. else {
  41. tail->next = p;
  42. tail = p;
  43. }
  44. }
  45. }
  46. struct student* delete(struct student *head,int delete_num) {
  47. if (head == NULL) {
  48. printf("list is empty!\n");
  49. return NULL;
  50. }
  51. if (head->num == delete_num) {
  52. head = head->next;
  53. return head;
  54. }
  55. else {
  56. struct student* p=head->next;
  57. struct student* q = head;
  58. while (p->num != delete_num&&p->next!=NULL) {
  59. q = p;
  60. p = p->next;
  61. }
  62. if (p->num == delete_num) {
  63. q->next = p->next;
  64. }
  65. else {
  66. printf("delete fail!!\n");
  67. }
  68. }
  69. return head;
  70. }
  71. struct student* add(struct student* head, struct student* add_node) {
  72. if (head == NULL) {
  73. return add_node;
  74. }
  75. if (head->num > add_node->num) {
  76. add_node->next = head;
  77. return add_node;
  78. }
  79. struct student* q, * p;
  80. q = head;
  81. p = head->next;
  82. while (p->num < add_node->num&&p->next!=NULL) {
  83. q = p;
  84. p = p->next;
  85. }
  86. if (p->num > add_node->num) {
  87. q->next = add_node;
  88. add_node->next = p;
  89. }
  90. else {
  91. p->next = add_node;
  92. }
  93. return head;
  94. }
  95. struct student* search(struct student* head, int search_num) {
  96. struct student * p = head;
  97. if (head == NULL) {
  98. return NULL;
  99. }
  100. while (p->num != search_num&&p->next!=NULL) {
  101. p = p->next;
  102. }
  103. if (p->num == search_num) {
  104. return p;
  105. }
  106. else {
  107. return NULL;
  108. }
  109. }
  110. int main() {
  111. struct student* head, * p;
  112. head = p = NULL;
  113. head = p = creat();
  114. while (p != NULL) {
  115. printf("num-%d math-%d english-%d\n", p->num, p->scr.math, p->scr.english);
  116. p = p->next;
  117. }
  118. printf("out ending!\n");
  119. int delete_num;
  120. printf("please input delete_num:");
  121. scanf("%d", &delete_num);
  122. head=delete(head,delete_num);
  123. struct student* padd_node;
  124. padd_node = (struct student*)malloc(sizeof(struct student));
  125. printf("please input add_node num:");
  126. scanf("%d", &padd_node->num);
  127. printf("please input add_node math:");
  128. scanf("%d", &padd_node->scr.math);
  129. printf("please input add_node english:");
  130. scanf("%d", &padd_node->scr.english);
  131. padd_node->next = NULL;
  132. head = add(head, padd_node);
  133. p = head;
  134. while (p != NULL) {
  135. printf("num-%d math-%d english-%d\n", p->num, p->scr.math, p->scr.english);
  136. p = p->next;
  137. }
  138. printf("out ending!\n");
  139. struct student* psearch;
  140. int search_num;
  141. printf("please input search_num:");
  142. scanf("%d", &search_num);
  143. psearch = search(head, search_num);
  144. if (psearch != NULL) {
  145. printf("num-%d math-%d english-%d\n", psearch->num, psearch->scr.math, psearch->scr.english);
  146. }
  147. else {
  148. printf("search error!!\n");
  149. }
  150. return 0;
  151. }
复制代码
  1. #define _CRT_SECURE_NO_WARNINGS // 必须放在第一行!
  2. #include<stdio.h>
  3. #include<stdlib.h>
  4. int n = 0;
  5. struct score {
  6. int math;
  7. int english;
  8. };
  9. struct student {
  10. int num;
  11. char name[10];
  12. struct score scr;
  13. struct student* next;
  14. };
  15. struct student* creat() {
  16. struct student* head, * tail, * p;
  17. head = tail = p = NULL;
  18. while (1) {
  19. //创建结点并初始化
  20. p = (struct student*)malloc(sizeof(struct student));
  21. printf("please input num:");
  22. scanf("%d", &p->num);
  23. printf("please input name:");
  24. scanf("%s", p->name);
  25. printf("please input math:");
  26. scanf("%d", &p->scr.math);
  27. printf("please input english:");
  28. scanf("%d", &p->scr.english);
  29. p->next = NULL;
  30. //判断是否是结束结点(判断输入的num是不是0)
  31. if (p->num == 0) {
  32. return head;
  33. }
  34. //不是结束结点
  35. n++;
  36. //判断是不是头节点
  37. if (n == 1) {
  38. head = tail = p;
  39. }
  40. else {
  41. tail->next = p;
  42. tail = p;
  43. }
  44. }
  45. }
  46. void print(struct student* head) {
  47. struct student* p = head;
  48. while (p != NULL) {
  49. printf("num-%d\tname-%s\tmath-%d\tenglish-%d\n", p->num, p->name, p->scr.math, p->scr.english);
  50. p = p->next;
  51. }
  52. }
  53. struct student* search(struct student* head, int search_num) {
  54. if (head == NULL) {
  55. return NULL;
  56. }
  57. struct student* p = head;
  58. while (p->num != search_num && p->next != NULL) {
  59. p = p->next;
  60. }
  61. if (p->num == search_num) {
  62. return p;
  63. }
  64. else {
  65. return NULL;
  66. }
  67. }
  68. struct student* add(struct student* head, struct student* add_node) {
  69. if (head == NULL) {//空链表
  70. return add_node;
  71. }
  72. if (head->num > add_node->num) {//插到头结点
  73. add_node->next = head;
  74. return add_node;
  75. }
  76. struct student* q, * p;
  77. q = head;
  78. p = head->next;
  79. if (p == NULL) {
  80. head->next = add_node;
  81. return head;
  82. }
  83. while (p->num < add_node->num&&p->next!=NULL) {//中间结点和尾结点
  84. q = p;
  85. p = p->next;
  86. }
  87. if (p->num == add_node->num) {
  88. printf("add_node repeat!\n");
  89. return head;
  90. }
  91. if (p->num > add_node->num) {//此判断说明插入链表中间节点
  92. q->next = add_node;
  93. add_node->next = p;
  94. }
  95. else {//此判断说明插入链表尾节点
  96. p->next = add_node;
  97. }
  98. return head;
  99. }
  100. struct student* delete(struct student* head, int delete_num) {
  101. if (head == NULL) {
  102. printf("delete error!\n");
  103. return head;
  104. }
  105. if (head->num == delete_num) {
  106. printf("delete success\n");
  107. return head->next;
  108. }
  109. struct student* q, * p;
  110. q = head;
  111. p = head->next;
  112. if (p == NULL) {
  113. printf("delete error!\n");
  114. return head;
  115. }
  116. while (p->num != delete_num && p->next != NULL) {
  117. q = p;
  118. p = p->next;
  119. }
  120. if (p->num == delete_num) {
  121. q->next = p->next;
  122. printf("delete success\n");
  123. return head;
  124. }
  125. else {
  126. printf("delete error!\n");
  127. return head;
  128. }
  129. }
  130. int main() {
  131. struct student* head, *search_node,*add_node;
  132. int search_num, delete_num;
  133. head = creat();
  134. print(head);
  135. add_node = (struct student*)malloc(sizeof(struct student));
  136. printf("please input add_node num:");
  137. scanf("%d", &add_node->num);
  138. printf("please input add_node name:");
  139. scanf("%s", add_node->name);
  140. printf("please input add_node math:");
  141. scanf("%d", &add_node->scr.math);
  142. printf("please input add_node english:");
  143. scanf("%d", &add_node->scr.english);
  144. add_node->next = NULL;
  145. head = add(head, add_node);
  146. print(head);
  147. printf("please input delete_num:");
  148. scanf("%d", &delete_num);
  149. head = delete(head, delete_num);
  150. print(head);
  151. printf("please input search_num:");
  152. scanf("%d", &search_num);
  153. search_node = search(head,search_num);
  154. if (search_node == NULL) {
  155. printf("search erroe!\n");
  156. }
  157. else {
  158. printf("num-%d\tname-%s\tmath-%d\tenglish-%d\n", search_node->num, search_node->name, search_node->scr.math, search_node->scr.english);
  159. }
  160. return 0;
  161. }
复制代码

2.3: typedef



用typedef声明新的类型名来代替已有的类型名

2.3.1:用法1(一般数据类型):

  1. typedef int III;
  2. int main() {
  3. III iii = 10;
  4. printf("%d", iii);
  5. return 0;
  6. }
复制代码

2.3.2:用法2(定义结构体类型):

  1. typedef struct {
  2. int year;
  3. int month;
  4. int day;
  5. }DATA;
  6. DATA birthday;
  7. birthday.year = 2001;
  8. birthday.month = 06;
  9. birthday.day =8;
  10. printf("year-%d,month-%d,day-%d", birthday.year, birthday.month, birthday.day);
复制代码

typedef 定义结构体

  • 语法 :在定义结构体的同时,使用 typedef 为其创建一个别名,这样在后续声明变量时就可以直接使用这个别名,而不需要再写 struct 关键字。

2.3.3:用法3(定义为数组类型)

  1. typedef int NUM[100];
  2. NUM num = { 0 };
  3. printf("%d\n", sizeof(num));
  4. typedef char* p;
  5. p p1= "hello";
  6. printf("%s\n", p1);
  7. typedef int (*p)(int,int);
  8. int fun(int a, int b) {
  9. return a + b;
  10. }
  11. p p1;
  12. p1 = fun;
  13. printf("sum=%d\n", p1(1, 2));
复制代码

三、补充知识

在 C 语言中,数据的进制表示主要通过特定的前缀来区分,以下是常见进制及其前缀的介绍:

十进制(Decimal)

  • 前缀特点 :没有特殊前缀,数字直接按正常方式书写即可,比如 123、456 等,都是十进制数。
  • 适用场景 :日常编程中,十进制是最常用的表示方式,适用于各种整数和小数的表示,比如变量赋值、数学运算等。

八进制(Octal)

  • 前缀特点 :以数字 0(零)开头,例如 0123、0456 等。需要注意的是,这里的 0 是阿拉伯数字零,不是字母 O。
  • 适用场景 :八进制在某些特定场景下比较有用,比如文件权限设置(如 Unix/Linux 系统中的文件权限),用八进制表示权限更简洁直观。在编程中,如果需要将整数以八进制形式输出或处理,可以使用八进制前缀。

十六进制(Hexadecimal)

  • 前缀特点 :以 0x 或 0X 开头,例如 0x1A2B、0XABCDEF 等。十六进制数中可以用字母 A-F(不区分大小写)来表示数值 10-15。
  • 适用场景 :十六进制常用于表示内存地址、颜色值(如 HTML/CSS 中的颜色代码)、位操作等场景。因为十六进制和二进制的转换比较方便,每一位十六进制数对应 4 位二进制数,在处理低层数据或硬件相关编程时也很常用。

二进制(Binary)

  • 前缀特点 :在标准 C 语言中,没有官方规定的二进制前缀。但在一些编译器(如 GCC)支持的扩展语法中,可以用 0b 或 0B 作为前缀来表示二进制数,例如 0b1010、0B1101 等。
  • 适用场景 :二进制主要用于底层编程、位操作相关的场景,如设置硬件寄存器、处理二进制文件等。虽然标准 C 没有二进制前缀,但在实际编程中,如果编译器支持,使用二进制前缀可以让代码更直观易懂。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4012
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行