完成任务的第10步,如果需要20个数据,如何自动化整个过程?

如果按步骤输入命令和数据,整个过程不能与手动操作分开。

如果将这10个步骤编辑成指令,指令和数据按一定的编码规则存储起来,由一个部件逐步取指令并解释成电信号,然后由另一个部件去执行,并可将中间结果也存储起来,循环这个过程,便可实现自动化。

这就是冯诺依曼的存储程序控制概念,这样的计算机称为冯诺依曼机,也就是今天绝大多数计算的理论模型。

存储指令和数据的部件称为存储器,可通过地址随机访问,属于线性结构。不管是电存储(记忆电路或电容)还是磁存储,都是用两个状态的二进制来表示。内存属于使用电容的电存储,8个位构成一个字节,每个字节线性编址。

数据“要存得进去,取得起来”,要取值离不开其地址, 地址之间虽然有可以利用的线性关系,但要显示使用地址来存取数据还是显得很不方便,于是高级语言使用了标识符的概念,用变量名来隐式表示内存单元的地址,通过变量名直接取数据值。虽然如此,变量名做为左值和右值还是稍有不变,右值纯粹指内存单元内01串代表的数据值,而右值则是可寻址的非只读表达式,表示可修改的对象,当再次出现在表达式的右边时,还是表示数据值。

我们知道,在内存中,知道了一块内存的首地址及其编码规则,便可以按变量类型的长度进行解码,依次访问对应的相邻单元的值,数组如此、结构体、类也是如此。要利用地址的这种线性关系,变量名更多的是直接取数据值,如果利用以下运算符来操作,则显得繁琐,且相邻单元的值无法通过地址来访问:

int n=22;
int m=33;
*&n*=2;
*(&n+sizeof(int))*=2;
cout<<n<<" "<<m; //44 33

如何显式获得其地址,隐式得到其数据值?这便是指针变量,指针就是地址,指针变量就是用来存储内存单元地址的变量。

指针变量做为左值,表示修改一个地址,指向一个新的内存单元,也可以理解为指针的移动。理解指针,关键在于理解指针的用做左值时被修改,得到一个新的地址值,这样就形成了指针的移动。

1 数组中指针的移动

int arr[]={1,2,3,4,5};
for(int i=0;i<5;++i)
cout<<" "<<arr[i];
for(int j=0;j<5;++j)
cout<<" "<<*(arr+j);

数组名是基地址,下标相当于基地址的偏移,得到不同的变量地址。

如字符中数组中指针的移动:

char dst[] = "abcdef";
char* src = "ghi";
char* ch=dst;
while(*ch++=*src++);
cout<<dst; //ghi

2 链表中指针的移动

与数组元素可以随机访问(下标可以做算术运算)不同,链表结点只能顺序访问(相邻节点逐个访问),通过指针移动实现。

理解链表的关键在于理解节点的链接、切断、指针移动,都是通过指针(节点的指针域)赋值实现的,指针赋值表达式的左值可以理解为左值的重新指向。或者说,左值与右值完成了相同指向。

如以下表示如何插入一个节点:

以下表示如何删除一个结点:

链表结点遍历:

链表中常见的指针操作:

(指针做左值时的赋值符号可以理解为左值指向)

3 STL中迭代器也是一种特殊的指针容器

int arr[] = {10,20,30,40,50};
vector<int> vec(arr,arr+5);
vector<int>::iterator it;
for (it = vec.begin(); it!=vec.end(); ++it)
cout << ' ' << *it;
//10 20 30 40 50

4 文件指针的移动

FILE *stream;
stream = fopen("MYFILE.TXT", "a+");
fprintf(stream, "This is a test");//读写文件时,编译器隐式实现了文件指针的移动
printf("The file pointer is at byte
%ldn", ftell(stream));//ftell()可以返回文件指针的位置
fseek(stream,3,SEEK_SET); //fseek()可以让程序员设置文件指针的位置
char ch = fgetc(stream);//返回文件中的第4个字符,s
printf("%c",ch);
fclose(stream);

-End-

相关推荐