指针计划分成3篇来讲: 上篇是指针的基本使用 、 中篇指针与数组的联系、下篇是指针与字符串的联系
一、概述
指针其实也是变量的一种,只是它是一种特殊的变量,特殊就特殊在它所接受的值并不是简单的值,比如整数10, 小数8.5, 字符 a ,它接受的是具体的地址。这个地址可以是一个变量的地址、一个函数的地址。一旦完成指针的初始化,即可看成指针与目标地址产生了指向关系,有了这层指向关系后,后续希望获取目标地址的值,除了使用原有的变量名之外,也还可以通过指针来操作。这也就是“指针”的意思。
二、声明和初始化
2.0 说在前面话
a. 指针的声明和初始化非常简单,与普通的变量几乎无异。
b. 指针声明的语法是: 指针类型 * 指针名称 = 具体的地址;
c. 获取变量的地址,需要使用取地址符号: & (小伙伴们不要把这个符号看成是与运算了)
2.1 声明指针并初始化
#include <stdio.h>
int main(){
// 定义一个变量 number
int number= 10 ;
// 声明一个int类型的指针p, 并且指向number这个变量。
int * p = &number
return 0 ;
}
柯南有话说:
1. number变量位于内存中有自己的地址,假设为: 0xF8
2. 使用指针p 指向 number , 相当于是在 指针 p 所开辟的内存空间里面存放 : 0xF8.
3. 当然指针p 也是一个变量,它应该也有自己的内存地址,比如此处给的: 0xCA . 但是此时没有谁指向它而已。
4. 指针的类型通常与它所指向的目标位置的数据类型一致。比如 int类型的指针指向int类型数据 ...
2.2 声明指针然后再赋值
#include <stdio.h>
int main(){
// 1. 定义一个 int 类型的指针 【虽然看起来没有指向,但是这种写法有风险的,后续再说道】
int * p ;
//2. 定义一个变量 number
int number = 10 ;
//3. 把number的地址赋值给 p
p = &number;
return 0 ;
}
三、解引用
有了指针之后,就可以使用指针来解引用,使用 解引用符号 * 来操作所指向的目标位置区域了。我们可以获取所指向位置的值,也可以修改所指向位置里面的值
#include <stdio.h>
int main(){
// 定义一个变量 number
int number= 10 ;
// 使用变量赋值和取值
number = 20;
printf("number的值是:%d \n", number);
// 声明一个int类型的指针p, 并且指向number这个变量。
int * p = &number
// 使用指针解引用赋值和取值
*p = 30;
printf("number的值是:%d \n", *p);
return 0 ;
}
柯南有话说:
1. 上面的代码底部的 *p = 30 。 此处的 * 符号即为 解引用符号。千万不要把 *p 和上面的 int *p 看成是一样的。
1.1 上面的 int * p 里面的 * 表示 p 是一个指针, 此处的 * 是指针的标识
1.2 底部的 *p 是表示要解引用,因为在这里 p 其实已经是指针了。
2. 解引用是指针的典型应用场景,甚至可以说是指针的最大作用。比如咱们平常所见到的内存修改器,背后其实就是使用指针指向具体的内存数据值,然后再利用解引用去修改值。
四、指针地址和大小
4.1 指针的地址
正如前面所说的指针也是一个变量,只是它比较特殊而已【它接收的值是地址】,既是变量,我们就可以对它取地址。其实对指针去地址对变量取地址没有什么两样。好比是我们取得教室101的地址和教室202的地址, 都是地址。区别仅仅在于教室里面装的是什么。
1. 猜一猜下面5句输出代码,分别会打印什么?
#include <stdio.h>
int main(){
// 定义一个变量 number
int number= 10 ;
printf("number的值是: %d\n" , number); // 1
printf("number的地址是: %#x\n", &number); // 2
// 声明一个int类型的指针p, 并且指向number这个变量。
int * p = &number;
printf("指针p的值是: %#x\n" , p); // 3
printf("指针p的地址是: %#x\n", &p); // 4
printf("指针p所指向的位置存放的数据是: %d\n", *p); // 5
return 0 ;
}
柯南有话说:
1. 第一行打印语句,输出的结果很容易就可以看出来是: 10
2. 第二行打印语句,输出的结果每个人运行结果不太一样了,打印的是内存地址, 比如我的电脑打印的是:0x9fdffcf4
3. 第三行打印语句,输出的是p的值,其实就是指针指向了哪里。结果显然就是number 的地址,所以打印的是: 0x9fdffcf4
4. 第四行打印语句,输出的是指针p的地址,这个每个人运行结果不太一样了,打印的是内存地址, 比如我的电脑打印的是: 0x9fdffcf8
5. 第五行打印语句,输出的是指针p指向的目标地址存放的值,它指向的是number, 所以当然应该打印: 10
6. 在打印的时候,我们使用 %x 来打印输出十六进制地址 , 前面加上# 表示强制使用十六进制格式打印,所以打印结果前面会有 0x 打头。
4.2 指针的大小
正如前面所说的指针也是一个变量,所以它也会有占用空间大小之分。不过它倒不用像其他数据类型有这么多变化,在32位系统下指针的大小(占用空间)是4个字节,在64位系统下指针的大小(占用空间)是8个字节。其实这很好理解: 指针就是专门存放着所指向的目标位置的地址,甭管目标位置存放的是什么数据。我们的指针永远在自己的位置储存着目标的地址。
#include <stdio.h>
int main(){
// 定义一个变量 number, 并且使用指针 p 指向它。
int number= 10 ;
int * p = &number;
// 定义一个变量 c ,并且使用指针 p1 指向它
char c = 'a';
char * p1 = &c;
// 定义一个变量 price , 并且使用指针 p2 指向它
double price = 20.5;
double * p2 = &price;
//把这3个不同类型的指针占用大小打一下,我们会见到一样的值。
//如果是32位的系统,那么则得到4个长度,如果是64位的系统,则得到8个长度
printf("指针p占用空间大小: %d \n" , sizeof(p));
printf("指针p1占用空间大小: %d \n" , sizeof(p1));
printf("指针p2占用空间大小: %d \n" , sizeof(p2));
return 0 ;
}
五、总结
1. 这章内容我们主要学习了指针的概念、声明和初始化、指针解引用、指针的地址和大小这些内容。 总体来说作为指针的入门学习篇,代码难度中等偏下,小伙伴们只要亲自动手写过一遍,那么还是十分容易记下来的。
2. 指针声明后应该完成初始化,或者在未初始化前不要贸然解引用。解引用应该是指针的经典应用了,小伙伴们请务必勤加练习。
3. 至于指针的地址和大小,这个应该就是套路而已,把规律记住,其实根本不需要费多大的功夫和时间。
六、思考
1. 指针声明未初始化前,不要贸然操作指针,这是出于什么考虑呢?
2. 指针可以接收地址,这样就可以指向具体的目标值了,那么请思考一下:是否可以让指针指向指针呢?
3. 指针的类型一般与所指向的目标位置数据类型保持一致,如果不一致会有什么问题?