1.system

打开其他应用

1.指针演练  C 指针、

正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。

  1. #include <stdio.h>
  2.  
  3. int main ()
  4. {
  5. int var_runoob = 10;
  6. int *p; // 定义指针变量
  7. p = &var_runoob;
  8.  
  9. printf("var_runoob 变量的地址: %p\n", p);
  10. return 0;
  11. }

当上面的代码被编译和执行时,它会产生下列结果:

  1. var_runoob 变量的地址: 0x7ffeeaae08d8

什么是指针?

指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

  1. type* var_name;
  1. int *ip; /* 一个整型的指针 */
  2. double *dp; /* 一个 double 型的指针 */
  3. float *fp; /* 一个浮点型的指针 */
  4. char *ch; /* 一个字符型的指针 */

如何使用指针?

使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:

  1. #include <stdio.h>
  2.  
  3. int main ()
  4. {
  5. int var = 20; /* 实际变量的声明 */
  6. int *ip; /* 指针变量的声明 */
  7.  
  8. ip = &var; /* 在指针变量中存储 var 的地址 */
  9.  
  10. printf("var 变量的地址: %p\n", &var );
  11.  
  12. /* 在指针变量中存储的地址 */
  13. printf("ip 变量存储的地址: %p\n", ip );
  14.  
  15. /* 使用指针访问值 */
  16. printf("*ip 变量的值: %d\n", *ip );
  17.  
  18. return 0;
  19. }
  1. var 变量的地址: 0x7ffeeef168d8
  2. ip 变量存储的地址: 0x7ffeeef168d8
  3. *ip 变量的值: 20

C 中的 NULL 指针

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为指针。

NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:

  1. #include <stdio.h>
  2.  
  3. int main ()
  4. {
  5. int *ptr = NULL;
  6.  
  7. printf("ptr 的地址是 %p\n", ptr );
  8.  
  9. return 0;
  10. }

当上面的代码被编译和执行时,它会产生下列结果:

  1. ptr 的地址是 0x0

在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。

如需检查一个空指针,您可以使用 if 语句,如下所示:

if(ptr) /* 如果 p 非空,则完成 */ if(!ptr) /* 如果 p 为空,则完成 */
 
  1.  

C 指针详解

在 C 中,有很多指针相关的概念,这些概念都很简单,但是都很重要。下面列出了 C 程序员必须清楚的一些与指针相关的重要概念:

C 指针的算术运算

C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

  1. ptr++

在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

我们概括一下:

  • 指针的每一次递增,它其实会指向下一个元素的存储单元。
  • 指针的每一次递减,它都会指向前一个元素的存储单元。
  • 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。

递增一个指针

我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:

  1. #include <stdio.h>
  2.  
  3. const int MAX = 3;
  4.  
  5. int main ()
  6. {
  7. int var[] = {10, 100, 200};
  8. int i, *ptr;
  9.  
  10. /* 指针中的数组地址 */
  11. ptr = var;
  12. for ( i = 0; i < MAX; i++)
  13. {
  14.  
  15. printf("存储地址:var[%d] = %p\n", i, ptr );
  16. printf("存储值:var[%d] = %d\n", i, *ptr );
  17.  
  18. /* 指向下一个位置 */
  19. ptr++;
  20. }
  21. return 0;
  22. }

函数指针

函数指针是指向函数的指针变量。

通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。

函数指针可以像一般函数一样,用于调用函数、传递参数。

函数指针变量的声明:

  1. typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
  1. #include <stdio.h>
  2.  
  3. int max(int x, int y)
  4. {
  5. return x > y ? x : y;
  6. }
  7.  
  8. int main(void)
  9. {
  10. /* p 是函数指针 */
  11. int (* p)(int, int) = & max; // &可以省略
  12. int a, b, c, d;
  13.  
  14. printf("请输入三个数字:");
  15. scanf("%d %d %d", & a, & b, & c);
  16.  
  17. /* 与直接调用函数等价,d = max(max(a, b), c) */
  18. d = p(p(a, b), c);
  19.  
  20. printf("最大的数字是: %d\n", d);
  21.  
  22. return 0;
  23. }

回调函数

函数指针作为某个函数的参数

函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。

简单讲:回调函数是由别人的函数执行时调用你实现的函数。

以下是来自知乎作者常溪玲的解说:

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。

实例

实例中 populate_array() 函数定义了三个参数,其中第三个参数是函数的指针,通过该函数来设置数组的值。

实例中我们定义了回调函数 getNextRandomValue(),它返回一个随机值,它作为一个函数指针传递给 populate_array() 函数。

populate_array() 将调用 10 次回调函数,并将回调函数的返回值赋值给数组。

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3.  
  4. void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
  5. {
  6. for (size_t i=0; i<arraySize; i++)
  7. array[i] = getNextValue();
  8. }
  9.  
  10. // 获取随机值
  11. int getNextRandomValue(void)
  12. {
  13. return rand();
  14. }
  15.  
  16. int main(void)
  17. {
  18. int myarray[10];
  19. /* getNextRandomValue 不能加括号,否则无法编译,因为加上括号之后相当于传入此参数时传入了 int , 而不是函数指针*/
  20. populate_array(myarray, 10, getNextRandomValue);
  21. for(int i = 0; i < 10; i++) {
  22. printf("%d ", myarray[i]);
  23. }
  24. printf("\n");
  25. return 0;
  26. }

C语言知识补充 --来自菜鸟教程的指针复习的更多相关文章

  1. Http状态码大全(来自菜鸟教程)

    HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准. HTTP是一个基于TCP/IP通信 ...

  2. C语言经典例题(菜鸟教程100例)

    学习c语言基础,怎么能少了菜鸟教程上的100道例题呢,这里整理一下每道题的链接,希望大家能享受学习的乐趣 1,有1,2,3,4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 2,企业发放 ...

  3. 菜鸟教程 Python100例 之实例29

    学习编程的路,走得好艰辛... 为了巩固基础知识,把菜鸟教程网上的实例拿来练习.. 在做到实例29时,看了网站给出的代码,觉得可以加强一下功能,不由得动了一下脑筋,如下: 原文题目: 题目:给一个不多 ...

  4. 曹工说Redis源码(2)-- redis server 启动过程解析及简单c语言基础知识补充

    文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ...

  5. 用汇编语言(ARM 32位)编写TCP Bind Shell的菜鸟教程

    用汇编语言(ARM 32位)编写TCP Bind Shell的菜鸟教程 来源 https://www.4hou.com/info/news/9959.html Change 新闻 2018年1月19日 ...

  6. 学习笔记之C# 教程 | 菜鸟教程

    C# 教程 | 菜鸟教程 http://www.runoob.com/csharp/csharp-tutorial.html 菜鸟教程在线编辑器 http://www.runoob.com/try/r ...

  7. 关于C语言知识调查

    因为上一篇随笔对这一部分写得不够清楚,因此在这篇做一些补充. 你是怎么学习C语言的? 起初,对于C语言的学习主要是通过老师课堂的教学,完成相关的课后作业.与我的技能相比的话,他们都有一个共同点需要去实 ...

  8. 菜鸟教程之学习Shell script笔记(下)

    菜鸟教程Shell script学习笔记(下) 以下内容是学习菜鸟教程之shell教程,所整理的笔记 菜鸟教程之shell教程:http://www.runoob.com/linux/linux-sh ...

  9. 菜鸟教程之学习Shell script笔记(上)

    菜鸟教程之学习Shell script笔记 以下内容是,学习菜鸟shell教程整理的笔记 菜鸟教程之shell教程:http://www.runoob.com/linux/linux-shell.ht ...

  10. Android知识补充(Android学习笔记)

    Android知识补充 ●国际化 所谓的国际化,就是指软件在开发时就应该具备支持多种语言和地区的功能,也就是说开发的软件能同时应对不同国家和地区的用户访问,并针对不同国家和地区的用户,提供相应的.符合 ...

随机推荐

  1. 更改grub2背景图片

    在/etc/grub/default这里面修改东西然后update-grub来间接修改/boot/grub/grub.cfg中的内容 1.将png图片放进/boot/grub/目录下 2.update ...

  2. 疫情可视化part3

    前言 之前在part2中说的添加自定义主题配色已经开发完成了,除此之外我还添加了一些的3d特效. 前期文章 这是part1的文章:https://blog.csdn.net/xi1213/articl ...

  3. mysql数据库(字段约束条件)

    什么是字段约束 字段约束就是将字段的内容定一个规则,我们要按照规则办事 约束 描述 关键字 非空约束 限制该字段的数据不能为null not null 唯一约束 保证该字段的所有数据都是唯一.不重复的 ...

  4. CH32V307 内部10M网络工程创建流程

    说明: 本次操作是基于目前MRSV1.8.0版本,以及WCH官网CH32V307-V1.8版本的例程操作. MRS链接:http://www.mounriver.com/download CH32V3 ...

  5. Google分布式文件系统GFS论文学习

    GFS作为最著名的分布式文件系统,首先具备了大规模.可扩展.适配大文件.自动运维等高级特性.虽然是比较早期的分布式文件系统,但是它里面的设计思想还是值得现代分布式系统设计参考的,并且还有很多后期著名的 ...

  6. Nacos详解

    Nacos是什么 欢迎来到Nocos的世界! 组成部分 全称 描述 Na naming/nameServer 即服务注册中心,与 Spring Cloud Eureka 的功能类似. co confi ...

  7. python之路33 MySQL 1

    存取数据的演变 1.文本文件 文件路径不固定:C:\aaa.txt D:\bbb.txt E:\ccc.txt 数据格式不统一:jason|123 jason$123 jason 123 2.软件开发 ...

  8. 关系数据库——MySQL

    数据库 1.基本操作 1.1命令行操作 mysql -u username -p+password; --连接数据库 flush privileges; --刷新权限 show databases; ...

  9. UVA12412 A Typical Homework (a.k.a Shi Xiong Bang Bang Mang) 代码

    #include <bits/stdc++.h> #define int long long #define judge(a,func) case a:func();break; usin ...

  10. Coolify系列02-从0到1超详细手把手教你上手Coolify

    接着上集(Coolify系列01- 从0到1超详细手把手教你上手Heroku 和 Netlify 的开源替代方案 ),此时我们已经运行成功,如果没有成功,可以参考我的Coolify系列其他文章来解决问 ...