cs107 编程范式(二)

331 阅读2分钟

指针的本质

double d = 3.1416;
char ch = *(char*)&d;

在&d操作中,会得到两部分信息,一是变量的首地址,二是指针的类型是double *(即在取值时, 会选择首地址后8bytes,作为该变量)。因此,我们可以通过修改指针的类型,对内存中的数据进行不同的解释,从而达到不同的效果。

在操作二中,我们将double *强转成了char *,因此在取值操作时,只会选择d变量首地址开始一个字节的数据作为char类型变量。接下来,我们在看一个例子。

short s = 45;
double d = *(double *)&s;

对于上述操作,变量s只占2个字节,但是因为将&s的指针类型强转为double *。因此,在取值操作时,会从s变量首地址后取8bytes解释为double类型数据。

大小端

大小端是指在内存中的字节序,大端是指将高位字节放在低地址处,小端是指将低位字节放在低地址处。举个例子。

捕获2.PNG

注:老师上课讲的一般是大端表示,笔记中则采用小端表示

结构体

struct fraction {
    int num;
    int denum;
}

fraction pi;
pi.num = 22;
pu.denum = 7;

编程范式.png

((fraction*)&(pi.denum))->num = 12;

编程范式.png

分析:&(pi.denum)的类型是int *类型,将其强制转为fraction *类型后,就会将pi.denum变量的首地址后8bytes作为fraction类型,因此在对num赋值时就会覆盖pi.denum中的数据。

后面有多个例子,大家可以自己分析一下。

((fraction *)&(pi.denum))->denum = 33;

编程范式.png

数组

int array[10];

以上式为例,数组的本质就是在内存中预留40字节的空间(即10个int类型)。而array实际上就是一个指向首元素的指针。如下图所示。

捕获.PNG

对于array[0]的操作本质上就是*(array + 0)的指针运算操作。同时,数组不会进行边界检查,诸如下列操作都是正确的。

array[0] = 44;
array[9] = 100;
array[-4] = 77;
*(array - 4) = 77;
int arr[3];
arr[3] = 128;
((short*)arr)[6] = 2;
cout << arr[3] << endl;

捕获3.PNG

输出为2

举个例子给大家分析一下

int arr[5];
((short*)((char*)(&arr[1]) + 8))[3] == ?

数组和结构体

struct student {
    char *name;
    char suid[8];
    int numUnits;
};

struct pupils[4];

捕获.PNG

pupils[3].name = pupils[0].suid + 6;
strcpy(pupils[3].name, "123456");

捕获.PNG