It has been 801 days since the last update, the content of the article may be outdated.

指针知识框架(详解)

本文为 C 语言学习过程中关于指针的笔记。根据书籍和程序题并参考网络上的博客回答,撰写的感悟和收获。
文章参考:
C 语言解惑指针、数组、函数和多文件编程(作者刘振安刘燕君,机械工业出版社)

一、对指针使用 const 限定符

1. 指向常量的指针

const int  y=66;
const int p=&y; // 此时 y 和 p 都不能做为左值,但可以作为右值。

使指针指向一个不可修改的常量,即 p 是常量。但是可以通过修改 p 指向的地址,改变 p 的值。
例如:

c
1
2
3
4
5
6
7
8
9
 const int y=66;
int x=50;
const int * p =&y;
printf("%d,%d,%p\n",y,*p,p);
p=&x;
printf("%d,%d,%p\n",x,*p,p);
/*输出结果为:
66,66,000000000062FE14
50,50,000000000062FE10*/

由指向 y 改为指向 x,*p 被覆盖。

2. 指向常量的指针指向非常量

示例:

c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
int main()
{
int x=55 ;//变量x能作为左值和右值
const int y=88;//常量y不能作为左值,但可以作为右值
const int *p;//声明指向常量的指针
int *p1 ;//声明指针
p=&y ;//用常量初始化指向常量的指针,*p不能作为左值
printf ("%d ",*p) ;
p=&x;//p作为左值,使常量指针改为指向变量x,*p不能作为左值
printf("%d ",*p) ;
x=128 ;//用x作为左值间接改变*p的值,使*p=x=128
printf("%d ", *p) ;
p1=(int*)&y;
printf("%d\n", *p1) ;
return 0;
}

示例中指向常量的指针 p 指向变量 x, 仅限制直接使用 p 作为左值,但可以通过直接修改 x 的值改变 p 的值。同时也与使用非常量指针一样,也可以直接使用 “&” 改变常量指针的指向,显然也改变了 * p 的值。

【注】常量只能由指向常量的指针(即 const voidp)指向,否则必须进行强制转换,将常量强制转换为相应的指针类型。如示例:p1=(int)&y;

3. 常量指针

限定符 const 放在 * 号右边,是指针本身成为一个 const 指针。声明常量时必须进行初始化,即指针变量 p 存储的为常量地址。

例如:int x=45;
int * const p=&x//p 始终指向 x 的地址。但可以修改 x 地址内存的值,x=123 和 * p=123;但 p 指向的地址不能改变

4. 指向常量的常量指针

即指针和指向的对象都不能改动的 “指向常量的常量指针”。p 和 p 都是常量。限制了 “&” 和 “” 运算符,很少使用。

5.void 指针

void 类型不能声明变量,但可以声明 void 类型的指针,而 void 型指针可以指向任何类型的变量。

c
1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
int main()
{
int x=256, y=386,*p=&x;
void*vp=&x;
printf("%d,%d,%d\n",vp,p,x);
vp=&y;
p=(int*)vp;//虽然void指针指向整型变量对象x,但不能使用*vp应用整型对象的值。要引用这个值,必须强制将void指针赋值给与值相对应的指针类型。
printf("%d,%d,%d\n",vp,p,*p);
return 0;
}

【注】但奇怪的是,测试时发现 p=(int*) vp 不加(int*)也可以正常运行。

小结

const 放在的右边(void * const p), 修饰的是指针(即指针变量 p 指向的地址)不可改变。
const 放在前端(const void * p), 修饰的是指向的对象(指针变量 p 存储的地址的值), 即
p 是常量

二、指针与数组

1. 数组与指针的关系

指向数组的指针实际上指的是能够指向数组众人一个元素的指针。

int a[5];
int *pa=&a [0];// 等同于 int *pa;
           pa=a;

数组名和指针的区别:指针是变量:pa=a 或 pa 是有意义的;
      数组名是指针常量:a=pa、a
、pa=&a(a 本身就是地址,无法对地址取地址)是非法操作。
假设指针现在指向 a [0], 则数组的第 i 个(下标为 i)元素可表示为 a [i] 或 *(pa+i), 还可使用带下标的指针 pa, 即 pa [i] 和 *(pa+i)的含义一样。若将 a [i] 的值修改,下列语句等价。

a[i]=123; *(a+4)=123; *(pa+4)=123; pa[4]=123;

指针与数组元素的关系

下标 数组名 指针 指针下标 四者的逻辑关系
a[0] a pa pa[0] a[0]*a*pa==pa[0]
a[1] a+1 pa+1 pa[1] a[1]*(a+1)*(pa+1)==pa[1]
a[2] a+2 pa+2 pa[2] a[2]*(a+2)*(pa+2)==pa[2]

2. 指针数组和数组指针

数组的指针:是一个指针,什么样的指针呢?指向数组的指针。
指针的数组:是一个数组,什么样的数组呢?装着指针的数组。
本质是的后面是类型。
然后,需要明确一个优先级顺序:()>[]>*,所以:
(*p)[n]:根据优先级,先看括号内,则 p 是一个指针,这个指针指向一个一维数组,数组长度为 n,这是 “数组的指针”,即数组指针;
p [n]:根据优先级,先看 [],则 p 是一个数组,再结合,这个数组的元素是指针类型,共 n 个元素,这是 “指针的数组”,即指针数组。
根据上面两个分析,可以看出,p 是什么,则词组的中心词就是什么,即数组 “指针” 和指针 “数组”。
———— 数组指针和指针数组_mick_hu 的博客 - CSDN 博客_数组指针和指针数组原文地址

3. c 语言优先级

C 语言运算符优先级(超详细)_embed_huang 的博客 - CSDN 博客_c 语言运算符优先级构成一系列表达式(六个左右),然后分析并打印输出他的结果原文地址