人人都能学会的编程入门课
胡光
原百度高级算法研发工程师
19410 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 38 讲
开篇词 (1讲)
人人都能学会的编程入门课
15
15
1.0x
00:00/00:00
登录|注册

08 | 指针系列(二):记住,指针变量也是变量

你好,我是胡光,咱们又见面了,上节课中,我们介绍了结构体相关的基础知识,也介绍了指针变量,并且教给你了最重要的一句话“指针变量也是变量”。这句话的意思在于告诉你,所有你对变量的理解,都可以放到指针变量上,例如:变量有类型,变量有大小,变量里面的值支持某些操作等等。今天呢,我们就来详细地聊一下指针变量。

任务回顾

在正式开始之前,我们先来回顾一下上节课的任务内容:
上节课我们说,如果给我们如下 Data 结构体类型,这个类型中有两个整型数据字段 x,y:
struct Data {
int x, y;
} a[2];
那么请用尽可能多得形式,替换下面代码中 &a[1].x 的部分,使得代码效果不变:
struct Data *p = a;
printf("%p", &a[1].x);
你会看到,如上代码中,就是输出 a[1].x 的地址值。
通过上节的学习,你现在已经掌握了关于结构体的相关知识,也初步地接触了“指针变量也是变量”的这个概念,今天就让我们再深入了解指针变量吧。

必知必会,查缺补漏

1. 深入理解:指针变量的类型

还记得我们是如何定义 p 变量的么?代码语句是:
int *p
之前我们介绍了,语句中的 * 代表 p 变量是一个指针变量,而 int 的作用是什么呢?只是用来说明 p 是一个指向整型存储区的指针变量么?其实 int 更大的作用,就是用来解决我们上面提到的那个问题,根据 p 变量中的内容,我们可以找到一个存储区的首地址,然后再根据 p 的类型,就可以确定要取几个字节中的内容了。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文深入探讨了指针变量的重要概念和与数组的关系。首先,指针变量的类型决定了取值时的字节长度和在加减法运算中的地址长度,而不同类型的指针占用的存储空间大小是相等的。其次,文章介绍了指针变量与数组的关系,指出数组名代表数组的首地址,可以用指针变量来存储,并且通过指针变量和数组名进行加法运算可以达到相同的效果。最后,强调了在编程中,多种等价表示都是有效的,需要重视这些等价表示的学习。整体而言,本文通过深入浅出的方式,帮助读者理解了指针变量的重要概念和与数组的关系,为读者提供了一份技术上的详细指南。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《人人都能学会的编程入门课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(22)

  • 最新
  • 精选
  • 徐洲更
    同样也有@大牛凯一样疑惑,不过不只是针对指针,而是所有数据类型。C语言是如何存放类型信息呢?对于`int a`而言,使用`a="123"`将字符串赋值给整型是会出问题的。这种类型错误的底层原理是啥呢?是不是C语言会划定一些区域,用来存放不同类型的变量呢?

    作者回复: 类型信息会被转换成相关的汇编代码。这个当中涉及到两件事情:一个是类型检查,这个是在编译阶段就做完了,另一个就是具体的程序运行,而运行阶段就已经没有了类型信息。也就是说,你所谓的出错,是在编译阶段报的错误。这个问题,你可以往后看,看到预处理命令一节的时候,可能就会认识的更清晰了。

    2020-01-23
    2
    6
  • Geek_7c47de
    老师你好,我有个小问题。 你在本节课中所举例子 0x61626364 为什么指针指向的的第一个字节不是0x61而是0x64呢?

    作者回复: 指针也有可能指向0x61,这个跟操作系统有关系,大端系统和小端系统的区别。我们一般的都是小端系统,数字的低位存储在低地址位,所以指针指向0x64。

    2020-06-29
    3
  • Noya
    #include <iostream> using namespace std; struct Date { int x, y; } a[2]; int main(void) { struct Date *p = a; printf("%p\n", &a[1].x); printf("%p\n", &(a + 1)->x); // 方法1, 效果和上面一样 printf("%p\n", &(a[0].y) + 1); // 定位到 a[0].y, 然后+1就是a[1].x的地址了 printf("%p\n", &(p + 1)->x); printf("%p\n", &(p->y) + 1); return 0; } 老师 这是我的思路

    作者回复: 不错!很棒!能把指针理解运用到这个程度,今后绝大多数和指针相关的问题,你基本就都可以自己理解和解决了。d(^_^o)

    2020-05-03
    2
    3
  • 罗耀龙@坐忘
    茶艺师学编程 老师,在我windows DEV环境里,写 int a , *p = &a; char *q = &a; 提示错误,说是int型与char型用在a上有冲突。

    作者回复: 这个和编程环境没关系,主要是&a 返回的地址类型和指针类型不匹配导致的。你进行强制类型转换就好了。语法类似于: char *q=(char *)&a; 这样就把 int *类型的地址,转换成了 char *类型的地址

    2020-05-19
    5
    2
  • rocedu
    把内存抽象成字节数组,上面内容就更容易理解了,总结的真好!

    作者回复: ^_^

    2020-02-10
    2
  • LJK
    老师好,请教一个问题,所有指针如果都是无差别存储地址的话,那拿到一个指针如何判断它的类型呢?整数型和字符型指针中,“整数”和“字符”这两个类型是存放在哪的呢?

    作者回复: 这个信息已经转换成了相关的汇编代码,你想想,指针的类型是不是只有在加减运算和取值操作的时候有用?那么转换成汇编的时候,只需要对这两个操作,做针对性的转换即可。

    2020-01-23
    2
    2
  • Jackie
    关于变量类型的区分,我的理解是在代码里声明了int a之后,编译的词法分析阶段会查表,把int对应的4这个大小对源码做转换,比如对一个int *p变量来说,p+1的源码,编译后会变成p的地址加上1*4这里的1是源码里p+1的1,4是int类型查表得到的4,关于类型的静态检查,这样理解对吗?

    作者回复: 完全正确!程序一旦编译完成以后,就没有了类型的概念。

    2020-06-20
    1
  • 三件事
    int main(int argc, char const *argv[]) { int i = 0; int arr[3] = {0}; for (; i <= 3; i++) { arr[i] = 0; printf("Hello world\n"); } return 0; } 老师,这是之前在争哥的数据结构之美中遇到的一个问题,说是 printf 会被执行无数次,原因是数组越界后,c 可以访问任意的内存地址。但在这个例子里,arr[i] 越界后又正好访问到 i = 0 的地址,所以会无限循环。 我自己试了下,并没有出现循环,而是打印了四次之后就中断了。 libsystem_kernel.dylib`__pthread_kill: 0x7fff64f437f0 <+0>: movl $0x2000148, %eax ; imm = 0x2000148 0x7fff64f437f5 <+5>: movq %rcx, %r10 0x7fff64f437f8 <+8>: syscall -> 0x7fff64f437fa <+10>: jae 0x7fff64f43804 ; <+20> 0x7fff64f437fc <+12>: movq %rax, %rdi 0x7fff64f437ff <+15>: jmp 0x7fff64f3da89 ; cerror_nocancel 0x7fff64f43804 <+20>: retq 0x7fff64f43805 <+21>: nop 0x7fff64f43806 <+22>: nop 0x7fff64f43807 <+23>: nop 所以请问下老师,数组越界后内存到底是怎么访问的?上面这个例子是恰好无限循环了吗?

    作者回复: 这个例子不太严谨,越界以后能否访问到i,取决于操作系统中系统栈的增长方向。大多数的操作系统中,确实会死循环,在某些版本的操作系统中,这个程序就不会死循环。 数字越界后,还是正常的访问,没啥特殊的。arr[1]就是从数组的首地址向后跳跃1个元素长度所到的元素位置,arr[100]就是跳跃100个元素长度。具体跳到哪里,根据指针的加法运算规则计算即可,你可以先往后看完指针相关知识以后再回来理解你说的这个问题。否则,很难跟你解释。(。ì _ í。)

    2020-04-15
    1
  • 1043
    不管你住大别墅还是我住小茅屋,写信邮寄的地址格式和信封标准是一样规范的;在Windows系统里一个执行程序还是一个文件所建的快捷方式都是1kB,不管源文件大有多大、是什么类型。需要多理解的是等价表示,理解的等价表示方法越广泛越有深度对他人的表示方法兼容性就越强。兼容性强不管是维护他人的代码还是领导他人做事,都很容易建立权力影响关系。

    作者回复: d(^_^o)

    2020-04-05
    1
  • 郑江北
    老师,我有个疑问,由于我是半路出家的,我自学的java了解java里面的变量,C中这个指针变量的作用是什么我一直有疑惑,比如定义一个int型变量a,那么我用变量名就可以做到赋值和取值,为什么要去用指针呢?还是说指针是存储的内存地址更直接一些,或者说更高效一些呢?

    作者回复: 不是效率问题,而是功能问题,很多功能实现,传统的变量无法做到,需要依靠在处理过程中传递变量原本的地址才能做到。

    2020-03-17
    1
收起评论
显示
设置
留言
22
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部