栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

c++笔记(指针、结构体、链表)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

c++笔记(指针、结构体、链表)

c + + 学习笔记(指针、结构体、链表)

文章目录
  • c + + 学习笔记(指针、结构体、链表)
    • 一、指针
    • 二、指针与数组
      • 1 数字数组
      • 2 字符串数组
      • 3 指针的指针
      • 4 数组地址和首元素地址
      • 5 数组指针
      • 6 二维数组和数组指针
    • 三、指针与函数
      • 1 整型作为函数的参数
      • 2 一维数组作为函数的参数
      • 3 二维数组作为函数的参数
      • 4 函数的返回值类型为指针类型
      • 5 函数指针
        • 5.1 函数指针变量注意
        • 5.2 函数指针变量 使用typedef定义
        • 5.3 函数指针作为函数的参数
    • 四、 动态内存
      • 1 基本操作
      • 2 操作数组空间
    • 五、 字符串处理函数
      • 1 测量字符串的长度 strlen
      • 2 字符串拷贝函数 strcpy
      • 3 字符串追加 strcat
      • 4 字符串比较 strcmp
    • 六、 结构体
      • 1 结构体
        • 1.1 结构体概述
        • 1.2 结构体变量初始化和清空
        • 1.3 使用键盘赋值
        • 1.4 单独操作结构体中的单元
        • 1.5 相同类型结构体变量之间赋值方法
      • 2 结构体嵌套结构体
      • 3 结构体数组
      • 4 结构体指针变量
        • 4.1 结构体数组元素的指针变量
      • 5 结构体的指针成员
        • 5.1 结构体指针指向堆区
        • 5.2 浅拷贝
        • 5.3 深拷贝
        • 5.4 结构体变量在堆区 结构体的指针成员也指向堆区
      • 6 结构体的对齐规则
    • 七、 链表
      • 1 概述
      • 2 静态链表
      • 3 动态链表
        • 3.1 main函数设计
        • 3.2 链表插入节点
        • 3.3 遍历链表
        • 3.4 按姓名查询
        • 3.5 删除节点
        • 3.6 释放链表
        • 3.7 整体的代码

一、指针

指针就是用来存储地址的类型

int main()
{
    int num = 100;
    int* p = #
    cout << "num的地址是:" << p< 

二、指针与数组 1 数字数组

数组名就是数组首地址

int * arr[4] 这是一个指针数组,本质是个数组,每一个元素是一个指针。

下面例子里arr每一个元素存储的是arr0的每一个对应的元素的地址

//数字数组练习
void test02() {
    int arr0[4] = { 10,20,30,40 };
    //声明一个指针数组
    int* arr[4];
    //输出结果为16,因为指针大小为4B(32位平台)
    cout << sizeof(arr) << endl;
    //计算数组大小
    int n = sizeof(arr) / sizeof(arr[0]);
    //将四个数字的地址赋值给指针数组
    for (int i = 0; i < n; i++)
    {
        arr[i] = &arr0[i];
        //输出地址
        cout << arr[i] << "->";
        //输出内容
        cout << *arr[i] << endl;
    }
}

2 字符串数组

这里声明的arr是指针数组,每一个元素存贮的都是一个地址,所以后面{}里面的元素都进行了(char *)的强制转换。

arr[i] 代表的是第i个元素的首地址

arr[i]+n 代表的是 第i个元素 从第n个字符开始的地址

*(arr[i] + n) 代表的是 第i个元素 从第n个字符的具体的值

//字符串数组练习;
void test01() {
    

    char* arr[4] = { (char *)"abcde",(char*)"fghij",(char*)"jlmno",(char*)"pqrst" };
    //获取数组大小;
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "显示每一个元素" << endl;
    for (int i = 0; i < n; i++)
    {
        //打印每一项的内容。arr[i]获取的是每一个元素的首地址
        cout << arr[i] << " ";
    }
    cout << endl;
    cout << "从每一个元素第三项开始显示" << endl;
    for (int i = 0; i < n; i++)
    {
        cout << arr[i] + 3 << " ";//这里是获取每个元素第三项的地址,显示的是第三项及以后的内容
    }
    cout << endl;
    cout << "显示第三项" << endl;
    for (int i = 0; i < n; i++)
    {
        cout << *(arr[i] + 3) << " ";
    }

}

3 指针的指针

num是个整型变量

*p接收num的地址

**p接收指针p的地址

//指针的指针;
void test03() {
    int num = 10;
    int* p = #
    int** q = &p;
    cout << "p的值:" << p << endl;;
    cout << "*p的值:" << *p << endl;
    cout << "q的值:" << q << endl;
    cout << "*q的值:" << *q << endl;
    cout << "**q的值:" << **q << endl;

}

4 数组地址和首元素地址

区分: 数组首元素地址 和 数组首地址
数组首元素地址:数组第一个元素的地址 &arr[0]==arr arr+1跳过的是第一个元素
数组首地址: 数组的地址 &arr &arr+1跳过整个数组
这两个数值上一样,但是意义不同

//数组地址和首元素地址;
void test04() {
    
    int arr[5] = { 12,34,56,78,91 };
    cout << "数组首元素地址:arr = " << arr << endl;
    cout << "跳过第一个元素:arr + 1 = " << arr + 1 << endl;
    cout << "数组首地址:&arr = " << &arr << endl;
    cout << "跳过整个数组 &arr + 1 = "<< &arr + 1 << endl;
}

5 数组指针

本质是:指针变量保存的是 数组的首地址

这里注意区分指针数组和数组指针
指针数组 int* p[5]
数组指针 int(* p)[5]

注意:对数组首地址取 * ==数组首元素地址

//数组指针;
void test05() {
    //本质是:指针变量保存的是 数组的首地址
    int arr[5] = { 10,20,30,40,50 };
    int(*p)[5] = NULL;//声明数组指针,小括号不可以去掉
    
    cout << "sizeof(p)=" << sizeof(p) << endl;//32位平台为4B
    cout << "p=" << p << endl;//因为初始化为空,所以大小为0
    //因为是数组指针,一个数组是5个元素,一个元素4B大小,所以一共20B,十六进制为14
    cout << "p+1=" << p + 1 << endl;

    //如何通过数组指针去访问数组元素
    
    int* q = arr;//获取首元素地址
    cout << "第二个元素为:" << *(q + 2) << endl;//q为首元素地址,q+2为第二个元素的地址,整体取 * 获取到具体的值
}

6 二维数组和数组指针

二维数组的组名代表的是第0行的行地址 +1跳过一个行
对行地址取 * 代表当前行第0列的列地址

//二维数组和数组指针;
void test06() {
    //声明二维数组
    int arr[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} };
    
    cout << "arr=" << arr << endl;//第0行首地址
    cout << "arr + 1 =" << arr+1 << endl;//第一行首地址
    cout << "*arr=" << *arr << endl;//第0列首地址
    cout << "*arr+1=" << *arr+1 << endl;//第1列首地址
    cout << "**arr=" << **arr << endl;//第0行第0列的元素值
    cout << "*(*arr+1)=" << *(*arr+1) << endl;//第0行第1列元素的值
    cout << "**arr + 1 =" << **arr +1  << endl;//第0行第0列的元素值+1

}

三、指针与函数

如果想在函数内部 修改函数外部的值 需要将外部变量的地址 传递给函数

1 整型作为函数的参数
void setnum(int* p) //int * p=&num
{
	*p = 100;/
		if (strcmp(pb->name,name)==0)
		{
			return pb;
		}
		else
		{
			return NULL;
		}
		return NULL;
	}
}
3.5 删除节点

删除节点的时候注意,要记得上一个节点,这样才能删除掉当前的节点(让上一个节点的next指向当前节点的next)

还要注意删除的时候删除的是头节点还是链表的中尾部节点

为什么中尾部和在一起

在下面的代码中pf记录上一个节点,pb是当前节点。删除尾部节点和中间节点的时候,代码都可以使用pf->next=pb->next。因为删除尾部节点的时候就是让pf的next为NULL,而pb的next恰好是NULL。所以这俩可以和在一起。

//删除节点
Stu* deleteLink(Stu* head, int num) {
	//判断链表是否存在
	if (NULL == head)
	{
		cout << "链表不存在" << endl;
		return NULL;
	}
	else
	{
		//逐个节点比较
		Stu* pf = head, * pb = head;
		while ((pb->num != num) && (pb->next != NULL)) {
			pf = pb;
			pb = pb->next;
		}
		//循环结束
		if (pb->num==num)//找到删除点
		{
			if (pb==head)//头节点删除
			{
				head = head->next;
				delete pb;
			}
			else//删除中尾部节点
			{
				pf->next = pb->next;
				delete pb;
			}
		}
		else
		{
			cout << "未找到要删除的节点" << endl;
		}
		return head;
	}
}
3.6 释放链表

释放是逐个节点进行释放,要注意pb和head的关系

//释放链表
Stu* freeLink(Stu* head) {
	
	//判断链表是否存在
	if (NULL == head)
	{
		cout << "链表不存在" << endl;
		return NULL;
	}
	else//逐个节点释放
	{
		Stu* pb = head;
		while (pb != NULL) {
			head = head->next;
			delete pb;
			pb = head;
		}
		return head;

	}
}
3.7 整体的代码
#include 
#include
using namespace std;


//定义链表节点类型
struct Stu
{
	//数据域
	int num;
	char name[32];
	//指针域
	Stu* next;
};
//构建一个链表头
Stu* head = NULL;

//帮助信息
void help() {
	cout << "********************************" << endl;
	cout << "* help:帮助信息                *" << endl;
	cout << "* insert:插入链表节点          *" << endl;
	cout << "* print:遍历链表               *" << endl;
	cout << "* search:查询链表某个节点      *" << endl;
	cout << "* delete:删除链表某个节点      *" << endl;
	cout << "* free:释放整个链表            *" << endl;
	cout << "* quit:退出程序                *" << endl;
	cout << "* cls :清空屏幕                *" << endl;
	cout << "********************************" << endl;
}

//插入函数 使用头插法
Stu* insertLink(Stu* head, Stu tmp) {
	//从堆区申请带插入的节点空间
	Stu* pi = new Stu;
	//给空间赋值
	*pi = tmp;
	pi->next = NULL;

	//判断链表是否存在
	if (NULL==head)//不存在
	{
		head = pi;
	}
	else//存在
	{
		pi->next = head;
		head = pi;
	}
	return head;
}
//插入函数 尾插法(未使用)
Stu* insertLink1(Stu* head, Stu tmp) {
	//从堆区申请带插入的节点空间
	Stu* pi = new Stu;
	//给空间赋值
	*pi = tmp;
	pi->next = NULL;

	//判断链表是否存在
	if (NULL == head)//不存在
	{
		head = pi;
	}
	else//存在
	{
		Stu* pb = head;
		//寻找尾节点
		while (pb->next!=NULL)
		{
			pb = pb->next;
		}
		//在尾节点插入pi
		pb -> next = pi;
	}
	return head;
}

//遍历链表
void printLink(Stu* head) {
	//判断链表是否存在
	if (NULL==head)
	{
		cout << "链表不存在" << endl;
		return;
	}
	else
	{
		Stu* pb = head;
		while (pb!=NULL)
		{
			cout << pb->name << " " << pb->num << endl;
			pb = pb->next;
		}
		return;
	}
}

//查询链表
Stu* searchLink(Stu* head, char* name) {
	//判断链表是否存在
	if (NULL==head)
	{
		cout << "链表不存在" << endl;
		return NULL;
	}
	else
	{
		//逐个节点查询
		Stu* pb = head;
		while ((strcmp(pb->name,name)!=0)&&(pb->next!=NULL))//判断pb的名字和要查询的名字不一致且还有下一个节点的时候,循环继续
		{
			pb = pb->next;

		}
		
		if (strcmp(pb->name,name)==0)
		{
			return pb;
		}
		else
		{
			return NULL;
		}
		return NULL;
	}
}


//删除节点
Stu* deleteLink(Stu* head, int num) {
	//判断链表是否存在
	if (NULL == head)
	{
		cout << "链表不存在" << endl;
		return NULL;
	}
	else
	{
		//逐个节点比较
		Stu* pf = head, * pb = head;
		while ((pb->num != num) && (pb->next != NULL)) {
			pf = pb;
			pb = pb->next;
		}
		//循环结束
		if (pb->num==num)//找到删除点
		{
			if (pb==head)//头节点删除
			{
				head = head->next;
				delete pb;
			}
			else//删除中尾部节点
			{
				pf->next = pb->next;
				delete pb;
			}
		}
		else
		{
			cout << "未找到要删除的节点" << endl;
		}
		return head;
	}
}

//释放链表
Stu* freeLink(Stu* head) {
	
	//判断链表是否存在
	if (NULL == head)
	{
		cout << "链表不存在" << endl;
		return NULL;
	}
	else//逐个节点释放
	{
		Stu* pb = head;
		while (pb != NULL) {
			head = head->next;
			delete pb;
			pb = head;
		}
		return head;

	}
}


int main()
{
	help();
	//在while循环里执行操作
	while (1)
	{
		char cmd[64] = "";
		cout << "请输入操作指令:";
		cin >> cmd;
		if (strcmp(cmd, "help") == 0)
		{
			help();
		}
		else if (strcmp(cmd, "insert") == 0)
		{
			cout << "请输入要插入的节点信息(num name):" << endl;
			Stu tmp;
			cin >> tmp.num >> tmp.name;
			head = insertLink(head, tmp);
		}
		else if (strcmp(cmd, "search") == 0)
		{
			cout << "请输入要查询的姓名:" << endl;
			char name[32] = "";
			cin >> name;
			Stu* ret = NULL;
			ret = searchLink(head, name);
			if (ret!=NULL)
			{
				cout << "查询的结果: num= " << ret->num << " name= " << ret->name << endl;
			}
			else
			{
				cout << "查无此人" << endl;
			}
		}
		else if (strcmp(cmd, "print") == 0)
		{
			printLink(head);
		}
		else if (strcmp(cmd, "delete") == 0)
		{
			cout << "请输入要删除的学号:" << endl;
			int num = 0;
			cin >> num;
			head = deleteLink(head, num);//如果删除的是头节点,头节点就需要更新,所以拿头节点接一下
		}
		else if (strcmp(cmd, "free") == 0)
		{
			head = freeLink(head);
			cout << "释放完成" << endl;
		}
		else if (strcmp(cmd, "quit") == 0)
		{
			return 0;
		}
		else if (strcmp(cmd, "cls") == 0)
		{
			system("cls");
		}
		else
		{
			cout << "请输入正确的指令" << endl;
		}
	}
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1010191.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号