C指针的一些区别介绍
函数传参是从右往左进行的,例如 printf(" No.1 i = %d\n No.2 i = %d\n No.3 i = %d\n", i++, i++, i++); 输出结果可以明显看到i值从左往右是由大到小
地址指向的变量单元,指针即是该地址
- 程序经过编译后,会把程序中的变量名全部转换为该变量的地址,存取操作都是通过地址进行的,而不是变量名。
- 按变量名访问属于“直接访问",即操作对象就在该变量名指向的地址里面;若将变量的地址存放到另一个变量中,称为“间接访问”。
- 指针变量就是用来存放地址的变量,指针变量的值就是变量的地址(指针)
附:“指针”和“指针变量”的区别【变量i的指针是2000,但不能说变量i的指针变量是2000】
特殊符号:
- & 取地址运算符,&a是指变量a的地址
- 指针运算符(“间接访问”运算符),*p代表指针变量p指向的对象(变量,该变量中有地址)
程序分析
- 数组名arr是该数组的首元素的地址,arr的首元素(arr[0])是一个内含两个int值的数组(*arr[0] = {arr[0][0], arr[0][1]}),所以arr是这个内含两个int值的数组的地址(arr[0] = {&arr[0][0], &arr[0][1]})
- 因为arr是数组首元素的地址,所以arr == &arr[0];因为arr[0]本身又是一个包含两个int值的数组,所以arr[0] == &a[0][0];综上可得:arr[0]是一个占用一个int大小对象的地址,arr是一个占用两个int大小对象的地址,但由于这个整数(arr[0][0])和内含两个整数的数组(arr[0])都开始于同一个地址,所以arr == arr[0]
int main(void) {
int arr[4][2] = { {2, 4}, {6, 8}, {1, 3}, {5, 7} };
printf(" arr = %p, arr + 1 = %p\n", arr, arr + 1);
printf("arr[0] = %p, arr[0] + 1 = %p\n", arr[0], arr[0] + 1);
printf(" *arr = %p, *arr + 1 = %p\n", *arr, *arr + 1);
printf("-----------------分-----割------线-------------------\n");
printf("arr[0][0] = %d\n", arr[0][0]);
printf(" *arr[0] = %d\n", *arr[0]);
printf(" **arr = %d\n", **arr);
printf("---分---割---线----\n");
printf(" arr[2][1] = %d\n", arr[2][1]);
printf("*(*(arr+2) + 1) = %d\n", *(*(arr+2) + 1));
return 0;
}
输出结果:
arr = 0x7ffeebd6a160, arr + 1 = 0x7ffeebd6a168
arr[0] = 0x7ffeebd6a160, arr[0] + 1 = 0x7ffeebd6a164
*arr = 0x7ffeebd6a160, *arr + 1 = 0x7ffeebd6a164
-----------------分-----割------线-------------------
arr[0][0] = 2
*arr[0] = 2
**arr = 2
---分---割---线----
arr[2][1] = 3
*(*(arr+2) + 1) = 3
理解这些表达式:
类似于“脱帽法”,a[1] = *(a+1)、a[1][2] = *(a+1)[2] = *(*(a+1)+2)
| 表达式 | 解释 | 相当于 |
|---|---|---|
| arr | 二维数组首元素地址(每个元素都是内含两个int类型元素的一维数组,也称作“行”) | &arr[0] |
| arr + 2 | 二维数组的第3个元素(即一维数组)的地址 | &arr[2] |
| *(arr + 2) | 二维数组的第3个元素(即一维数组)的首元素(一个int类型的值)的地址 | &arr[2][0] |
| *(arr + 2) + 1 | 二维数组的第3个元素(即一维数组)的第2个元素(一个int类型的值)的地址 | &arr[2][1] |
| *((arr+2) + 1) | 二维数组的第3个元素(即一维数组)的第2个元素(一个int类型的值) | arr[2][1] |