精华内容
下载资源
问答
  • 直接寻址、间接寻址、立即寻址

    万次阅读 多人点赞 2018-06-01 11:38:56
    一、前言 直接寻址、间接寻址、立即寻址,只是CPU在通过总线与内存交互时的不同交互方法,而产生的三种概念词!对于这些寻址方式,很多人没有听说过,但是对于学习汇编的同学来说,非常熟悉,很书中都有提到过这几...

    一、前言

        直接寻址、间接寻址、立即寻址,只是CPU在通过总线与内存交互时的不同交互方法,而产生的三种概念词!

    对于这些寻址方式,很多人没有听说过,但是对于学习汇编的同学来说,非常熟悉,很多书中都有提到过这几种寻址方式,但是没有细说,这里来给大家详细介绍一下这三种寻址方式的不同体现在哪里!

    二、直接寻址

        直接寻址即直接给出内存单元的物理地址/虚拟地址直接寻址!

    详细说一下:

    假如有一个内存,且大小是:0x00000000~0xFFFFFFFF

    每个物理地址代表一个内存单元(这里抛开虚拟内存管理机制),那么我想要取得0x00000001地址里的数据,首先CPU需要通过地址总线找到该内存单元,然后通过控制总线确定操作方法,在通过数据总线将其数据送回来,便于处理!

    那么我们要怎样将地址给CPU呢?

    答:

    放到CS段地址寄存器中,CS寄存器负责保存段地址,CPU会根据此段地址,去内存中将指令读取到CS:IP寄存器当中,然后执行!

    假如我想要将0x00000001地址里的数据取出来,放到AX寄存器当中,那么需要在内存中写好指定代码:

    MOVE AX,[DS:0x00000001H]

    MOVE AX,[0x00000001H]

    (AX内存=DS+0x00000001H)

     

    DS是段寄存器,这里无需多说,详细介绍可以看这篇文章:C语言内存模型详细介绍_堆栈介绍

     

    操作系统会自动帮我们把CS:IR寄存器指向我们的代码段,当CPU将指令取到CS:IP寄存器以后,就会通过CU控制单元译码解析指令转换成对应的电平信号,驱动CPU晶体管工作!

    CPU会直接将段地址+0x00000001的物理地址通过北桥,传送给内存芯片,内存芯片会把该地址里的数据取回来传递给CPU,当CPU接受到返回来的数据时,会把该数据写入到AX寄存器,这样一个指令就执行完成了,实际上并不是一个指令,其实CPU要分好几次时钟周期来执行,第一次去将DS寄存器里的段首地址读取出来,第二次加上0x00000001,第三次去内存中取数据,第四次将获取到的数据写入到AX中,即四个个时钟周期来完成一个指令,其中还会用到alu运算单元来进行段地址+偏移地址的运算,所以实际上可能需要多个时钟周期来完成!

    CPU是由晶体管来驱动的,每次开关驱动一次都称为一次时钟周期,时间周长不算,一般用赫兹来表示时钟周期的单位!

    上面的过程仅一步到位非常之快,因为我们直接给出了实际物理地址!

    下面来说说间接寻址

    三、间接寻址

    间接寻址是建立在直接寻址之上的一种概念,地址不是直接寻址那样直接给出,而是通过某个特定的内存单元得出,第一次是得到某个特定内存单元里的地址数据,第二次在将得出的地址进行DS+偏移地址H的运算直接寻址!

    这样说可能有点含糊不清,不过来看一下这段汇编代码,你就应该能明白直接寻址与间接寻址之间的区别了:

    MOV esp,0x00000001
    MOV AX,[esp]

    esp、eax等寄存器均为8086寻址寄存器,用于暂时存放地址的,并且寻址时也是以DS+esp的方式!

    其实esp和eax等e开头的寄存器和AX,BX,CX通用寄存器的作用没有区别,只是CPU设计者,设计出这么多寄存器是为了方便区分,某些寄存器做某些事情,这样更加方便于统一和区分,你也可以使用BX来进行间接寻址,只要你在里面写上[],这个括号在汇编里表示寻址括号,如果你把bx用[]括起来,CPU会把BX里的内容当做地址看待!

    这样的话,CPU要做的工作可就很多了,首先要将0x00000001地址送入到esp里,在将esp里的地址取出来,然后通过DS+esp在去内存中寻址,在取回来放到AX中!

    所以间接寻址说的明白一点,就是通过寄存器得到要寻址的地址,然后在寻址,而非直接给出地址直接寻址!

     

    上面有个疑惑,就是直接寻址的地址是怎么来的?

    答:在内存中取出指令存入到IP寄存器时,这个地址就已经存放进去了,在IP寄存器的低位,直接寻址的地址是存放在指令中的,而不需要二次获取!

     

    其如果使用间接寻址,在8085系列的CPU设计出了R0,R1的寄存器,并且如果间接寻址使用@符号表示

    mov R0,0x00000001
    mov ax,@R0

    用于表示间接寻址,不过这种寻址方式更加少见了,因为自8086系列CPU出现以后,[]指令的出现,更加方便于寻址,并且直观性更强,但是还是可以使用上面这种方法寻址的,因为向前兼容(即新的东西兼容老的东西),只是不同架构的CPU编写方法不同,但意思都是一个样!

     

    三、立即寻址

     

    通过上面的了解,立即寻址就非常简单了,即立即数寻址!

    立即数即指令的一部分,平常我们所看到的编程语言当中:

    int a = 5;

    这样我们在栈中保存了一个数据5,但是它是有空间的,在汇编中对它寻址是这样的:

    比如a在栈中的偏移地址是0x135h

    mov ax,[135h]

    CPU会到135h的内存中根据位宽寻址,将值寻回来以后,放入到ax寄存器当中!

     

    立即数不同,立即数是不占任何空间的,它存在于代码段,是指令的一部分:

     

    mov ax,135H

    ax内容=135

    当这个指令执行完成之后内存被释放掉之后,我们下次想要找到这个内存空间是找不到的!

    立即寻址要快于其它寻址,因为它无需进行寻址!

     

    展开全文
  • 直接寻址、间接寻址、立即寻址,只是CPU在通过总线与内存交互时的不同交互方法,而产生的三种概念词! 对于这些寻址方式,很多人没有听说过,但是对于学习汇编的同学来说,非常熟悉,很书中都有提到过这几种寻址...

    一、前言

        直接寻址、间接寻址、立即寻址,只是CPU在通过总线与内存交互时的不同交互方法,而产生的三种概念词!

    对于这些寻址方式,很多人没有听说过,但是对于学习汇编的同学来说,非常熟悉,很多书中都有提到过这几种寻址方式,但是没有细说,这里来给大家详细介绍一下这三种寻址方式的不同体现在哪里!

    二、直接寻址

        直接寻址即直接给出内存单元的物理地址/虚拟地址直接寻址!

    详细说一下:

    假如有一个内存,且大小是:0x00000000~0xFFFFFFFF

    每个物理地址代表一个内存单元(这里抛开虚拟内存管理机制),那么我想要取得0x00000001地址里的数据,首先CPU需要通过地址总线找到该内存单元,然后通过控制总线确定操作方法,在通过数据总线将其数据送回来,便于处理!

    那么我们要怎样将地址给CPU呢?

    答:

    放到CS段地址寄存器中,CS寄存器负责保存段地址,CPU会根据此段地址,去内存中将指令读取到CS:IP寄存器当中,然后执行!

    假如我想要将0x00000001地址里的数据取出来,放到AX寄存器当中,那么需要在内存中写好指定代码:

    MOVE AX,[DS:0x00000001H]

    MOVE AX,[0x00000001H]
    (AX内存=DS+0x00000001H)
    DS是段寄存器

    操作系统会自动帮我们把CS:IR寄存器指向我们的代码段,当CPU将指令取到CS:IP寄存器以后,就会通过CU控制单元译码解析指令转换成对应的电平信号,驱动CPU晶体管工作!

    CPU会直接将段地址+0x00000001的物理地址通过北桥,传送给内存芯片,内存芯片会把该地址里的数据取回来传递给CPU,当CPU接受到返回来的数据时,会把该数据写入到AX寄存器,这样一个指令就执行完成了,实际上并不是一个指令,其实CPU要分好几次时钟周期来执行,第一次去将DS寄存器里的段首地址读取出来,第二次加上0x00000001,第三次去内存中取数据,第四次将获取到的数据写入到AX中,即四个个时钟周期来完成一个指令,其中还会用到alu运算单元来进行段地址+偏移地址的运算,所以实际上可能需要多个时钟周期来完成!

    CPU是由晶体管来驱动的,每次开关驱动一次都称为一次时钟周期,时间周长不算,一般用赫兹来表示时钟周期的单位!

    上面的过程仅一步到位非常之快,因为我们直接给出了实际物理地址!

    下面来说说间接寻址

    三、间接寻址

    间接寻址是建立在直接寻址之上的一种概念,地址不是直接寻址那样直接给出,而是通过某个特定的内存单元得出,第一次是得到某个特定内存单元里的地址数据,第二次在将得出的地址进行DS+偏移地址H的运算直接寻址!

    这样说可能有点含糊不清,不过来看一下这段汇编代码,你就应该能明白直接寻址与间接寻址之间的区别了:

    MOV esp,0x00000001
    MOV AX,[esp]
    esp、eax等寄存器均为8086寻址寄存器,用于暂时存放地址的,并且寻址时也是以DS+esp的方式!

    其实esp和eax等e开头的寄存器和AX,BX,CX通用寄存器的作用没有区别,只是CPU设计者,设计出这么多寄存器是为了方便区分,某些寄存器做某些事情,这样更加方便于统一和区分,你也可以使用BX来进行间接寻址,只要你在里面写上[],这个括号在汇编里表示寻址括号,如果你把bx用[]括起来,CPU会把BX里的内容当做地址看待!

    这样的话,CPU要做的工作可就很多了,首先要将0x00000001地址送入到esp里,在将esp里的地址取出来,然后通过DS+esp在去内存中寻址,在取回来放到AX中!

    所以间接寻址说的明白一点,就是通过寄存器得到要寻址的地址,然后在寻址,而非直接给出地址直接寻址!

    上面有个疑惑,就是直接寻址的地址是怎么来的?

    答:在内存中取出指令存入到IP寄存器时,这个地址就已经存放进去了,在IP寄存器的低位,直接寻址的地址是存放在指令中的,而不需要二次获取!

    其如果使用间接寻址,在8085系列的CPU设计出了R0,R1的寄存器,并且如果间接寻址使用@符号表示

    mov R0,0x00000001
    mov ax,@R0
    用于表示间接寻址,不过这种寻址方式更加少见了,因为自8086系列CPU出现以后,[]指令的出现,更加方便于寻址,并且直观性更强,但是还是可以使用上面这种方法寻址的,因为向前兼容(即新的东西兼容老的东西),只是不同架构的CPU编写方法不同,但意思都是一个样!
    三、立即寻址

    通过上面的了解,立即寻址就非常简单了,即立即数寻址!

    立即数即指令的一部分,平常我们所看到的编程语言当中:

    int a = 5;
    这样我们在栈中保存了一个数据5,但是它是有空间的,在汇编中对它寻址是这样的:

    比如a在栈中的偏移地址是0x135h

    mov ax,[135h]
    CPU会到135h的内存中根据位宽寻址,将值寻回来以后,放入到ax寄存器当中!
    立即数不同,立即数是不占任何空间的,它存在于代码段,是指令的一部分:

    mov ax,135H
    ax内容=135

    当这个指令执行完成之后内存被释放掉之后,我们下次想要找到这个内存空间是找不到的!

    立即寻址要快于其它寻址,因为它无需进行寻址!

    展开全文
  • 1.间接寻址方式顺序表的书写。 2.循环移动k位的算法。 3.约瑟夫问题的求解函数。

    代码开始前的闲谈

        1.本章在基础的顺序表功能上增加了 循环移动k位的函数、约瑟夫问题的求解函数,合并两个顺序表的函数。
        2 .如果线性表 首先重载了 cout<<,线性表的元素也重载了cout<<。.cout <<多次重载 可以用 static 或者 inline 来限制文件作用域  就不会 报重复定义的错了。

    包括的主要知识点

        1.间接寻址方式顺序表的书写。
        2.循环移动k位的算法。
        3.约瑟夫问题的求解函数。

    运行结构截图


    头文件

    #pragma once
    #define MaxSize 100
    #include<ostream>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    
    template<class T>
    class LinearList;
    
    template<class T>
    ostream& operator<<(ostream & os, LinearList<T> & a);
    
    template<typename T>
    void PrintList2(LinearList<T> & a);
    
    typedef struct student
    {
    	int ID;
    	char name[40];
    	friend ostream & operator<<(ostream & out, struct student & data)
    	{
    		out << "student ID:";
    		out << data.ID;
    		out << " name:";
    		out << data.name;
    		out << endl;
    		return out;
    	}
    }student;
    
    template<class T>
    class LinearList
    {
    public:
    	LinearList();//无参数构造函数。
    	LinearList(int maxSize);
    	LinearList(T a[], int n);//n个数据的 构造函数。
    	LinearList(const LinearList& a);//深拷贝构造函数
    	~LinearList();//析构函数。
    
    private:
    	T **Data;//
    	int Length;//总容量。
    	int Size;//当前容量。
    public:
    	int GetLength();//获取线性表储存数据的个数。
    	int GetSize();//获取顺序表总分配空间。
    	T GetPos(int pos);//返回线性表的 第 pos 个数据。
    	void InsertObjInPos(T Obj, int pos);//在第 pos 个位置 插入Obj
    	T DeletePos(int pos);//删除第 pos 个位置的数据。
    	int Locate(T Obj);//查找 数据Obj 的位置。没有则返回 -1。
    	void PrintList1();
    	friend ostream& operator<< <>(ostream & os, LinearList<T>& a);//重载输出线性表
    	friend void PrintList2<>(LinearList<T> & a);//友元函数输出顺序表。
    	T SetPosToObj(int pos, T Obj);//把第 pos 个位置的数据改成 Obj
    	T *ToFirstAdd();//返回线性表首地址
    	void SetLength(int len);//设置线性表长度。
    	void RevListSeg(int form, int to);//从 form 到 to 位 倒置。 
    	void LeftRotate(int k);//数据循环左移 k 位。
    	void Josephus(int m);//报数到 m 的人出圈。
    	LinearList<T> & operator =(const LinearList<T> & a);//深拷贝。
    };
    
    template<typename T>
    ostream& operator<<(ostream & os, LinearList<T> & a)
    {
    	for (int i = 0; i < a.Length; i++)
    	{
    		os << *(a.Data[i]) << " ";
    	}
    	os << '\n';
    	return os;
    }
    
    template<typename T>
    void PrintList2(LinearList<T> & a)
    {
    	for (int i = 0; i < a.Length; i++)
    	{
    		std::cout << *(a.Data[i]) << " ";
    	}
    	std::cout << '\n';
    }

    源文件

    #include "stdafx.h"
    #include "LinearList.h"
    
    template<typename T>
    LinearList<T>::LinearList()
    {
    	Length = 0;
    	Size = 5;
    	Data = new T*[5];
    }
    
    template<class T>
    LinearList<T>::LinearList(int maxSize)
    {
    	Length = 0;
    	Size = 10;
    	Data = new T*[maxSize];
    }
    
    template<typename T>
    LinearList<T>::LinearList(T a[], int n)
    {
    	this->Length = n;
    	this->Size = n;
    	this->Data = new T*[n];
    	if (this->Data == nullptr)
    	{
    		throw "LinearList (T a[] , int n) trapped!\n";
    	}
    
    	for (int i = 0; i < n; i++)
    	{
    		this->Data[i] = new T;
    		*(this->Data[i]) = a[i];
    	}
    }
    
    template<typename T>
    LinearList<T>::LinearList(const LinearList & a)
    {
    	this->Length=a.Length;
    	this->Size=a.Size;
    	this->Data = new T*[a.Size];
    	for (int i = 0; i < this->Length; i++)
    	{
    		this->Data[i] = new T;
    		*(this->Data[i])=*(a.Data[i]);
    	}
    }
    
    template<typename T>
    LinearList<T>::~LinearList()
    {
    	for (int i = 0; i < Length; i++)
    	{
    		delete [] (this->Data[i]);
    	}
    	delete [] this->Data;
    	Length = 0;
    }
    
    template<typename T>
    int LinearList<T>::GetLength()
    {
    	return this->Length;
    }
    
    template<class T>
    int LinearList<T>::GetSize()
    {
    	return Size;
    }
    
    template<typename T>
    T LinearList<T>::GetPos(int pos)
    {
    	return *(this->Data[pos]);
    }
    
    template<typename T>
    void LinearList<T>::InsertObjInPos(T Obj, int pos)
    {
    	if (pos > Length + 1 || pos<1)
    	{
    		throw "InsertObjInPos error! And mostly the position is too long or too short";
    		return;
    	}
    	this->Length++;
    	if(Length > Size)
    	{
    		Size += 10;
    		this->Data = (T **)realloc(this->Data, Size * sizeof(T));
    		if (this->Data == nullptr)
    		{
    			//throw exception();
    			throw "InsertObjInPos error! And mostly wrong in realloc";
    		}
    	}
    	T * temp=this->Data[Length - 1] = new T;
    	*temp = Obj;
    	for (int i = Length - 1; i >= pos; i--)
    	{
    		this->Data[i] = this->Data[i - 1];
    	}
    	this->Data[pos - 1] = temp;
    }
    
    template<typename T>
    T LinearList<T>::DeletePos(int pos)
    {
    	if (pos<1 || pos>this->Length)
    	{
    		throw "DeletePos error and mostly the position is wrong";
    	}
    	T temp = *(this->Data[pos - 1]);
    	T *p = this->Data[pos - 1];
    	for (int i = pos - 1; i < Length - 1; i++)
    	{
    		this->Data[i] = this->Data[i + 1];
    	}
    	delete p;
    	this->Data[Length - 1] = nullptr;
    	Length--;
    	return temp;
    }
    
    template<typename T>
    int LinearList<T>::Locate(T Obj)
    {
    	int pos = -1;
    	for (int i = 0; i < Length; i++)
    	{
    		if (*(this->Data[i]) == Obj)
    		{
    			//return i+1;
    			pos = i + 1;
    			return pos;
    		}
    	}
    	return pos;
    }
    
    template<typename T>
    void LinearList<T>::PrintList1()
    {
    	for (int i = 0; i < this->Length; i++)
    	{
    		std::cout << *(this->Data[i]) << ' ';
    	}
    	std::cout << endl;
    }
    
    template<typename T>
    T LinearList<T>::SetPosToObj(int pos, T Obj)
    {
    	if (pos<1 || pos>this - Length + 1)
    	{
    		throw "DeletePos error and mostly the position is wrong";
    	}
    	if (pos == Length + 1)
    	{
    		Length++;
    		this->Data[Length - 1] = new T;
    		*(this->Data[pos - 1]) = Obj;
    	}
    	*(this->Data[pos - 1]) = Obj;
    	return T();
    }
    
    template<typename T>
    T * LinearList<T>::ToFirstAdd()
    {
    	return this->Data[0];
    }
    
    template<typename T>
    void LinearList<T>::SetLength(int len)
    {
    	this->Length = len;
    }
    
    template<typename T>
    void LinearList<T>::RevListSeg(int form, int to)
    {
    	if (form < 1 || form>Length || to<1 || to>Length)
    	{
    		throw "RevListSeg() error!";
    	}
    	T *temp;
    	for (int i = 0; i <= (to - form) / 2; i++)
    	{
    		temp = Data[form - 1 + i];
    		Data[form - 1 + i] = Data[to - 1 - i];
    		Data[to - 1 - i] = temp;
    	}
    }
    
    template<class T>
    void LinearList<T>::LeftRotate(int k)
    {
    	RevListSeg(1, k);
    	RevListSeg(k + 1, Length);
    	RevListSeg(1, Length);
    }
    
    template<class T>
    void LinearList<T>::Josephus(int m)
    {
    	int s = 0;//出圈的位置。
    	for (int n = Length; n >= 2; n--)
    	{
    		s = (s + m-1) % n;
    		cout << "After delete " << *Data[s]<<": ";
    		DeletePos(s+1);
    		cout << *this;
    	}
    	cout << "delete position " << m << " the result is " << *this;
    }
    
    template<typename T>
    LinearList<T> & LinearList<T>::operator=(const LinearList<T> & a)
    {
    	if (this->Length != 0)
    	{
    		for (int i = 0; i < Length; i++)
    		{
    			delete[] this->Data[i];
    		}
    		delete[] this->Data;
    	}
    	this->Length = a.Length;
    	this->Size = a.Size;
    	this->Data = new T*[a.Size];
    	for (int i = 0; i < this->Length; i++)
    	{
    		this->Data[i] = new T;
    		*(this->Data[i]) = *(a.Data[i]);
    	}
    	return *this;
    }
    

    用于测试的主函数

    // 线性表_间接寻址.cpp : 定义控制台应用程序的入口点。
    
    #include "stdafx.h"
    #include"LinearList.cpp"
    //#include"Student.h"
    #include<iostream>
    using namespace std;
    
    
    int main()
    {
    
    	int test[10] = { 2,4,6,8,10,12,14,16,18,20 };
    	LinearList<int> a(test, 10);
    
    	std::cout << "构造函数后顺序表为:" << endl;
    	a.PrintList1();//第一种方法输出。
    
    	std::cout << "在第1个位置插入99" << endl;
    	a.InsertObjInPos(99, 1);
    	PrintList2(a);//第二种方法输出。
    
    	std::cout << "在第12个位置插入88" << endl;
    	a.InsertObjInPos(88, 12);
    	cout << a;//重载输出。
    
    	std::cout << "查找 数据 3 的位置:" << a.Locate(3) << endl;
    	std::cout << "查找到数据 4 并删除后输出:";
    	a.DeletePos(a.Locate(4));
    	cout << a;//再来一个重载输出。其实重载输出还有其他的写法。我这里用了 <> 来写。下一章我会用其他的写法实现重载。
    
    	cout << "输出顺序表数组首地址元素:";
    	std::cout << a.ToFirstAdd()[0]<< endl;
    
    	cout << "倒置 2-6位后:";
    	a.RevListSeg(2, 6);
    	cout<<a;
    
    	cout << "循环左移 3 位后:";
    	a.LeftRotate(3);
    	cout << a;
    
    	cout << endl << " 另一个顺序表:";
    	int test2[10] = { 1,2,3,4,5,6,7,8,9,10 };
    	LinearList<int> b(test2, 8);
    	cout << b;
    	cout << "报数到 3 的出圈:";
    	b.Josephus(3);
    	
    	cout << "拷贝 a 表 到 c 表 :";
    	LinearList<int> c(a);
    	cout << a;
    
    	cout << "operator = 拷贝c:";
    	LinearList<int> d;
    	d = c;
    	cout << d;
    	cout << "operator = 拷贝b:";
    	d = b;
    	cout << d;
    	
    
    	cout << "元素为两个学生结构的线性表:";
    	student e[3];
    	e[0].ID=111;
    	e[1].ID=222;
    	e[2].ID=333;
    	strcpy_s(e[0].name, 40, "aaa");
    	strcpy_s(e[1].name, 40, "bbb");
    	strcpy_s(e[2].name, 40, "ccc");
    	LinearList<student> f(e, 2);
    	cout << f;
    
    	cout << "在第三个位置插入一个学生结构:"<<endl;
    	f.InsertObjInPos(e[2], 3);
    	cout << f;
    	cout << "删除第二个元素:"<<endl;
    	f.DeletePos(2);
    	cout << f;
    	getchar();
    	return 0;
    }


    展开全文
  • 数据结构实验二,间接寻址操作成绩表。

    一.实验目的
    巩固间接寻址的数据结构的存储方法和相关操作,学会针对具体应用,使用线性表的相关知识来解决具体问题。

    二. 实验内容
    建立一个由n个学生成绩的顺序表,n的大小由自己确定,每一个学生的成绩信息由自己确定,实现数据的对表进行插入、删除、查找等操作。用间接寻址来实现,分别输出结果。
    为了以后的对代码的修改、优化和复用,这里采用了C++中的模板来实现,下面是模板的实现。

    IndirectAddress.h

    #ifndef IndirectAddress_h
    #define IndirectAddress_h
    
    #include <iostream>
    using namespace std;
    
    const int MaxSize = 100;
    
    template<class DataType>
    struct Node {
        DataType data;
        Node<DataType> *next;
    };
    
    template<class DataType>
    class IndirectAddress {
    public:
        // 无参构造函数,建立只有头结点的空链表
        IndirectAddress();
        // 有参构造函数,建立有n个元素的单链表
        IndirectAddress(DataType a[], int n);
        // 析构函数
        ~IndirectAddress();
        // 求单链表长度
        int Length();
        // 按位查找
        DataType Get(int i);
        // 按值查找
        DataType Locate(DataType x);
        // 插入操作
        void Insert(int i, DataType x);
        // 删除操作
        DataType Delete(int i);
        // 遍历操作
        void PrintList();
    private:
        // 头指针
        Node<DataType> *first;
        // 节点数量
        int length = 0;
        // 节点指针数组
        Node<DataType> *address[MaxSize];
    };
    
    #endif /* IndirectAddress_h */

    IndirectAddress.cpp

    #include "IndirectAddress.h"
    
    
    template<class DataType>
    IndirectAddress<DataType>::IndirectAddress()
    {
        first = new Node<DataType>;
        first->next = NULL;
    }
    
    
    template<class DataType>
    // 尾插法
    IndirectAddress<DataType>::IndirectAddress(DataType a[], int n)
    {
        Node<DataType> *r, *s;
        first = new Node<DataType>;    // 生成头结点
        r = first;                     // 尾指针初始化
        for (int i = 0; i < n; i++)
        {
            s = new Node<DataType>;
            s -> data = a[i];          // 为每个数组元素建立一个结点
            r -> next = s;
            r = s;                     // 将结点s插入到终端结点之后
            address[i] = s;            // 将指针保存在数组中
            length++;
        }
        r -> next = NULL;              // 单链表建立完毕,将终端结点的指针域置空
    }
    
    template<class DataType>
    int IndirectAddress<DataType>::Length()
    {
        return length;
    }
    
    template<class DataType>
    DataType IndirectAddress<DataType>::Get(int i)
    {
        if (i >= length) {
            throw("位置错误");
        }
        return address[i - 1] -> data;
    }
    
    template<class DataType>
    DataType IndirectAddress<DataType>::Locate(DataType x)
    {
        Node<DataType> *p;
        p = first -> next;
        int count = 1;
        while (p != NULL)
        {
            if (p -> data == x)
            {
                return count;
            }
            p = p -> next;
            count++;
        }
        return -1;
    }
    
    template <class DataType>
    void IndirectAddress<DataType>::Insert(int i, DataType x)
    {
        // 单链表的插入
        Node<DataType> *p = first;
        for (int k = 1; k <= i - 1; k++)
        {
            p = p -> next;
        }
        Node<DataType> *tempNode ;
        tempNode = new Node<DataType>;
        tempNode -> data = x;
        tempNode -> next = p -> next;
        p -> next = tempNode;
        length++;
        // 顺序表的插入
        if (length >= MaxSize) {
            throw "溢出";
        }
    
        for (int j = length - 1; j > i - 1; j--) {
            address[j] = address[j - 1];
        }
        address[i - 1] = tempNode;
    
    }
    
    template<class DataType>
    DataType IndirectAddress<DataType>::Delete(int i)
    {
        DataType x;
        // 单链表操作
        Node<DataType> *p;
        p = first;
        for (int k = 1; k < i; k++)
        {
            p = p -> next;
        }
        Node<DataType> *tempNode;
        tempNode = new Node<DataType>;
        tempNode = p -> next;
        x = tempNode -> data;
        p -> next= tempNode -> next;
        delete tempNode;
        length--;
        // 顺序表操作
        address[i - 1] = NULL;
        for (int j = i - 1; j <= length; j++) {
            address[j] = address[j + 1];
        }
        return x;
    }
    
    template<class DataType>
    void IndirectAddress<DataType>::PrintList()
    {
        for (int i = 0; i < Length(); i++) {
            cout << address[i] -> data << " ";
        }
        cout << endl;
    }
    
    template<typename DataType>
    IndirectAddress<DataType>::~IndirectAddress()
    {
        while (first != NULL)
        {
            Node<DataType> *q = first;
            first = first->next;
            delete q;        
        }
        length = 0;
    }

    间接寻址模板借鉴了前面单链表模板和顺序表模板,将二者合在了一起。接下来就是测试模板,这里依然是用实验题目的成绩表基本操作。

    main.cpp

    #include <iostream>
    #include "IndirectAddress.cpp"
    
    int main(int argc, const char * argv[]) {
        float score[5] = {66.5, 81.5, 80, 95.5, 100};
        IndirectAddress<float> list(score, 5);
        cout << "遍历学生分数" << endl;
        list.PrintList();
        cout << "读取第三个学生的分数" << endl;
        cout << list.Get(3) << endl;
        cout << "在第二个位置插入学生分数 95" << endl;
        list.Insert(2, 95);
        list.PrintList();
        cout << "80分在分数表中的位置为: " << list.Locate(80) << endl;
        cout << "该分数表长度为: " << list.Length() << endl;
        cout << "删除第3个分数" << endl;
        list.Delete(3);
        list.PrintList();
        return 0;
    }

    运行结果如下:

    控制台输出

    三. 总结和心得
    在写了链表和顺序表的模板后,写间接寻址的模板比前面轻松了许多,主要是将两种模板的有点结合在一起。在按位查找时省力很多,但是牺牲了插入和删除这两个小功能的性能,代码也相对比较多。
    顺序表的实现这里就不重复了,在上一次实验中我写了顺序表的模板,这个实验题目只需要使用上次的模板,修改一下数据即可。用C++来实现线性表这五种方法,主要是写模板,模板写好了之后,在以后的复用中就十分方便。
    在编码的时候在适合的地方还是需要适当加点注释,时间过久了,阅读起来还是有点吃力的。毕竟现在代码并不难写,在平时敲代码时候,应该是在保证代码的阅读顺带实现一下功能,这样在以后的维护和优化中起到很好的帮助。

    简书传送门:http://www.jianshu.com/u/1bed5943be92

    展开全文
  • 运算的对象称为运算分量,然而在指令中对其操作的对象往往称为操作数。在指令的执行中最频繁地涉及的问题之一是操作数的存取。...1.直接寻址法在直接寻法中,操作数给出的是真实的单元抛址。例如,...
  • 错误 C2040 “remove”:“stu *(stu *)”与“stu *(stu *)”的间接寻址级别不同 查到了一个很让人震惊的点。 这是原楼主的问题 //用强制类型转换可以解决,但我想知道这是为什么错,第一见到这错误 #include <...
  • 线性表之间接寻址
  • 指令寻址方式

    2021-03-23 13:43:48
    这里有个问题,一次间接寻址很容易判断两次寻址后就是所要取的操作数有效地址,但是多次间接寻址后该如何判断哪次寻址得到的才是操作数有效地址? 可以在存储单元前面增加一个标志位,当标志位是1的时候表明取地址后...
  • 首先,我是一名初学者,我希望和大家一起进步、一起成长。这里,我要跟大家分享:汇编语言中巧...MOV 37H,#00HRET采用以上办法,如果要作用的不是8个、而是16个甚至更个字节单元,那程序将会很长。而以下的程序就...
  • http://blog.csdn.net/qq_34649947/article/details/72777785
  • i_block[13] 这个是间接寻址,并且采用二级间接寻址方式,即这个数值给出的是块地址,并且块内容也是一个块地址,形式如下: i_block[13]---->| ID0 | -------------------------------------------------->| | ...
  • ARM寻址方式

    2015-08-05 15:39:15
    目前ARM处理器支持9种寻址方式,分别是立即数寻址、寄存器寻址、寄存器偏移寻址、寄存器间接寻址、基址变址寻址、寄存器寻址、相对寻址、堆栈寻址和块拷贝寻址。 1. 立即数寻址 也叫立即寻址,是一种...
  • 寻址方式

    2013-04-20 22:56:51
    ARM处理器有 9 种基本寻址方式:寄存器寻址, 立即寻址,寄存器偏移寻址,寄存器间接寻址,基址寻址,寄存器寻址,堆栈寻址, 块拷贝寻址, 相对寻址。 1、寄存器寻址 操作数的值在寄存器里面,指令中地址码...
  • 寻址模式

    千次阅读 2019-12-08 12:52:24
    寻址模式(代码后补) ...特点:在执行阶段访问了一储存器,而形式地址的位数限制了指令操作数的寻址范围,地址不易修改。 隐含寻址:在指令中隐含着操作数的地址。 如单地址的指令格式,就不是明显地在地址字...
  • 寻址方式分类

    2019-09-27 04:09:20
    寄存器间接寻址;5.基址寻址; 6.寄存器寻址;7.堆栈寻址; 8.块拷贝寻址;9.相对寻址。 1,寻址方式分类——立即寻址立即寻址指令中的操作码字段后面的地址码部分即是操作数本身,也就是说,数据就包含在指令当.....
  • ARM处理器寻址方式

    2020-11-09 16:34:58
    4.寄存器间接寻址; 5.基质寻址; 6.寄存器寻址; 7.堆栈寻址; 8.相对寻址。 一:立即寻址 立即寻址指令中的操作码,字段后面的地址码部分,即是操作数本身,也就是说,数据包含在指令当中,取出指令也就取出了...
  • arm 寻址方式

    2015-03-05 18:53:40
    目前ARM处理器支持9种寻址方式,分别是立即数寻址、寄存器寻址、寄存器偏移寻址、寄存器间接寻址、基址变址寻址、寄存器寻址、相对寻址、堆栈寻址和块拷贝寻址。 1. 立即数寻址 也叫立即寻址,是一种特殊的...
  • 4.3 数据寻址

    2020-09-26 13:46:49
    4.3 数据寻址 操作数类型 1.地址(无符号数) 2.数字 定点数、浮点数、十进制数(BCD码) 3.... 4....1.数据寻址指令格式 ... 1.... 形式地址就是操作数本身,又...间接寻址 形式地址不是操作数的真正地址,而是操作数真实地址
  • ARM中的寻址方式

    2019-01-11 15:15:28
    寄存器间接寻址 基址变址寻址 寄存器寻址 块复制寻址 堆栈寻址 相对寻址 立即寻址 操作数本身就在指令中给出 寄存器寻址 利用寄存器中值作为操作数 寄存器移位寻址 第二个寄存器操作数移位后与第...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,845
精华内容 5,538
关键字:

多次间接寻址