指针笔记草稿

  1. 在C中,指针加1指的是增加一个存储单元。对于数组而言,这意味着把加1后的地址是下一个元素的地址,而不是下一个字节的地址
  2. 指针的值是它所指向对象的地址。地址的表示方式依赖于计算机内部的硬件。大多数计算机都是按字节编址。一个较大对象的地址(如double类型的变量占8个字节)通常是该对象第一个字节的地址
  3. 在指针前面使用*运算符可以得到该指针所指向对象的值
  4. 指针加1,指针的值递增它所指向类型的大小(以字节为单位)
1
2
dates + 2 == &datas[2]  // 相同的地址
*(dates + 2) == dates[2] // 相同的值

以上体现了指针与数组的关系非常密切,datas不仅是数组名,还可以表示该数组的地址。

1
2
3
4
// C语言在描述数组时确实运用到了指针。

ar[n] // 该数组的定义意思就是*(ar + n)
//即到内存的ar位置,然后移动n个单元,检索储存在那里的值
  • 注:指针中有个容易混淆的点
1
2
3
*(dates+2) // dates第3个元素的值
*dates+2 // 相当于*(dates)+2 dates第1个元素的值加2
// 这里的间接运算符(*)的优先级高于+,

这样在编写程序的时候就可以适时使用指针表示法或者数组表示法。

1
2
3
4
int days[10];

//指针表示法 //数组表示法
*(days + 2); days[2];

明白了指针和数组是互通的,那么看看下面代码

1
2
3
4
5
6
7
8
9
10
int days[6] = { 1, 2, 3, 4, 5, 6};
int *p, *q;

p = &days[1]
*q = p[2]
printf("%d", *q);
//此时*q的值应该为days[4]中元素的值
//p = &days[1] 等价于 p = days + 1
//*q = p[2] 等价于 *q = *(p + 2)
//即*q = *(days + 1 + 2)
  • C保证在给数组分配空间时,指向数组后面第一个位置的指针仍是有效的指针。这使得while循环的测试条件是有效的,因为start在循环中最后的值是end。注意,使用这种“越界”指针的函数调用更为简洁

  • 虽然C保证了marbles + SIZE有效,但是对marbles[SIZE] (即储存在该位置上的值)未作任何保证,所以程序不能访问该位置。

  • 注意:

1
2
3
total += *start++;
//一元运算符*和++的优先级相同,但是结合律是从右往左
//所以start++先求值,然后才是*start

ar[i] 和 *(ar +i)这俩个表达式都是等价的,只有当ar是指针变量时,才能使用ar++;

指针的操作

指针的公共功能

指针赋值

可以把地址赋给指针。

注意:地址应该和指针类型兼容,一个声明为int类型的指针不能指向存储double类型数据的地址

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500};
int * ptr1, *ptr2, *ptr3;

ptr1 = urn; //把数组urn[0]的地址赋值给指针ptr1
ptr2 = &urn[2]; //把urn[2]的地址赋值给指针ptr2
return 0;
}

指针解引用

*运算符给出指针指向地址上储存的值。

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500};
int *ptr1;

ptr1 = urn; //把数组urn[0]的地址赋给指针ptr1
printf("*ptr1 = %d", *ptr1) //此时输出的值为100
return 0;
}

指针取址

指针也是变量,自然也会有相应的地址。用&运算符给出指针本身的地址。

1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500};
int *ptr1, *ptr2;

ptr1 = urn; //把数组urn[0]的地址赋给指针ptr1
ptr2 = &ptr1;//把指针变量ptr1的地址赋值给ptr2
return 0;
}

指针与整数相加、减

可以使用+运算符把指针与整数相加,或整数与指针相加。

但是并不是将指针与整数直接相加,这与声明指针时的数据类型有关。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500};
int *ptr1, *ptr2;

ptr1 = urn //把数组urn[0]的地址赋给指针ptr1
printf("ptr1 = %p", ptr1);
//ptr1 = 000000000065FE00
//假设本系统的int类型是4字节
ptr1 = ptr1 + 1;
printf("ptr = %p", ptr2);
//ptr1 = 000000000065FE04
//此时ptr1指向urn[1]

//同样的
ptr1 = ptr1 - 1;
//此时ptr1指向urn[0]


return 0;
}
  • 指针与整数相加并不是单纯加上该数,而是指针的值+整数*数据类型所占的字节。

  • 指针与整数相加的意思就是指向下一个相同类型变量的地址

  • 注:指针减一个整数时,指针只能是被减数,整数要做减数

指针递增、减

与其他基本数据类型一样,指针也可以使用递增运算符。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500};
int *ptr1, *ptr2;

ptr1 = urn //把数组urn[0]的地址赋给指针ptr1
printf("ptr1 = %p", ptr1);
//ptr1 = 000000000065FE00
//假设本系统的int类型是4字节
ptr1++;
printf("ptr = %p", ptr2);
//ptr1 = 000000000065FE04
//此时ptr1指向urn[1]

ptr--;
//ptr1 = 000000000065FE00
//此时ptr1又指向原来的urn[0]
return 0;
}

指针求差

可以将两个指针相减。通常求差的指针分别指向同一数组的不同元素。

通过相减可以求出两个元素之间的距离。

差值的单位与数组类型的单位相同。

两个不同数组类型的指针相减会出错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500 };
int * ptr1, *ptr2, *ptr3;

ptr1 = urn; // 把一个地址赋给指针
ptr2 = &urn[2]; // 把一个地址赋给指针

printf("ptr2 - ptr1 = %td", ptr2 - ptr1);
//ptr2 - ptr1 = 2
//注意2并不是2字节,而是2个int类型
return 0;
}

指针比较

使用关系运算符可以比较两个指针的值,但是前提是两个指针都指向相同类型的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main(void)
{
int urn[5] = { 100, 200, 300, 400, 500 };
int * ptr1, *ptr2, *ptr3, a;

ptr1 = urn;
ptr2 = &urn[2];
a = (ptr2 > ptr1);
// 比较为真a的值为1
a = (ptr2 == ptr1)
// 比较为假a的值为0

return 0;
}