指针与数组
指针:
程序中的变量实际是存储空间的别名。,通常以 *+ 变量名的形式组成。
- 变量名: 存储参数的地址。
- * :类似钥匙一样,作为打开存储内存的地址,并取出存储参数的值。
int i = 1; int *p = &i; // p---&i, *p ----1
指针变量虽然是指向变量存储的空间地址,其本质还是变量,所以依然可以对其进行取地址,这就是后面我们所学到的双指针或多层数组。
传值调用和传址调用:
函数的参数也可为指针,如果函数内部需要修改实参,则需要指针的方式将实参以参数地址的方式传入函数。
// 传值调用 int swap(int a, int b){ int c = a; a = b; b = c; } // 上述方式只是简单的将参数值传入到了函数内部,并未修改参数所在地址的参数值,如果函数内部不需要修改实参,而是将其作为运算或逻辑判断的标志,则可用上述方法。 // 传址调用 int swap(int *a, int *b){ int *c = *a; *a = *b; *a = *c; } // 上述的这种方法,是将实参的地址传入到了函数内,这种常用于对实参重新赋值
常量与指针:
前面提到的指针本质还是变量,而只要是变量就可以通过const修饰指针,将其变为常量。
const int *p; // p指向内存空间的内容不可改变,地址可变 int const *p; // p指向内存空间的内容不可改变,地址可变 int * const p; // p指向内存空间不可改变,值可以改变 const int * const p; // p指向内存空间和内容不可改变
数组:
数组是相同类型变量的有序集合,且为连续的内存空间。
如何定义数组的大小与初始化:
int a[5] = {0}; // 全部参数均为0, 数组长度为5 int a[5] = {1,2}; // 数组长度为5,数组前两个值为1,2, 其他全为0 int a[] = {1,2}; // 数组长度为2
数组名作为数组的首地址,数组的地址则通过&来获取,虽然两者的地址值相同,但是两个不同的概念。数组地址即数组的起始地址和数组长度。而数组首地址为数组第一个元素的地址以及元素的长度。
数组名可以看作常量地址,数组名不包含数组的长度信息,且只能作为右值使用。
int a[5] = {0}; // 全部参数均为0, 数组长度为5 int *p = a; sizeof(a); // 打印4*5 = 20字节 sizeof(p); // 打印4字节
指针与数组:
上面我们了解到,数组名本身是数组的首地址,所以可以看作指针。因此,数组名+1等价于指针+1(地址+类型_sizeof)<==> a+n = a + n*sizeof(type)
指针是可以实现减法,前提是两个指针必须类型相同,且指向数组中的同一元素。减法的值为数组的下标差。
int a[5] = {0}; int *p1 = &a[0]; int *p2 = &a[3]; printf("p1-p2 = %d\n", p1-p2) // 输出-3