b站:https://www.bilibili.com/video/av418203
目录:
一 、 char t[10] = "hi" & char *p = "hi" 的区别
二、 动态内存分配
三、 释放动态内存
四、 链表基本概念
五、 链表的遍历
六、 插入
一、char t[10] = "hi" & char *p = "hi" 的区别
1)
char t[10] = "hi" (其实是{“h”, “i”}的简写) -----> 可变 -----> 内存的动态存储区
-----> 数组在定义的时候 在动态内存声明了相应的长度的区域,大小取决于数组的长度
2)
char *p = "hi" -----> 不可变 -----> 内存的静态存储区
(数据可以读出来,但是不能写进去。静态不能更改)
-----> "hi"是常量,不能通过“hi” = "en "来修改,指针p指向的是一块静态内存,其中数据不能动态更改
二、 动态内存分配
malloc函数:
void *malloc(unsigned int size) 无符号整数型 (ps:右边输入一个10,就在内存中找地方,再把首地址左边返回)
在内存的动态存储区中分配一个长度为size的连续空间。
参数:无符号整数
返回值:是系统分配的,连续内存空间的起始地址
若分配内存空间失败(如内存不足),则返回NULL。所以在使用之前一定判断是否为NULL
ps:该函数只针对指针使用,使用前引用malloc,h库
(ps:上述函数最后返回一个地址,地址存在指针里面。因为数组本身有内存,不能又申请一个内存赋予它,长度不一样会出各种错误。)
#include<stdio.h>
#include<malloc.h> // 为了使用malloc函数
#include<windows.h>
#include<string.h>
void main()
{
char *a;
a = (char *)malloc(10 * sizeof(char));
// 原本的格式是void *malloc(10 * sizeof(char)) ,现在把void*类型强制类型转换为char*类型
// 通过malloc获取的是动态内存,付给指针来操作这个内存
// 获取一个char类型的长度sizeof(char),申请10个char单位的长度,
// 返回回来的是指针,指针里面存储的是地址。
// 申请一块动态内存,并返回这块内存的地址
if(a == NULL) { // 判断一下是不是为空
printf("内存分配失败");
exit;
}
*a = 'H';
*(a+1) = 'e';
*(a+2) = 'l';
*(a+3) = 'l';
*(a+4) = 'o';
*(a+5) = '\n';
*(a+6) = '\0'; // 字符串结尾是要有\0
printf(a);
Sleep(10000);
}
三、 释放动态内存
free函数
void *free(void *p)
申请了内存,一定要去释放!!!
ps;把指针放进去就释放指针所指向的内存
eg:
char *a, *b;
a = (char *) malloc(10 * sizeof(char));
b = a;
...
free(a); /* 释放其指向的动态内存 */
free(b)是同样的,因为释放的是指向的动态内存,指针只是一个中介
char *a, *b;
a = (char *) malloc(10 * sizeof(char));
b = a;
...
free(b); /* 释放其指向的动态内存 */
四、 链表基本概念
数组:
存储形式上来说,数组实际上并不是一个很方便的结构。
int arr[8]
[1, 1, 2, 3, 5, x, x, x] // 线性结构
向其中插入数字很费力,后面都要依次后延。
缺点:
1 增加删除不方便。
2 可能会存在累赘,一个数组里面存人名,不一定占满。
链表:
为了实现动态保存一串数据。
动态是指不需要预先分配内存空间,而是需要时动态申请内存。
整个数据产保存所需要的空间可以根据需要扩大或者缩小,而设计的一种数据结构。
----------------------链表结构----------------------
数据1 alan 数据1 zjc 数据1 alex
数据2 18 数据2 16 数据2 14
指针 指针 指针
---------------------------------------------------------
同色相指
结构:
1)数据域
存储数据
2)指针域
存储下一个节点元素的地址
----------------------链表结构----------------------
数据1 alan 数据1 zjc 数据1 alex 数据域
数据2 18 数据2 16 数据2 14
指针 指针 指针 指针域
---------------------------------------------------------
eg:
如果有后继元素,指针link指向下一个元素,
如果没有,则设置为NULL(空)
struct Student {
char name[256];
int age;
struct Student *link; // 指针link指向下一个元素
};
例子1:用结构体依次输出名字:
b站:https://www.bilibili.com/video/av418203
#include<stdio.h>
#include<malloc.h> // 为了使用malloc函数
#include<windows.h>
#include<string.h>
struct Student {
char name[10];
struct Student *next; // 结构体指针
};
void main() {
struct Student s1 = {"Alan", NULL};
struct Student s2 = {"Ben", NULL};
struct Student s3 = {"Cici", NULL};
struct Student s4 = {"David", NULL};
struct Student *p; // 注意:这里的声明都需要放在最前面,否则像up主那样写在vs里面会报错
s1.next = &s2;
s2.next = &s3;
s3.next = &s4;
p = & s1;
while (1) {
if (p->next != NULL) {
printf("%s \n", p->name);
p = p->next;
} else {
printf("%s \n", p->name);
break;
}
}
Sleep(5000);
}
输出:
Alan
Ben
Cici
David
例子二:依次scanf输入名字,直到不像输入,然后摁 N 为止
我把 next 与 _next 分开
up主都用的next, 这不利于理解
#include<stdio.h>
#include<windows.h>
#include<string.h> // 字符串操作需要加这个头文件
#include<malloc.h>
struct Student {
char name[10]; // 成员
struct Student *_next;
};
struct Student *create() {
struct Student *head, *current, *next;
char str[10];
char flag;
printf("Please input name: \n");
scanf("%s", str); // 在输入完这个str之后摁了以下回车,如果不用getchar(),这回车会存在缓存里面
getchar(); // 下面的scanf会从缓存里面把回车读出来,相当于把回车这个字符保存在了flag里面
// 这里的getchar()把这个回车给处理掉
head = (struct Student *)malloc( sizeof(struct Student) );
strcpy(head->name, str);
current = head;
// Y/N
printf("是否继续输入: ");
scanf("%c", &flag); // 这里的scanf会从缓存里面把回车读出来,相当于把回车这个字符保存在了flag里面。后面的判断就失效了。
while(flag != 'N') {
printf("Please input name: \n");
scanf("%s", str);
getchar();
next = (struct Student *)malloc( sizeof(struct Student) ); // 新申请一个结构体
strcpy( next->name, str);
// 上一个元素的指针指向下一个元素
current->_next = next; // 完成链表的链接&
// 当前指针指向下一个元素
current = next;
printf("是否继续输入:\n");
scanf("%c", &flag);
}
// 循环结束,当前指针指向最后一个元素,此时将最后一个元素的,此时将最后一个元素的指针赋值为NULL
current->_next = NULL;
return head;
}
void main() {
struct Student *p;
p = create();
while(1) { // 这是打印输出的过程
printf("%s \n", p->name);
if(p->_next!=NULL) {
p = p->_next; //p指向下一个目标,让当前p变为下一个p&
}else {
break;
}
}
Sleep(10000);
}
问题1:
查询一下getchar()的功能
https://blog.csdn.net/zjc910997316/article/details/89351519
问题2:
// Y/N
printf("是否继续? \n");
scanf("%c", &flag);
输入字符需要加&
问题3:
struct Student *p;
p = create();
还是不太懂
五、 链表的遍历
遍历
#include<string.h>
#include<windows.h>
#include<stdio.h>
#include<string.h>
struct Student {
char name[10];
struct Student *_next;
};
struct Student *create() {
struct Student *head, *current, *next;
char str[10];
char flag;
printf("请输入名:\n");
scanf("%s", str);
getchar();
head = (struct Student *)malloc( sizeof(struct Student));
strcpy(head->name, str);
current = head;
printf("是否继续输入:\n");
scanf("%c", &flag);
while(flag != 'N') {
printf("请输入名:\n");
scanf("%s", str);
getchar();
next = (struct Student *)malloc( sizeof(struct Student) );
strcpy(next->name, str);
current->_next = next;
current = next;
printf("是否继续输入:\n");
scanf("%c", &flag);
}
current->_next = NULL;
return head;
}
void list (struct Student *p) { // 把遍历部分封装成函数
while(1) {
printf("%s \n", p->name);
if(p->_next != NULL) {
p = p->_next;
}else {
break;
}
}
}
void main() {
struct Student *p;
p = create();
list(p); // 这里引用
Sleep(10000);
}
六、 插入
插入元素,在已经有的链表里面插入新的内容。
多次插入任意位置
#include<string.h>
#include<windows.h>
#include<stdio.h>
#include<string.h>
struct Student {
char name[10];
struct Student *_next;
};
struct Student *create() {
struct Student *head, *current, *next;
char str[10];
char flag;
printf("请输入名:\n");
scanf("%s", str);
getchar();
head = (struct Student *)malloc( sizeof(struct Student));
strcpy(head->name, str);
current = head;
printf("是否继续输入:\n");
scanf("%c", &flag);
while(flag != 'N') {
printf("请输入名:\n");
scanf("%s", str);
getchar();
next = (struct Student *)malloc( sizeof(struct Student) );
strcpy(next->name, str);
current->_next = next;
current = next;
printf("是否继续输入:\n");
scanf("%c", &flag);
}
current->_next = NULL;
return head;
}
void list (struct Student *p) {
while(1) {
printf("%s \n", p->name);
if(p->_next != NULL) {
p = p->_next;
}else {
break;
}
}
}
int insert (struct Student *p) {
int position;
struct Student *insert, *current;
char str[10];
current = p;
printf("请输入名: \n");
scanf("%s", str);
getchar();
insert = (struct Student *)malloc( sizeof(struct Student) );
strcpy(insert->name, str);
printf("需要插入的位置为: \n");
scanf("%d", &position);
if (position > 0) {
// 插入在position-1的位置
while(position > 1) {
current = current->_next; // 指针指向下一个元素
position--;
}
insert->_next = current->_next; // 插入元素的指针 指向了 当前元素的下一个元素
current->_next = insert; //当前元素 指向了 插入元素
}else if (position == 0) {
// 插入第一个元素的前面
insert->_next = current;
p = insert;
}
return p;
}
void main() {
struct Student *p;
p = create();
printf("当前链表元素为: \n");
list(p);
while(1) {
p = insert(p);
printf("插入元素后的链表为: \n");
list(p);
}
Sleep(10000);
}