保姆式指针讲解,超详细,适合初学者

1.指针是什么

2.指针的类型

3.野指针的情况

4.指针与数组

5.二级指针

6.指针数组


一. 指针是什么

1.指针是内存中一个最小单元的编号,也就是地址

2.我们平时口语所说的指针,通常指的是指针变量,用来存放内存地址

 一句话来说,指针就是地址,我们口语常说的指针是指针变量

我们不妨借表格来理解指针变量

内存
一个字节 0xFFFFFFFF
一个字节 0xFFFFFFFE
...
一个字节 0x00000002
一个字节 0x00000001

我们可以通过&符将变量的内存以及地址,并将其存放在一个变量中,这个变量就是指针变量。

#include<stdio.h>
int main()
{
int a=20;//在内存中找到一块空间
int *p=&a;//用取地址操作符取出变量a的地址
//a变量占用四个字节的空间,这里是将a的四个字节的第一个字节的地址存放在p变量中,
//p成了一个指针变量
return 0;
}

总而言之,指针变量是用来存放地址的变量,我们不由地提出问题

1.一个小的内存单元应该是多大?

2.如何编址?

我们假设一个内存单元是1比特,那么一个字节的变量就需要8个内存空间,这是十分不方便的。

所以,我们将一个内存单元设为1字节

对于一般的32位的机器,假设有32根地址线,每根地址线在寻址时产生高电平和低电平(1或者0),那么32根地址线产生的地址为

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
 11111111  11111111 11111111 11111111

就产生了2^32次方个地址。

每个地址是一字节的内存空间,计算可得2^32Byte == 2^32/1024KB == 2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB

即我们可以给4G的空间编址

比葫芦画瓢,在64位的机器上,我们可以给8G的空间编址

二,指针的类型

我们都知道,变量有不同的类型,指针有没有呢?答案是肯定的

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
    char* pa = NULL;
    int* pb = NULL;
    short* pc = NULL;
    long* pd = NULL;
    float* pe = NULL;
    double* pf = NULL;
    return 0;
}

可以看到,指针的定义方式是“类型+*”

类似与定义变量,int *类型的指针是为了存放int类型变量的地址,double *类型的指针是为了存放double类型变量的地址。

2.1.指针类型的意义

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int n = 10;
	char* a = (char*)&n;
	int* b = &n;
	printf("%p\n", &n);
	printf("%p\n", a);
	printf("%p\n", a + 1);
	printf("%p\n", b);
	printf("%p\n", b + 1);
	return  0;
}

运行结果: 

00EFF930
00EFF930
00EFF931
00EFF930
00EFF934

D:\Program Files (x86)\Microsoft Visual Studio\class109\Project114\Debug\Project114.exe (进程 20716)已退出,代码为 0。
按任意键关闭此窗口. . .

总而言之,指针类型决定了指针向前或向后走一步有多大距离

2.3.指针解引用

对于不同的指针类型,指针解引用的权限也不同

例如,char*的指针解引用只能访问一个字节,而int*可以访问4个字节

三.野指针

成因:

1.未初始化

#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化
    *p = 20;
 return 0;
}

2.指针越界访问

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	int a[10] = { 0 };
	int i = 0;
	int* p = &a[0];
	for (i = 0;i <= 11;i++)
	{
		*(p++) = i;//当指针超出数组的范围时,p就是野指针
	}
	return  0;
}

3.2.如何避免野指针

1.不忘记指针初始化

2.不超出数组范围,不越界

3.使用前检查指针有效性

四.指针与数组

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
    int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
    printf("%p\n", a);
    printf("%p\n", &a[0]);
    return 0;
}

 运行结果:

009BF9E4
009BF9E4

可以看到结果是一致的。所以数组名表示的是数组首元素的地址

那么,我们这样写代码是可行的

 int a[10] = { 1,2,3,4,5,6,7,8,9,0 };
    int* p = a; //*p存放的是首元素的地址

既然可以将数组名当成地址存到指针中,那我们直接用指针访问也成了可能 

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
    int main()
    {
        int a[] = { 1,2,3,4,5,6,7,8,9,0 };
        int* p = a; //指针存放数组首元素的地址
        int sz = sizeof(a) / sizeof(a[0]);
        for (int i = 0; i < sz; i++)
        {
            printf("&a[%d] = %p   <====> p+%d = %p\n", i, &a[i], i, p + i);
        }
        return 0;
}

运行结果:

&a[0] = 010FFE80   <====> p+0 = 010FFE80
&a[1] = 010FFE84   <====> p+1 = 010FFE84
&a[2] = 010FFE88   <====> p+2 = 010FFE88
&a[3] = 010FFE8C   <====> p+3 = 010FFE8C
&a[4] = 010FFE90   <====> p+4 = 010FFE90
&a[5] = 010FFE94   <====> p+5 = 010FFE94
&a[6] = 010FFE98   <====> p+6 = 010FFE98
&a[7] = 010FFE9C   <====> p+7 = 010FFE9C
&a[8] = 010FFEA0   <====> p+8 = 010FFEA0
&a[9] = 010FFEA4   <====> p+9 = 010FFEA4

所以p+i其实计算的是数组a下标为i的地址

我们可以直接通过指针来访问数组

#include<stdio.h>
int main()
{
 int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
 int *p = a; //指针存放数组首元素的地址
 int sz = sizeof(a) / sizeof(a[0]);
 int i = 0;
 for (i = 0; i<sz; i++)
 {
 printf("%d ", *(p + i));
 }
 return 0;
}

五.二级指针

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
    int main()
    {
        int a = 10;
        int* pa = &a;
        int** ppa = &pa;
        return 0;
}

*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa .

int b = 20; *ppa = &b;//等价于 pa = &b;

而**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a .

**ppa = 30; //等价于*pa = 30; //等价于a = 30

六.指针数组 

指针数组是数组,而且是存放指针的数组

我们已经知道的数组有整型数组和字符数组

int a1[5];

char a2[5];

a1 int
int
int
int

int  

a2 char
char
char
char
char

指针数组是这样的

int *a3[5];//整形指针数组

a3 int *
int *
int *
int *
int 

c语言小白,有错误的话请大家私信我,我会改正,之后的几章章节梳理我也会陆续写出来

猜你喜欢

转载自blog.csdn.net/weixin_73534885/article/details/128410861