C语言知识补充 --来自菜鸟教程的指针复习
1.system
打开其他应用
1.指针演练 C 指针、
正如您所知道的,每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。
#include <stdio.h> int main ()
{
int var_runoob = 10;
int *p; // 定义指针变量
p = &var_runoob; printf("var_runoob 变量的地址: %p\n", p);
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
var_runoob 变量的地址: 0x7ffeeaae08d8
什么是指针?
指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
type* var_name;
int *ip; /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */
如何使用指针?
使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。下面的实例涉及到了这些操作:
#include <stdio.h> int main ()
{
int var = 20; /* 实际变量的声明 */
int *ip; /* 指针变量的声明 */ ip = &var; /* 在指针变量中存储 var 的地址 */ printf("var 变量的地址: %p\n", &var ); /* 在指针变量中存储的地址 */
printf("ip 变量存储的地址: %p\n", ip ); /* 使用指针访问值 */
printf("*ip 变量的值: %d\n", *ip ); return 0;
}
var 变量的地址: 0x7ffeeef168d8
ip 变量存储的地址: 0x7ffeeef168d8
*ip 变量的值: 20
C 中的 NULL 指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。
NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:
#include <stdio.h> int main ()
{
int *ptr = NULL; printf("ptr 的地址是 %p\n", ptr ); return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
ptr 的地址是 0x0
在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。
如需检查一个空指针,您可以使用 if 语句,如下所示:
C 指针详解
在 C 中,有很多指针相关的概念,这些概念都很简单,但是都很重要。下面列出了 C 程序员必须清楚的一些与指针相关的重要概念:
C 指针的算术运算
C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。
假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:
ptr++
在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。
我们概括一下:
- 指针的每一次递增,它其实会指向下一个元素的存储单元。
- 指针的每一次递减,它都会指向前一个元素的存储单元。
- 指针在递增和递减时跳跃的字节数取决于指针所指向变量数据类型长度,比如 int 就是 4 个字节。
递增一个指针
我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量。下面的程序递增变量指针,以便顺序访问数组中的每一个元素:
#include <stdio.h> const int MAX = 3; int main ()
{
int var[] = {10, 100, 200};
int i, *ptr; /* 指针中的数组地址 */
ptr = var;
for ( i = 0; i < MAX; i++)
{ printf("存储地址:var[%d] = %p\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr ); /* 指向下一个位置 */
ptr++;
}
return 0;
}
函数指针
函数指针是指向函数的指针变量。
通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。
函数指针可以像一般函数一样,用于调用函数、传递参数。
函数指针变量的声明:
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
#include <stdio.h> int max(int x, int y)
{
return x > y ? x : y;
} int main(void)
{
/* p 是函数指针 */
int (* p)(int, int) = & max; // &可以省略
int a, b, c, d; printf("请输入三个数字:");
scanf("%d %d %d", & a, & b, & c); /* 与直接调用函数等价,d = max(max(a, b), c) */
d = p(p(a, b), c); printf("最大的数字是: %d\n", d); return 0;
}
回调函数
函数指针作为某个函数的参数
函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
简单讲:回调函数是由别人的函数执行时调用你实现的函数。
以下是来自知乎作者常溪玲的解说:
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
实例
实例中 populate_array() 函数定义了三个参数,其中第三个参数是函数的指针,通过该函数来设置数组的值。
实例中我们定义了回调函数 getNextRandomValue(),它返回一个随机值,它作为一个函数指针传递给 populate_array() 函数。
populate_array() 将调用 10 次回调函数,并将回调函数的返回值赋值给数组。
#include <stdlib.h>
#include <stdio.h> void populate_array(int *array, size_t arraySize, int (*getNextValue)(void))
{
for (size_t i=0; i<arraySize; i++)
array[i] = getNextValue();
} // 获取随机值
int getNextRandomValue(void)
{
return rand();
} int main(void)
{
int myarray[10];
/* getNextRandomValue 不能加括号,否则无法编译,因为加上括号之后相当于传入此参数时传入了 int , 而不是函数指针*/
populate_array(myarray, 10, getNextRandomValue);
for(int i = 0; i < 10; i++) {
printf("%d ", myarray[i]);
}
printf("\n");
return 0;
}
C语言知识补充 --来自菜鸟教程的指针复习的更多相关文章
- Http状态码大全(来自菜鸟教程)
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是因特网上应用最为广泛的一种网络传输协议,所有的WWW文件都必须遵守这个标准. HTTP是一个基于TCP/IP通信 ...
- C语言经典例题(菜鸟教程100例)
学习c语言基础,怎么能少了菜鸟教程上的100道例题呢,这里整理一下每道题的链接,希望大家能享受学习的乐趣 1,有1,2,3,4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 2,企业发放 ...
- 菜鸟教程 Python100例 之实例29
学习编程的路,走得好艰辛... 为了巩固基础知识,把菜鸟教程网上的实例拿来练习.. 在做到实例29时,看了网站给出的代码,觉得可以加强一下功能,不由得动了一下脑筋,如下: 原文题目: 题目:给一个不多 ...
- 曹工说Redis源码(2)-- redis server 启动过程解析及简单c语言基础知识补充
文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ...
- 用汇编语言(ARM 32位)编写TCP Bind Shell的菜鸟教程
用汇编语言(ARM 32位)编写TCP Bind Shell的菜鸟教程 来源 https://www.4hou.com/info/news/9959.html Change 新闻 2018年1月19日 ...
- 学习笔记之C# 教程 | 菜鸟教程
C# 教程 | 菜鸟教程 http://www.runoob.com/csharp/csharp-tutorial.html 菜鸟教程在线编辑器 http://www.runoob.com/try/r ...
- 关于C语言知识调查
因为上一篇随笔对这一部分写得不够清楚,因此在这篇做一些补充. 你是怎么学习C语言的? 起初,对于C语言的学习主要是通过老师课堂的教学,完成相关的课后作业.与我的技能相比的话,他们都有一个共同点需要去实 ...
- 菜鸟教程之学习Shell script笔记(下)
菜鸟教程Shell script学习笔记(下) 以下内容是学习菜鸟教程之shell教程,所整理的笔记 菜鸟教程之shell教程:http://www.runoob.com/linux/linux-sh ...
- 菜鸟教程之学习Shell script笔记(上)
菜鸟教程之学习Shell script笔记 以下内容是,学习菜鸟shell教程整理的笔记 菜鸟教程之shell教程:http://www.runoob.com/linux/linux-shell.ht ...
- Android知识补充(Android学习笔记)
Android知识补充 ●国际化 所谓的国际化,就是指软件在开发时就应该具备支持多种语言和地区的功能,也就是说开发的软件能同时应对不同国家和地区的用户访问,并针对不同国家和地区的用户,提供相应的.符合 ...
随机推荐
- MySQL57 zip安装
引用:MySQL5.7的.zip文件的配置安装 由于MySQL5.7之后在javaEE中交互的端口发生了变化,而MySQL官网中5.6.5.7版本64位的只有.zip文件,而.zip文件不像直接下 ...
- 【Linux】/proc/stat解析
一. 概述 1.1 CPU时间 cpu指标 含义user 用户态时间nice 用户态时间(低优先级,nice>0)system 内核态时间idle 空闲时间iowait I/O等待时间irq 硬 ...
- 记一次 .NET 某工控软件 内存泄露分析
一:背景 1.讲故事 上个月 .NET调试训练营 里的一位老朋友给我发了一个 8G 的dump文件,说他的程序内存泄露了,一时也没找出来是哪里的问题,让我帮忙看下到底是怎么回事,毕竟有了一些调试功底也 ...
- v-model双向绑定原理
1 <div id="app"> 2 <div>{{msg}}</div> 3 <!-- 写法1 --> 4 <input t ...
- MongoDB安全加固,防止数据库攻击删除勒索威胁
前言: 今天发现前段时间自己搭建的一个系统的MongoDB数据找不到了,觉得很奇妙,然后登上MongoDB数据库发现多了一个名为READ__ME_TO_RECOVER_YOUR_DATA的数据库,里面 ...
- 东拼西凑学java
前言 随着大环境的影响,互联网寒冬降临,程序员的日子越来越难,搞不好哪天就被噶了,多学点东西也没啥坏处,国内市场java如日中天,出门在外不会写两行java代码,都不好意思说自己是程序员,伪装成一个萌 ...
- 前段知识之CSS
目录 CSS层叠样式表 CSS语法结构: CSS注释语法 引入css的多种方式 CSS选择器 1. CSS基本选择器 2. CSS组合选择器 3. 分组与嵌套 4. 属性选择器 5. 伪类选择器 6. ...
- MongoDB - 副本集简介
简介 在 MongoDB 中,副本集指的是一组 MongoDB 服务器实例掌管同一个数据集,实例可以在不同的机器上. 其中一个用于处理写操作的是主节点(Primary),还有多个用于保存主节点的数据副 ...
- 线性方程组的直接解法——Gauss消去法
考虑线性方程组 \[\mathrm{A}x=\mathrm{b} \] 其中,\(\mathrm{A}=(a_{ij})_{n\times n}\),\(\mathrm{b}=[b_1,b_2,\cd ...
- 【运维笔录】局域网实现HTTPS访问,只需Nginx + mkcert
1)下载安装mkcert wget -O mkcert https://github.com/FiloSottile/mkcert/releases/download/v1.4.3/mkcert-v1 ...