您的当前位置:首页正文

C语言入门系列:指针入门(超详细)

2024-11-21 来源:个人技术集锦

指针是 C 语言的重点,也是难点,这篇文章主要讲解指针是什么以及如何使用。

一,什么是指针

1,内存

指针与内存是息息相关的,在学习指针之前,先回忆下内存相关的知识。

如果把内存比作一栋酒店大楼,内存单元就像是一个个小的房间,数据就住在小房间里。

我们知道,为了客人能准确找到属于自己的房间,酒店房间是有房号的。

2,指针是什么?

二,指针的声明

1,声明指针类型变量

在编写代码过程中,通常会声明一个变量,然后对变量进行赋值或者其他各种运算。

要使用指针,也需要声明一个指针类型的变量。

指针类型由两部分构成

  • ①指针标识符,C语言用字符*表示指针
  • ②指针类型,指针不能单独存在,必须和数据类型一起出现,表明这个指针是某种数据类型的指针

比如,char*表示一个指向字符的指针,float*表示一个指向float类型的值的指针。

int* intPtr;

星号*可以放在变量名与类型关键字之间的任何地方,下面的写法都是正确的。

int   *intPtr;
int * intPtr;
int*  intPtr;

推荐使用星号紧跟在类型关键字后面的写法,即int* intPtr;

声明指针变量时需要注意,如果要在一行声明多个指针变量,每个变量前都要携带字符*

// 正确
int * foo, * bar;

// 错误
int* foo, bar;

上面示例中,第二行实际上仅仅声明了一个指针变量,foo是整数指针变量,而bar是整数变量,即*只对第一个变量生效。

2,二级指针

一个指针指向的可能还是指针,这时就要用两个星号**表示,这种指针通常称为二级指针

int** foo;
int a = 10;
// &a表示a变量的内存地址
int* pa = &a;
// &a表示指针变量pa的内存地址
int** ppa = &pa;

三,指针的计算

1,两个指针运算符

1.1 *运算符

*这个字符除了声明变量时代表指针外,还可以作为运算符,用来获取指针指向的内存中的值。

void plus1(int* p) {
  *p = *p + 1;
}

上面代码中,函数plus1的参数是一个整数指针p。

函数体里面,*p就表示指针p所指向的那个整数值。

对*p赋值,就是改变指针p指向的内存中的值。

这有点绕,和普通变量对比更容易理解。

int a = 10;
int b = 100;
// 将b的地址赋于指针pb
int* pb = &b;

*pb = *pb +1;
a = a + 1;

对于上述代码的最后两行:

  • *pb = *pb +1,这个表达式可以拆解为4步,计算机首先从指针变量pb中取出地址0xffeecc再去这个地址指向的内存单元中获取整数100然后执行运算100+1,执行完成后,0xffeecc这个内存单元的值就变成101。
  • a = a + 1,相当于上面的表达式,执行过程更简单。计算机从变量a对应的内存直接取出整数10然后执行运算10+1执行完成后,a变量对应的内存的数据更新为11

1.2 & 运算符

int x = 1;
printf("x's address is %p\n", &x);

上一小节中,参数变量加1的函数,可以像下面这样使用。

void plus1(int* p) {
  *p = *p + 1;
}

int x = 1;
plus1(&x);
printf("%d\n", x); // 2

1.3 &运算符与*运算符的关系

&运算符与*运算符互为逆运算,下面的表达式,是成立的。

int i = 5;

if (i == *(&i)) // 正确

2,指针变量的初始化

2.1 指针变量的大坑

声明指针变量之后,编译器会为指针变量本身分配一个内存空间,这个内存空间可能还保存着历史数据。

int* p;
*p = 1; // 错误

上述代码是必须避免的,因为指针p指向的内存单元是随机的。

2.2 指针变量初始化

int* p;
int i;

p = &i;
*p = 13;

2.3 指针变量初始化最佳实践

强烈推荐,声明指针变量的同时,将指针变量的值设为NULL。

int* p = NULL;

三,指针的运算

C语言允许指针参与运算,但是指针的运算规则和整数的运算规则是相差很大的。

1,指针与整数值的加减运算

指针与整数值的运算,表示指针的移动。

short* j;
j = (short*)0x1234;
j = j + 1; // 0x1236

由于0x1234本身是整数类型(int),跟j的类型(short*)并不兼容,所以强制使用类型投射,将0x1234转成short*。

表明上看,j + 1应该等于0x1235,但正确答案是0x1236。

指针移动的单位,与指针指向的数据类型有关。数据类型占据多少个字节,每单位就移动多少个字节。

2,指针与指针的加法运算

指针只能与整数值进行加减运算,两个指针进行加法是非法的。

unsigned short* j;
unsigned short* k;
x = j + k; // 非法

上面示例是两个指针相加,这是非法的。

3,指针与指针的减法

相同类型的指针允许进行减法运算,返回它们之间的距离,即相隔多少个数据单位。

这时,减法返回的值属于ptrdiff_t类型,这是一个带符号的整数类型别名,具体类型根据系统不同而不同。这个类型的原型定义在头文件stddef.h里面。

short* j1;
short* j2;

j1 = (short*)0x1234;
j2 = (short*)0x1236;

ptrdiff_t dist = j2 - j1;
printf("%td\n", dist); // 1

上面示例中,j1和j2是两个指向 short 类型的指针,变量dist是它们之间的距离,类型为ptrdiff_t,值为1,因为相差2个字节正好存放一个 short 类型的值。

4,指针与指针的比较运算

显示全文