C语言:指针详解【图解 + 练习】

这篇具有很好参考价值的文章主要介绍了C语言:指针详解【图解 + 练习】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

        指针其实是我们学习C语言中最难的知识点,很多人在学习指针的时候会被绕晕,包括博主也是,当初百思不得其解,脑袋都要冒烟了,本来打算在学习指针的时候就写一篇博客,但是当初自己的能力还是没有办法去完成这个壮举,但今时不同往日,如今也算是一名精通C语言的学生了,所以前来编写一篇关于指针的博客。

        本篇博客会让你对指针和数组的了解更深一步,你会发现其实数组和指针并没有什么区别,你也会知道数组指针其实存的就是数组的地址,而数组的地址是比里面元素的地址还要高一级的指针,这里我只会讲解一级数组指针,毕竟指针是可以无限套娃的,讲一个就理解多个了!

        如有表达不清晰或错误,请大家在评论区帮我指正,让我们的学习可以更加完善,而博主也会不断的来更新和修改!

学习目标

  • 首先要搞懂什么是取地址( & ),什么是解引用( * ),以及指针的加法
  • 学习一级指针,二级指针
  • 搞懂 数组指针和指针数组一维、二维数组名、二维数组的行、&数组名

一、理解取地址&、解引用*和指针的加法

        取地址很好理解,就是对一个变量取出它的地址;然后我们要用指针类型来接收这个地址,所以既然指针可以接收地址,那就说明指针就是地址!

        而指针最重要的其实就是解引用和指针的加法,这篇博客会让你理解什么是解引用和指针的加法:深入理解:指针变量的解引用 与 加法运算-CSDN博客

二、快速学习一级指针和二级指针

1. 一级指针

一级指针:其实存的就是非指针变量的地址,可以是各种非指针类型的地址

        而一级指针也是一个变量,变量一定占空间,有空间就要有地址,所以一级指针也是有地址的,千万不能认为一级指针没有地址!!!

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

    char c = '2';
    char *pc = &c;            //存char变量的地址
    
    short s = 1;
    short *ps = &s;           //存short变量的地址
    
    int i = 3;
    int *pi = &i;             //存int变量的地址
    
    double d = 4.5;
    double *pd = &d;          //存double变量的地址
    
    float f = 5.6f;
    float *pf = &f;           //存float变量的地址
    
//无符号等基本数据类型

    struct List l;
    struct List *plist = &l;  //存结构体stuct 变量的地址
    
    union All all; 
    union All *pall = &all;     //存联合体union变量的地址

enum、位段等自定义类型

这里面没有涉及对数组的取地址,因为比较特殊,会放在这里讲:🔗

2. 二级指针

二级指针:对一级指针取地址,可以是各种指针类型的地址

所以二级指针就是存放一级指针的地址的指针变量,那同理二级指针也是有地址的,这样就可以实现无限套娃,三级指针、四级指针、n级指针;

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

    char c;
    char *pc = &c;            
    char **ppc = &pc;

    short s;
    short *ps = &s;          
    short **pps = &ps;
    
    int i;
    int *pi = &i;             
    int **ppi = π
    
    double d;
    double *pd = &d;          
    double **ppd = &pd;
    
    float f;
    float *pf = &f;           
    float **ppf = &pf;
    
//无符号等基本数据类型

    struct List l;
    struct List *plist = &l; 
    struct List **pplist = &plist;
    
    union All all;
    union All *pall = &all;   
    union All **ppall = &pall;
    
//enum、位段等自定义类型    

三、指针数组

1. 指针数组的介绍

        我们先来学习指针数组的原因就是比数组指针好理解,并且数组名和二维数组的行都是和数组指针有关系的。

        那什么是指针数组呢?

        指针数组,顾名思义:是一个数组,数组元素都是指针类型的,说白了,指针数组就是存放地址的数组。

int arr[5] = {1,2,3,4,5};
int *arr[5] = {arr, arr + 1, arr + 2, arr + 3, arr + 4};

        既然有二级指针、三级指针、四级指针等等,就一定会有一级指针数组、二级指针数组和三级指针数组等等,后面的数组指针也是一个道理,所以我们在这里就仅仅讲解一级指针数组;

int **arr[5];    //二级整型指针数组
char ***ch[5];   //三级字符型指针数组

2. 指针数组的计算

        我们另外一篇文章知道了解引用是根据指针的数据类型(除*之外)来访问字节的;所以直接看下面的例题:

温馨提示:第三个printf语句需要了解大小端字节序才可以解决问题

#include <stdio.h>
int main()
{
    int arr[5] = {1,40000,3,4,5};
    int *parr[5] = {arr, arr + 1, arr + 2, arr + 3, arr + 4};
    printf("%d\n", **parr);
    printf("%d\n", **(parr + 1));
    printf("%d\n", *parr[1]);
    printf("%d\n", *(char*)parr[1]);
    return 0;
}

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

第一个printf

首先 **parr ,先看parr 这是一个数组名,是首元素的地址,也就是arr的地址,那parr的数据类型就是int*,*parr解引用是根据 int* 来的,也就是拿出一个指针类型大小的字节(指针类型在32位机器下是4字节,在64位机器下是8字节),取出了arr,那**parr 本质上就是*arr,arr是首元素地址,类型是int*,那*arr解引用就是根据int来的,拿出了一个int类型的大小,4字节,所以**parr = 1;

图解如下:

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

第二个printf 

同理,这里就是用到了指针+整数,parr的数据类型是int **,那parr + 1,是根据int *来加 的,也就是往后移动一个指针类型的大小,后面的过程都跟第一个相同

图解如下:

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

第三个printf

就是典型的用下标访问数组元素,但是在这里你就会发现 *(parr + 1) 和 parr[1]是等效的,那我们就可以使用指针的方式和数组下标一起来访问数组元素,因为这是等价的;

图解如下:

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

第四个printf

这里就涉及到一个强制类型转换,也就会导致我们解引用的时候取出来的字节数是改变的;

具体结果和大小端有关

大端字节序:低地址存放高数字位

小端字节序:低地址存放低数字位

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

        这里我们能快速地找到parr[1]是arr + 1 这个地址,然后被强制转换为char*类型,这也就表明了解引用的时候,只能取出char类型的字节,1字节。然而这里涉及一个大小端的问题,解引用的时候是从低地址开始解引用,一个字节一个字节取,所以经过char*强转取出来了只有地址最低的一个字节,也就是40;转换为十进制就是64;这是基于小端字节序的结果:

图解如下:

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

大端字节序的结果为:9c = 156

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

四、数组名和指针

        终于到了我们的数组名和指针这里了,这里会将数组名和数组指针一起对比着来讲解,大家最好要知道啥是数组指针就行,数组指针就是一个指向整个数组的指针。知道这些我们就开始学习吧!

1. 数组名

我们都知道 数组名表示的是数组首元素的地址,但是有两个特例表示的是整个数组的地址

表示整个数组的地址

  • &数组名
  • sizeof(数组名)

这里想讲解一下 &arr仅仅是一维数组的数组名

int arr[5] = {1,2,3,4,5};

        首先我们知道&arr是整个数组的地址,也就是其数据类型必须是这样: int (*) [5];这也就证实了其实&数组名的本质就是一个数组指针

        那怎样来理解这个类型呢?

        首先我们要让编译器 &arr 知道是整个数组的地址,那就必须让编译器知道有几个数组元素,所以我们会加上[ ],这里大家简单理解一下就行。最后我们只需要知道,&arr表示的是整个数组的地址就行。

接下来看一下下面的题:

#include <stdio.h>
int main()
{
    int arr[5] = {1,2,3,4,5};
    printf("%p\n", &arr);
    printf("%p\n", arr);
    return 0;
}

运行的结果是什么呢?整个数组的地址是啥样的呢?

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

        我们惊喜地发现,整个数组的地址居然和数组首元素的地址是一样的,那是真的一样吗?继续看下面的代码:

#include <stdio.h>
int main()
{
    int arr[5] = {1,2,3,4,5};
    printf("%p\n", arr);
    printf("%p\n", arr + 1);

    printf("%p\n", &arr);    
    printf("%p\n", &arr + 1);
    return 0;
}

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

        我们会发现&arr + 1,跳过了20个字节,也就是5个元素的大小

        所以虽然整个数组的地址和数组首元素的地址是一样的,但是加一之后移动的字节是不同的,本质上是因为数据类型的不同导致的

        arr的数据类型:int * ,&arr的数据类型是 int(*)[5]

2. 二维数组名

二维数组名,同样也适用于对数组名的规则;

先说结论:二维数组的数组名 == 二维数组第一行的地址

下面代表的运行结果是什么呢?

#include <stdio.h>
int main()
{
    int arr[2][2] = {{1,2},{3,4}};
    printf("arr: %p\n", arr);
    printf("arr + 1: %p\n", arr + 1);
    return 0;
}

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

        结果是移动了8个字节,也就是两个int类型的大小啊,两个int类型的大小不就是第一行吗?所以通过这个现象可以知道,二维数组的首元素是整个第一行,所以二维数组的数组名就是整个第一行的地址啊!

3. 二维数组的行

二维数组的行:是表示该行这个一维数组的数组名,是该行首元素的地址

        讲解二维数组的行之前

        大家先想一下一维数组的每个元素是什么?

        通过一维数组能不能推出二维数组的每个元素是什么呢?

int arr[2][2] = {{1,2},{3,4}};

        不难想出,二维数组的每个元素其实就是每一行的一维数组,因为上面也隐含了二维数组的数组名是第一行的地址,而数组名又是首元素的地址,那就侧面印证了二维数组其实就是一维数组的数组。但是这跟我们的行有什么关系呢?接下来就是要学习的知识了

        大家先理清一下思路,二维数组的行是什么?二维数组的行就是第一个方括号[ ],而我们要访问一个一维数组元素的时候,是这样访问的:

int a[5] = {1,2,3,4,5};
a[1] = 8;

访问二维数组的第一行的元素,是这样访问的:

int arr[2][2] = {{1,2},{3,4}};
arr[0][1] = 8;

它们之间的共同之处: 都要用数组名+下标引用

一维数组:arr + [1]

二维数组:arr[0] + [1]

所以我们会发现二维数组的行,其实就相当于一维数组的数组名!既然二维数组的行相当于一维数组的数组名了,那就是首元素的地址,arr[0] == &arr[0][0]!

我们学完这些,根本上来说二维数组就可以相当于一级数组指针的数组了!

C语言:指针详解【图解 + 练习】,C语言学习,c语言,指针,数组指针,指针数组,二维数组名,一维数组名,取地址数组名

数组和指针拓展知识

  • a[ i ] = *( a + i )
  • b[ x ][ y ] = *( b[ x ] + y ) = *( *( b + x ) + y )

五、数组指针

终于来到数组指针了!!!!

数组指针,顾名思义:是一种指向数组的指针

我们只讨论一级数组指针,多级数组指针大家有兴趣可以私信我

        我们来思考这样一个问题,既然一个指针是可以指向整个数组的,并且指针是存放地址的变量,那数组指针是如何做到指向整个数组的呢?

        其实不难理解,我只要存放整个数组的地址就可以了呀,那如何存放数组的地址呢?别忘了&数组名代表的就是整个数组的地址哦!而&数组名中的数组名是首元素地址,但是对首元素地址取地址,那不就相当于一个二级指针了吗?既然这样,数组指针就相当于一个二级指针,那二维数组名,实际上也相当于一个二级指针,这也是为什么数组指针和二维数组名拿元素要解引用两次的原因

        但是解引用要涉及到数据类型,那数组的数据类型又是什么呢?

int arr[5] = {1,2,3,4,5};
int (*parr) [5] = &arr;

        提到这里就不得不拓展一个知识点,int arr[5]是一个数组,那这个数组的类型是什么呢?大多数人都没有去研究过吧,我们不妨可以通过以往的经验来看

        比如 int a 的 a是一个变量名,a 的类型是 int ,double d 的 d是一个变量名,类型是double;那int arr[ 5 ]的变量名是什么呢?没有变量名,一定有数组名!所以数组名是arr,那数据类型是int [5] ;这表示这个变量arr是一个数组类型,是一个有5个int类型的数组。

        因为解引用和加法是涉及到类型的问题,所以我们必须要明白数组指针的数据类型是什么,虽然我上面说了数组指针是相当于二级指针的,但是仅仅是为了让我们来理解 解引用2次的原因。

        那到底数组指针的数据类型到底是什么呢?

        首先依旧是拿出数组名parr,剩下的就是数据类型:int (*) [5],这个的意思就是为一个数组的指针类型,但是这里还有数组元素的个数,只有知道元素个数,解引用的时候才知道拿出来多少字节,加的时候才知道移动多少字节。

        *表示这是一个指针,int 表示 元素类型,而[5]表示有多少个元素;

对于加法:数组指针移动的是整个数组的大小;

对于解引用:作者目前没有搞懂深层,但是有一种方法简单易懂:

        因为parr 是 &arr,那 *parr 就是 *&arr, * 和 & 相互抵消了,就是arr,这样我们也就是可以理解为啥是指针降级了。

        所以*parr == arr,那对*parr的解引用或者是加法,就是对arr来的。

六、总结

        其实我们对指针和数组这里的考点基本都是在解引用和指针➕整数这里出题,因为对于学C的大家,这里算是难题了,它往往可以伴随着强制类型转换,隐式类型转换和大小端字节序等多方面出题,但是万变不离其宗,你只要弄清是啥数据类型就OK,仔细画图就一目了然了。

        最后给大家推荐一下我的C语言刷选择题的专栏,这里是我在牛客网上精选出来的题,里面有我的个人解析,如有错误,请大家指正,有不懂的不会的可以私信哦!

https://blog.csdn.net/2302_76941579/category_12492707.html?spm=1001.2014.3001.5482文章来源地址https://www.toymoban.com/news/detail-774532.html

到了这里,关于C语言:指针详解【图解 + 练习】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端学习C语言 - 初级指针

    本篇主要介绍: 指针和变量的关系 、指针类型、 指针的运算符 、空指针和野指针、 指针和数组 、 指针和字符串 、const 和指针、以及 gdb 调试段错误 。 指针是一种特殊的变量。存放地址的变量就是指针。 int num = 1; 会申请4个字节的内存来存放数字1,每次访问 num 就是访问

    2024年02月10日
    浏览(43)
  • C语言学习系列-->看淡指针(3)

    在指针的类型中我们知道有⼀种指针类型为字符指针 char* 一般使用: 进阶使用 本质是把字符串 hello ⾸字符的地址放到了pstr中。 把⼀个常量字符串的⾸字符 h 的地址存放到指针变量 pstr 中。 经典例题: 运行结果: 这⾥str3和str4指向的是⼀个同⼀个常量字符串。C/C++会把常量

    2024年02月11日
    浏览(43)
  • C语言-基础语法学习-3 二级指针

    当涉及到多级指针时,C语言的灵活性和强大的指针功能可以得到充分的发挥。二级指针是指指向指针的指针,也被称为指向指针的引用。 使用二级指针可以实现以下功能: 动态内存分配:通过二级指针可以动态地分配内存块,并将其地址传递给其他函数或模块进行操作。这

    2024年02月12日
    浏览(45)
  • luatOS网站 lua语言学习 练习题

    lua 教程跳转链接,练习题都来自这里 题目:如果已知number变量n,那么如果需要判断n是否符合下面的条件: 3n≤10 以下四行判断代码,正确的是? (返回true即表示变量n符合要求) 你需要使用前面几章的知识,来完成下面的题目 已知三个number类型的变量a、b、c,分别代表三

    2024年02月06日
    浏览(40)
  • C语言指针入门学习、知识点梳理(四)

    本篇内容:指针星号的三种含义以及指针在函数调用时,与实参、形参的变量传递关系,如何通过被调函数修改主调函数普通变量的值。 传送门: C语言指针入门学习、概念梳理(一) C语言指针入门学习、概念梳理(二) C语言指针入门学习、知识点梳理(三) C语言指针入门

    2024年02月09日
    浏览(44)
  • C语言学习笔记:数组

    ✨博文作者:烟雨孤舟 💖 喜欢的可以 点赞 收藏 关注哦~~ ✍️ 作者简介: 一个热爱大数据的学习者 ✍️ 笔记简介:作为大数据爱好者,以下是个人总结的学习笔记,如有错误,请多多指教! 目录 ​​​​​​​ 简介 数组声明 数组初始化 访问数组元素 多维数组 二维数组

    2024年02月09日
    浏览(56)
  • C语言学习分享(第六次)------数组

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C语言学习分享⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习更多C语言知识   🔝🔝 啊~~,很久没有更新C语言知识了,各位久等了,本篇文章在了解了数组的基本知识后, 着重于给大家实现两个小游戏:三子棋和扫雷

    2024年02月03日
    浏览(63)
  • 【C语言】从零开始学习数组

    💓博客主页:江池俊的博客 ⏩收录专栏:C语言初阶之路 👉其他专栏:数据结构探索 💻代码仓库:江池俊的代码仓库 🎪 社区:GeekHub社区 (欢迎大家加入与我一起探讨学习经验) 🍁 如果觉得博主的文章还不错的话,请点赞👍收藏🌟 三连支持一下博主💞 目录 一、一维数

    2024年02月15日
    浏览(52)
  • C语言-指针进阶-qsort函数的学习与模拟实现(9.3)

    目录 思维导图: 回调函数 qsort函数介绍 模拟实现qsort 写在最后: 什么是回调函数? 回调函数是一个通过函数指针调用的函数。 将一个函数指针作为参数传递给一个函数,当这个指针被用来调用所指向函数时, 我们就将此称为回调函数。 在举例之前,我们先学习一个C语言

    2024年02月15日
    浏览(55)
  • perl脚本语言学习1——基础篇:变量、数组、哈希数组、循环、文件、函数

    2023.3.18 今天下载虚拟机把电脑磁盘内容弄到乱七八糟,难受 发现每次学习遇到一个坎,感觉面前是一座大山,越过去之后又对前途充满了希望 perl:practical extraction report language 实用提取和报表语言 从字面上看主要与文本处理相关 变量定义: my 存储 数字、字符、字符

    2024年02月12日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包