C++ 结构体指针理解
上一篇基础链接 https://www.cnblogs.com/xuexidememeda/p/12283845.html
主要说一下链表里面双重指针
先说一下结构体
typedef struct LNode { int data; struct LNode *next; }LNode, *LinkList; typedef 把这个结构体定义一个别的名字 LNode==LNode 类型 LinkList==LNode* 类型 *LinkList 是函数指针..........这个写法我也很懵逼没法从内存角度理解 最后也有简单介绍函数指针
你不定义typedef一样直接可以用LNode 就是写的时候不方便 但是我觉得对新手易于理解
先上总代码 两个main12是测试函数 自己改着玩
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include<malloc.h> using namespace std; typedef struct LNode { int data; struct LNode *next; }LNode, *LinkList; //--------------后插法创建单链表 ------------------ void CreateList_E(LinkList &head, int n) { int i; LinkList pnew; LinkList pend;//定义最后的节点指针; //先建立头结点,数据为空; head = new LNode; head->next = NULL; pend = head;//头结点是最后的节点 ; for (i = 0; i < n; i++) { pnew = new LNode; printf("请输入第%d个节点的数据:\n",i); scanf_s("%d", &pnew->data); pnew->next = NULL; pend->next = pnew; pend = pnew; } } void CreateList_E1(LNode* &head, int n) { int i; LinkList* ptr; LinkList pnew; LinkList pend;//定义最后的节点指针; //先建立头结点,数据为空; head = new LNode; //返回的是分配空间的首地址LNode* 类型 head->next = NULL; pend = head;//头结点是最后的节点 ; for (i = 0; i < n; i++) { pnew = new LNode; printf("请输入第%d个节点的数据:\n", i); scanf_s("%d", &pnew->data); pnew->next = NULL; pend->next = pnew; pend = pnew; } } //双重指针 头结点貌似必须在外面创建?? void CreateList_E1(LNode** lnode, int n) { LinkList head = *lnode; head->next = NULL; for (int i = 0; i < n; i++) { LNode* pnew = new LNode; printf("请输入第%d个节点的数据:\n", i); scanf_s("%d", &pnew->data); pnew->next = head->next; head->next = pnew; } } //------------------打印链表---------------- void PrintList(LinkList head) { LinkList item; item = head; item = item->next;//这一步不是必须要做的,为了跳过头结点(没有数据) while (item != NULL) { printf("----%d----\n", item->data); item = item->next; } } void main1() { LNode* L = NULL; int n; printf("输入要创建的链表结点个数:\n"); scanf_s("%d", &n); CreateList_E1(L, n); printf("\n打印结果!\n"); PrintList(L); } void main2() { LNode* temp= new LNode; LNode** L= &temp; int n; printf("输入要创建的链表结点个数:\n"); scanf_s("%d", &n); CreateList_E1(L,n); printf("\n打印结果!\n"); PrintList(*L); } int _tmain(int argc, _TCHAR* argv[]) { //main1(); main2(); }
说一下创建+赋值链表函数(自己看着前面的看)
void CreateList_E(LinkList &head, int n)==void CreateList_E1(LNode* &head, int n)
LinkList 的类型其实是LNode* 类型 然后&head 是传参引用?好像是这样的(忘怎么说了) 如果你不带&符号只能在本函数打印出来赋值语句 在封装的函数是无法打印的
跟你的swap学过一个函数交换值他真实的值还是不变,多数人疑问就是我传的可是一个指针类型,他是一个地址呀!为什么还是传不过去呢 因为你的指针地址是在栈中分配空间用完就销毁呢( CreateLis函数运行结束main函数无法找到原来分配的地址) 只要头结点是在main函数中分配的那么他以后的指针在哪分配都没问题的..... 看似简单的一个问题,要 真正弄懂其实要看编译器怎么办的就是看汇编
(本人汇编基础不扎实自学的以后博客再补上!!)
唯一确定的是不加&函数call return 之后会 main函数无法得到指针的地址
void CreateList_E1(LNode** lnode, int n) 这个和CreateList_E(LinkList &head, int n) 差不多因为我们之前说过 加一个& 相当于类型后加个*
其实你完全可以想简单点你完全可以把指针类型当成类似int之类的类型 ,比如 要实现 void swap1(int a, int b)交换a b的值 我们都知道无法交换值 要交换值有两种方法 一种是void swap1(int* a, int* b) 一种是引用 所以要使用指针的指针
函数指针...............简单例子
例如:
class Test { private: int x; int y; public: Test(){ x = 1; y = 2;} void Pintf() { cout << x << " " << y << endl; } };
int _tmain(int argc, _TCHAR* argv[]) { Test a; a.Pintf(); int* b = (int*)&a; //cout << *b; cout << &a << endl; //如果直接输出a的内存的话 是0001 0002 //没法直接输出必须用指针查看值 short* c = (short*)&a; char* d = (char*)&a; cout << *d << endl; cout << *c<<endl; cout <<b; getchar(); /* 17: Test a; 00972CC8 8D 4D F0 lea ecx,[a] ecx 0x0108FCB0 this 指针 00972CCB E8 E5 E7 FF FF call Test::Test (09714B5h) 18: a.Pintf(); 00972CD0 8D 4D F0 lea ecx,[a] 00972CD3 E8 7A E6 FF FF call Test::Pintf (0971352h) 19: int* b = (int*)&a; 00972CD8 8D 45 F0 lea eax,[a] 00972CDB 89 45 E4 mov dword ptr [b],eax 20: //cout << *b; 21: cout << &a<<endl; 00972CDE 8B F4 mov esi,esp 00972CE0 68 ED 13 97 00 push 9713EDh 00972CE5 8B FC mov edi,esp 00972CE7 8D 45 F0 lea eax,[a] 00972CEA 50 push eax 00972CEB 8B 0D F8 10 98 00 mov ecx,dword ptr ds:[9810F8h] 00972CF1 FF 15 FC 10 98 00 call dword ptr ds:[9810FCh] 00972CF7 3B FC cmp edi,esp 00972CF9 E8 40 E6 FF FF call __RTC_CheckEsp (097133Eh) 00972CFE 8B C8 mov ecx,eax 00972D00 FF 15 9C 10 98 00 call dword ptr ds:[98109Ch] 00972D06 3B F4 cmp esi,esp 00972D08 E8 31 E6 FF FF call __RTC_CheckEsp (097133Eh) */ }
Test a; 这个a 到底是什么? 其实就是这个类的开头 比如这个开头存的就是0001 0002 x,y 我原来认为a存的 一直是一个地址指向 00010002这位置
假如test 类里面有虚函数 例如 virtual void Function_4() 则 Test a 中 a的首地址开头存的就是一个虚表函数 总地址例如是A (意思是 *A 是你第一个虚函数 *(A+1)是你第二个虚函数)
如果你多继承而且父类中有虚函数则比如有2个则有2个虚表