C语言指针全归纳-初级版
C语言作为一门较为好上手的高级计算机语言,我相信任何一个开始学习编程的人都是先从他开始入手的,但是其中的指针曾叫人叫苦不迭。本文章旨在全面梳理C语言指针的知识点,内容非常宏大且精细,希望可以给看到本篇文章的人带来全新的指针认识。
本文为初阶版,我会尽快创作出高阶版的指针,喜欢本文的可以点个关注
本文章主要内容
- 1. 什么是指针
- 2. 指针的类型有哪些
- 3. 野指针
- 4. 指针的运算
- 5. 指针和数组
- 6. 二级指针
- 7. 指针数组
1. 什么是指针
先来看看定义
在计算机科学中,指针(Pointer)是编程语言中的一个对象,利用地址,它的值直接指向(points to)存在电脑存储器中的另一个地方的值。由于通过地址能找到所需的变量单元,所以可以说,地址指向该变量单元。因此,将地址形象化的称为‘指针’。意思是通过它能找到以他为地址的内存单元。
int a=10;int *p=&a;p是指针变量,存放内存单元的地址(整形占四个字节,存放首地址,其他类型亦是如此)&a是a的地址,也就是指针存入p 所以说&a或p唯一指向a
地址是如何产生的呢?
地址就是数据在内存中的存储位置的“门牌号”
计算机有32位和64位的配置,已32位为例:
就是有32根地址线,可以在寻址时产生32个电信号(正或负),将电子信号转换为数字信号就是32位的01序列(64位就是64位的01序列),地址编号就是由此产生的,但是为了便于观察,我们会用16进制来进行表示。
由此也可以推断出32位机器的指针大小为4字节(32bit==4byte),64位机器的指针为8字节。
2. 指针的类型有哪些
int *p1;char *p2;double *p3;float *p;………… 这些指针虽然指向的数据类型不同,但本身大小都一样, 那么为什么要给出这么多指针类型呢?难道不能只设置一种类型指向所有吗? 比如pointer *p;接下来我们看看指针类型有什么用呢?
以上两个图片我们可以看到
int* 型的指针解引用访问了四个字节的内容
char* 型的指针解引用只访问了一个字节的内容
由此可以看出指针类型的第一个作用:决定了指针的访问权限,即指针向后方访问几个字节
所以我们想要访问几个字节就用相对应字节数类型的指针进行存储。
从上图可看出不论是什么类型的指针存放的都是元素起始地址。
但不同类型的指针+/-1所改变的距离不同,这就是指针类型的第二个作用
所以我们如果用char*指针就可以把arr[10]当成四十个空间来使用。
3. 野指针
p得到地址时,地址指向的空间已经释放了,所以这个时候的p就是野指针。
野指针:指针指向的位置是不可知的。(随机的、不正确的、无明确限制的)
野指针形成原因共一下几种可能:
- 指针未初始化
#include<stdio.h>int main(){int *p;//此时p未初始化,里面是随机值,乱用会很危险*p = 20;return 0;}
- 指针越界访问
#include<stdio.h>int main(){int arr[10] = { 0 };int *p = arr;int i;for (i = 0; i < 11; i++){*(p + i) = i;}return 0;}
- 指针指向的空间释放
那么如何规避野指针呢?
- 指针初始化
int *p=NULL;//不知道要指向谁就置成空指针orint a=1;int *p=&a;//知道要指向谁
- 防范指针越界
- 指针指向空间释放后就及时置成空指针
- 指针使用前检验有效性
指针置成空指针时是无法使用的
要学会使用断言(assert)判断指针是不是空指针
#include<stdio.h>#include<assert.h>int main(){int *p=NULL;assert(p!=NULL);//上式为假会报错return 0;}
4. 指针的运算
- 指针+/-整数
指针加减整数上面其实已经提到了,*(p+i)就是一种应用
再介绍一种
#include<stdio.h>int main(){int arr[10] = { 0 };int *p = arr;int i;for (i = 0; i < 10; i++){*p++ = i;} p = arr;//注意++对p产生了实际效果,所以要重置for (i = 0; i < 10; i++){printf("%d ", *p++);}return 0;}
- 指针 - 指针
由此可知,指针-指针得到的值的绝对值是两者之间元素的个数
但是必须是两个指针指向同一块连续的空间,两个数组的话会造成不确定结果 - 指针的关系运算
其实际就是指针之间进行比较
#define N 5int main(){float arr[N];float *p;for (p = &arr[5]; p > &arr[0];){*--p = 0;}return 0;}
5. 指针和数组
数组是指针吗?
指针式数组吗?
答案统统都是No,数组是一堆相同类型元素的集合,指针只是一个变量
他们之间的关系是数组可通过指针来访问
数组名表示的是数组首元素的地址,所以就可以将其存入指针中
在说指针越界那里已有举例,在此就不再过多赘述了。
强调一点:(p+i)==&arr[i]
6. 二级指针
一个int型的变量的地址可以存放到一个指针变量里边,那么这个指针作为一个变量是否也可以存放在一个指针变量里边呢,这就涉及到二级指针的概念了。
int main(){int a = 1;int *p1 = &a;//一级指针int **p2 = &p1;//二级指针//p2->&p1,*p2->&a,**p2->a//以此类推,可以得到以下式子,但使用几率不大int ***p3 = &p2;int ****p4 = &p3;int *****p5 = &p4;return 0;}
7. 指针数组
指针数组是指针还是数组呢?
答案是数组。
int main(){//整形数组:存放整形元素的数组int arr1[10] = { 0 };//指针数组:存放元素为指针的数组int a, b, c, d, e;int *arr2[5] = { &a, &b, &c, &d, &e };//存放整形指针的数组char *ch[5] = { NULL };//存放字符指针的数组//介绍一下使用方法char *c[5] = {"hehe","haha","ohhhh"};int i=0;for(i=0;i<3;i++){printf("%s ",c[i]);}return 0;}