为什么pageNum从0开始
时间: 2023-12-06 09:03:18 浏览: 119
在计算机科学中,很多编程语言都是从0开始计数的,而不是从1开始计数。这是因为在计算机内部,数据都是以二进制的形式存储的,而二进制的最小单位是0和1。因此,从0开始计数更符合计算机内部数据的存储方式,也更容易进行数值计算和内存地址的计算。此外,从0开始计数还能避免一些常见的偏差和错误,例如数组越界等。虽然从1开始计数在某些情况下更符合人类的思维方式,但在计算机科学中,从0开始计数已经成为了一种惯例和标准。
相关问题
struct sockaddr_in sin1; struct timeval to; int i,tmp; char *pRec; HANDLE hBuffer; // Socket timeout 3 sec to.tv_sec = 3; to.tv_usec = 0; setsockopt( s, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof( to ) ); setsockopt( s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof( to ) ); for(;;) { tmp = sizeof( sin1 ); i = (int)recvncfrom( s, (void **)&pRec, 0, (PSA)&sin1, &tmp, &hBuffer ); NandPageRead(blkNum, pageNum, &pdbuf[0]); // Read NAND if( i >= 0 ) { vSum = pdbuf[2047]*128+pdbuf[2046]; i=vSum-14; // length of sent data sendto( s, pdbuf+14, i, 0, (PSA)&sin1, sizeof(sin1) ); recvncfree( hBuffer ); } else break; } 把这段代码每句解读一下
这段代码主要是一个接收和发送UDP数据包的循环,下面是每句话的解读:
1. `struct sockaddr_in sin1;` 声明了一个 `sockaddr_in` 结构体类型的变量 `sin1`,表示一个IPv4套接字地址。
2. `struct timeval to;` 声明了一个 `timeval` 结构体类型的变量 `to`,表示超时时间。
3. `int i,tmp;` 声明了两个 `int` 类型的变量 `i` 和 `tmp`,用于存储接收或发送的数据量。
4. `char *pRec;` 声明了一个 `char` 指针类型的变量 `pRec`,用于指向接收到的数据。
5. `HANDLE hBuffer;` 声明了一个 `HANDLE` 类型的变量 `hBuffer`,用于存储接收到的数据缓冲区的句柄。
6. `to.tv_sec = 3;` 设置超时时间为 3 秒。
7. `to.tv_usec = 0;` 设置微秒部分为 0。
8. `setsockopt( s, SOL_SOCKET, SO_SNDTIMEO, &to, sizeof( to ) );` 设置套接字 `s` 的发送超时时间为 `to`。
9. `setsockopt( s, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof( to ) );` 设置套接字 `s` 的接收超时时间为 `to`。
10. `for(;;)` 循环开始。
11. `tmp = sizeof( sin1 );` 设置 `tmp` 的值为 `sin1` 的大小。
12. `i = (int)recvncfrom( s, (void **)&pRec, 0, (PSA)&sin1, &tmp, &hBuffer );` 接收 `s` 套接字中的数据,并将接收到的数据存储在 `pRec` 指向的缓冲区中,返回值存储在变量 `i` 中。
13. `NandPageRead(blkNum, pageNum, &pdbuf[0]);` 从NAND中读取数据,存储在 `pdbuf` 数组中。
14. `if( i >= 0 )` 如果接收到的数据量大于等于 0。
15. `{` 循环体开始。
16. `vSum = pdbuf[2047]*128+pdbuf[2046];` 计算接收到的数据的长度。
17. `i=vSum-14;` 计算需要发送的数据的长度。
18. `sendto( s, pdbuf+14, i, 0, (PSA)&sin1, sizeof(sin1) );` 发送 `pdbuf+14` 中的数据,长度为 `i`。
19. `recvncfree( hBuffer );` 释放接收缓冲区的句柄。
20. `}` 循环体结束。
21. `else` 如果接收到的数据量小于 0。
22. `break;` 跳出循环。
给出这样一个改进型clock置换算法的c语言模拟代码:(1)从指针所指示的当前位置开始,扫描循环队列,寻找A=0且M=0的第一类页面, 将所遇到的第一个页面作为所选中的淘汰页。在第一次扫描期间不改变访问位A。(2)如果第一步失败,即查找一轮后未遇到第一类页面,则开始第二轮扫描,寻找A=0 且M=1的第二类页面,将所遇到的第一个这类页面作为淘汰页。在第二轮扫描期间,将所有扫描过的页面的访问位都置0。 (3)如果第二步也失败,亦即未找到第二类页面,则将指针返回到开始的位置,并将所有的访问位复0。然后重复第一步,即寻找A=0且M=0的第一类页面,如果仍失败,必要时再重复第二步,寻找A=0且M=1的第二类页面,此时就一定能找到被淘汰的页。
好的,以下是一个改进型clock置换算法的C语言模拟代码,实现了上述所描述的三个步骤:
```c
#include <stdio.h>
#include <stdlib.h>
#define PAGE_SIZE 4 // 每页大小
#define PAGE_NUM 16 // 总页数
#define FRAME_NUM 4 // 物理内存中的帧数
struct PageTableEntry {
int present; // 是否在内存中
int referenced; // 是否被访问过
int modified; // 是否被修改过
int frame; // 物理内存中的帧号
};
struct PageTableEntry pageTable[PAGE_NUM];
int memory[FRAME_NUM][PAGE_SIZE];
int accessCount = 0;
int hand = 0;
int main() {
// 初始化页表项
for (int i = 0; i < PAGE_NUM; i++) {
pageTable[i].present = 0;
pageTable[i].referenced = 0;
pageTable[i].modified = 0;
pageTable[i].frame = -1;
}
// 初始化物理内存
for (int i = 0; i < FRAME_NUM; i++) {
for (int j = 0; j < PAGE_SIZE; j++) {
memory[i][j] = -1;
}
}
// 模拟对页面的访问
int accessSequence[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
int accessCount = sizeof(accessSequence) / sizeof(int);
int missCount = 0;
// 依次访问每个页面
for (int i = 0; i < accessCount; i++) {
int pageNum = accessSequence[i];
if (!pageTable[pageNum].present) {
// 页面不在内存中,发生缺页中断
missCount++;
int firstRound = 1;
int secondRound = 0;
int selectedFrame = -1;
while (selectedFrame == -1) {
if (firstRound) {
// 第一轮扫描
if (!pageTable[hand].referenced && !pageTable[hand].modified) {
selectedFrame = hand;
}
pageTable[hand].referenced = 1;
} else if (secondRound) {
// 第二轮扫描
if (!pageTable[hand].referenced && pageTable[hand].modified) {
selectedFrame = hand;
}
pageTable[hand].referenced = 0;
} else {
// 回到起始位置,所有页面的访问位复位
hand = 0;
for (int j = 0; j < PAGE_NUM; j++) {
pageTable[j].referenced = 0;
}
}
// 手指向下一个帧
hand = (hand + 1) % FRAME_NUM;
if (hand == 0) {
if (firstRound) {
// 第一轮扫描结束,开始第二轮扫描
firstRound = 0;
secondRound = 1;
} else if (secondRound) {
// 第二轮扫描结束,必定能找到淘汰页
selectedFrame = hand;
}
}
}
// 将页面调入内存
for (int j = 0; j < PAGE_SIZE; j++) {
memory[selectedFrame][j] = pageNum * PAGE_SIZE + j;
}
// 更新页表项
pageTable[pageNum].present = 1;
pageTable[pageNum].referenced = 1;
pageTable[pageNum].modified = 0;
pageTable[pageNum].frame = selectedFrame;
} else {
// 页面已经在内存中,更新其引用位和修改位
int frameNum = pageTable[pageNum].frame;
pageTable[pageNum].referenced = 1;
pageTable[pageNum].modified = 1;
}
}
// 输出缺页率
float missRate = (float)missCount / accessCount;
printf("缺页率:%.2f%%\n", missRate * 100);
return 0;
}
```
该代码实现了在第一轮扫描中寻找A=0且M=0的第一类页面,在第二轮扫描中寻找A=0且M=1的第二类页面,如果两轮扫描都失败,则重新回到起始位置,并将所有页面的访问位复位。具体实现可以参考代码中的注释。
阅读全文