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

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

一. 指针是什么


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语言小白,有错误的话请大家私信我,我会改正,之后的几章章节梳理我也会陆续写出来


相关文章
|
6月前
|
存储 程序员 编译器
爱上C语言:指针很难?来来来,看看这篇(基础篇)
爱上C语言:指针很难?来来来,看看这篇(基础篇)
|
机器学习/深度学习 C语言
头歌c语言实训项目-数组的使用
头歌c语言实训项目-数组的使用
226 1
|
30天前
|
C语言 C++
保姆式教学C语言——数组
保姆式教学C语言——数组
16 0
保姆式教学C语言——数组
|
30天前
|
机器学习/深度学习 C语言
C语言必刷题上(保姆式详解)
C语言必刷题上(保姆式详解)
13 0
|
6月前
|
IDE Java 开发工具
C语言入门(前期准备工作)——超级详细的建议和教学,带你顺利跨越编程门槛
C语言入门(前期准备工作)——超级详细的建议和教学,带你顺利跨越编程门槛
|
5月前
|
C语言
C语言结构体教程:从入门到实践(保姆式教学)
C语言结构体教程:从入门到实践(保姆式教学)
66 0
|
C语言
【C语言航路】第十站:指针进阶(二)
【C语言航路】第十站:指针进阶(二)
38 0
|
存储 编译器 C语言
抽丝剥茧C语言(中阶)指针+练习
抽丝剥茧C语言(中阶)指针+练习
|
C语言
可能你看到的大部分教材里讲的指针和指针变量是一个概念,但是真的是这样吗?看完我这篇文章肯定会颠覆你的认知哦?
可能你看到的大部分教材里讲的指针和指针变量是一个概念,但是真的是这样吗?看完我这篇文章肯定会颠覆你的认知哦?
133 0
可能你看到的大部分教材里讲的指针和指针变量是一个概念,但是真的是这样吗?看完我这篇文章肯定会颠覆你的认知哦?
|
安全 Java 程序员
<<c和指针>>温故及问题研讨(第一章)
这个部分的分享主要是我在阅读<<C和指针>>这本书的过程发现的我以前遗漏或者没有记清楚的知识点,这本书内容很多,我只做我认为容易混淆或遗漏的部分的分享,有些我认为比较简单的地方会略掉,知识点可能比较杂,我尽量为大家理请逻辑.此书共十八章,也就代表这一部分的博客会有18篇,希望大家多多支持!
<<c和指针>>温故及问题研讨(第一章)
下一篇
无影云桌面