C语言--(十)(Lellansin) 动态内存分配 & 链表

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);
}


猜你喜欢

转载自blog.csdn.net/zjc910997316/article/details/89323131
今日推荐