1.指针和数组的关系
▶指针指向第一个元素之前一个位置
for(vp = &values[5-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
//vp指针最后会停在&values[0]前面一个位置,即“&values[-1]”
以上代码实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
▶数组名与指针之间的等价关系
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int * p = arr;
//以下全部等价
printf("%d\n", arr[2]);
printf("%d\n", p[2]);
printf("%d\n", 2[arr]);
printf("%d\n", *(arr+2));
printf("%d\n", *(p+2));
printf("%d\n", *(2+arr));
2.一些调试实例
▶数组越界导致的死循环:
int i = 0;
int arr[10] = {0};
for(i=0; i<=12; i++)
{
arr[i] = 0;
printf("hehe\n");
}
内存分为栈区、堆区、静态区。在栈区中,变量创建从高地址向低地址依次创建,所以上述代码中,变量i处于高地址(在VS编译器中处于arr[12],即与数组间隔2),数组arr依次从低向高地址访问,越界到arr[12]会操作变量i,导致死循环。
3.关于const
const修饰变量,使其变为常变量,具有不可修改属性。下面探讨一下相关用法。
▶const修饰指针变量
int n = 10;
int m = 20;
//const放在*左边,修饰的是*p,表示指针指向的内容不能通过指针来改变,但是指针变量本身是可以修改的
const int *p = &n;
*p = 5; //err,不可修改
p = &m; //ok,可修改
//const放在*右边,修饰的是指针变量p,表示指针变量不能改变,但是指针指向的内容可以改变
int* const p = &n;
*p = 5; //ok,可修改
p = &m; //err,不可修改
当const放在*左边的时候,有没有可能“通过指针p”改变其指向的内容呢?
int n = 10;
int m = 20;
const int* p = &n;
int* p2 = p;
*p2 = 5;
printf("%d\n", n); //5
int** p3 = &p;
**p3 = 6;
printf("%d\n", n); //6
由上,在C中通过“中转指针”或二级指针,都是可以间接改变p指向的内容。
但是第5行代码会在编译时报出警告:warning C4090: “初始化”: 不同的“const”限定符
当const放在*右边的时候,同样可以间接改变p指向的内容。不同的是第8行代码会报出警告。
(题外,在C++中对const限制更为严格,无法从const变量进行取址中转)

949

被折叠的 条评论
为什么被折叠?



