Back home
中文
H7 / SECURITY RESEARCH NOTES

Chapter 10: Arrays and Pointers

  • An array name is the address of the array's first element. If demo is an array, then demo == &demo[0] holds true

  • %p is the conversion specification for displaying a pointer in hexadecimal

  • %zd is the conversion specification for the return value of sizeof (that is, the size_t type), measured in bytes.

  • In the c language, the two expressions ar[i] and *(ar + i) are equivalent, but there is one point: only when ar is a pointer variable can an expression such as ar++ be used.

  • The difference between addresses can use the conversion specification %td

Pointer Operations

1.赋值:把地址赋给指针
- 数组名赋值
- 带地址运算符&的变量名赋值
- 另一个指针赋值
2.解引用:*运算符给出指针指向地址上的值
3.取址:&运算符给出变量本身的地址
4.指针与整数相加:可以使用 + 把指针与整数相加,或者整数与指针相加。
- 计算结果 = 整数 × 指针所指向类型的大小(以字节为单位)+ 初始地址
5.递增指针:递增指向数组元素的指针可以让该指针指向数组的下一个元素。
6.指针减去一个整数:可以用 - 从指针减去一个整数,这里指针必须在被减数的位置。
- 计算结果 = 初始地址 - 整数 × 指针所指向类型的大小(以字节为单位)
7.递减指针:递减指向数组元素的指针可以让该指针指向数组的上一个元素。
8.指针求差:可以计算两个指针之间的差值。差值的单位与数组类型的单位相同,例如 int 类型的数组中两个相邻的值的指针相减,那么得出的值为 1,即 1 个int。
9.比较:可以用关系运算符比较两个指针的值,前提是两个指针指向相同类型的对象。

The const Keyword

# 以下为2021.10.28日的笔记
作用:用于限制一个变量为只读变量。

- 编写一个处理基本类型的函数时,对于数组来说,必须传递指针,这样效率高,但是会面临一个问题就是关于修改数组的问题。解决办法是通过使用指向const的指针,表明该函数不会通过指针来修改数据,如下:
int sum(const int ar[], int n); /* 函数原型 */
int sum(const int ar[], int n) /* 函数定义 */
{
	int total = 0;
	...
	return total
}

- const可以创建const数组、const指针、指向const的指针。
# 说说const指针和指向const的指针
const double locked[4] = {1, 2, 3, 4}
const double * pc = rates; /* 指向const的指针 */
double * const pc = rates; /* const指针 */
const double * const pc = rates; 
- 规律总结:
1.*左边有const意味着是指向const的指针,特点是不能使用指针来更改它所指向的值。
2.*右边有const意味着是const指针,特点是指针本身的值是不可变的。即指针指向的地址是一个固定值,那就不能改变指针所指向的地址。
3.如果const用了两次,则不能使用指针改变指向的值且指针指向的地址也不能变。
4.指向const的指针可以指向const数据和非const数据,但是普通指针不能指向const数据(不然就能通过指针操作const数据了)

# 用途:
- 指向const的指针通常用于函数形参中,表明该函数不会使用指针改变数据。

Pointers and Multidimensional Arrays

I feel completely lost reading the book, but I must understand this! There are more impatient people in the world, so stay patient and I will definitely figure it out!

int zippo[4][2]; /*内含int数组的数组*/

// zippo是数组首元素的地址,即zippo == &zippo[0];
// 而zippo[0]是一个内含两个int对象的数组,所以zippo[0] == &zippo[0][0];
// 所以zippo是一个指向占用两个int大小对象的指针,而zippo[0]是一个指向占用1个int大小对象的指针
// 但是由于zippo和zippo[0]开始于同一个地址,所以zippo == zippo[0]

// 解引用一个指针(即在指针前使用 * 运算符),得到指针所指向的地址上的值。因为zippo[0]是数组首元素zippo[0][0]的地址,所以*(zippo[0]) = zippo[0][0].
// *zippo = zippo[0],因为zippo[0] == &zippo[0][0],所以*zippo = &zippo[0][0]
// **zippo = zippo[0][0]
  • For int zippo[4][2], the relationships are summarized below:
# 几类符号:
1.zippo
2.zippo[0]
3.&zippo[0]
4.zippo[0][0]
5.&zippo[0][0]
6.*zippo
7.**zippo

(1) zippo数组名代表二维数组首元素的地址,所以推导出 zippo == &zippo[0],所以 *zippo = zippo[0]

(2) 二维数组首元素是一个包含两个int对象的一维数组,所以zippo[0]相当于一维数组数组名,那么针对一维数组数组名来说,数组名相当于首元素的地址,所以推导出 zippo[0] == &zippo[0][0], 所以 *zippo[0] = zippo[0][0]

结合(1)和(2),可以推导出 **zippo = zippo[0][0]

先背下来吧,zippo == zippo[0] == &zippo[0][0]

- 注意:zippo + 1 得到的值和 zippo[0] + 1 得到的值是不同的,因为zippo是指向一维数组对象的指针,而 zippo[0] 是指向一维数组的单个对象的指针。两个对象占用的内存空间大小不同。

Pointers to Multidimensional Arrays

// pz 指向一个内含两个int类型值的数组
int (* pz)[2]; // 括号的原因是[]的优先级高于*

// 下面是声明一个指针数组
int * pz[2] // 表示该数组含两个指向int类型值的指针

Functions and Multidimensional Arrays

# 用到时再说

Variable-Length Arrays

变长数组指在创建数组的时候,可以使用变量指定数组的维度。
# 声明带二维变长数组参数的函数如下:
int sum2d(int rows, int cols, int ar[rows][cols]); # 注意:rows和cols的声明要在ar[rows][cols]之前,因为ar[rows][cols]用到了它。
# 但是,该程序要求编译器支持变长数组这个特性