Coursera课程笔记----C程序设计进阶----Week 4
指针(一) (Week 4)
什么是“指针”
互联网上的资源——地址
当获得一个地址,就能得到该地址对应的资源,所以可以把“网址”称为指向资源的“指针”
内存中的位置——地址
- 变量的三要素:变量的地址,变量的值,变量的名字
- 通常把某个变量的地址称为“指向该变量的指针”
如何拿到or看到一个变量的地址
- 可以利用 取地址运算符“&” 实现
- cout<<&c<<endl; //结果:0041FE24
- cout<<sizeof(&c)<<endl; //结果:4
- 可以利用 取地址运算符“&” 实现
变量地址(指针)的作用
我们可以通过资源地址(指针)访问网络资源
计算机通过变量地址(指针)操作变量
可以用指针运算符*实现
cout<<*&c<<endl; // 等价于cout<<c<<endl;
什么是“指针变量”
- 我们可以设置一个变量,来存放网络资源的地址
- 我们可以设置一个变量,来存放变量的地址(指针)
指针变量
专门用于存放指针(某个变量地址)的变量
- 例:若指针pointer为指针变量,且存储着变量c的指针(地址),则称pointer为指向变量c的“指针变量”
定义一个指针变量
int *****pointer;
指针变量的基类型/指针运算符pointer的类型/指针变量的名字
基类型:指针变量指向的变量的类型
int c = 76;
int *pointer; //定义名字为pointer的指针变量
pointer = &c; //将变量c的地址赋给指针变量pointer;
//赋值后,称指针变量pointer指向了变量c
- 使用指针变量
- 既然指针变量中存放的是“某个变量的地址”,可否通过“指针变量”访问“它所指向的变量”呢?
- 可以用指针运算符*****实现
int c = 76;
int *pointer = &c;
//*pointer为“pointer所指向的存储单元的内容”————也就是变量c
- 一些说明
- 指针变量也是变量,是变量就有地址
- &与*的运算符优先级比较高(优先级基本上跟着逻辑走就行了)
- 指针变量的++ --
- 根据基类型来确定++和--
- 假设:iPtr当前所存地址是0x00000100
- 若iPtr指向一个整型元素(占4个字节),则iPtr++等于iPtr+1*4 = 0x00000104
- 若iPtr指向一个实型元素(占4个字节),则iPtr++等于iPtr+1*4 = 0x00000104
- 若iPtr指向一个字符元素(占1个字节),则iPtr++等于iPtr+1*1 = 0x00000101
数组与指针
- 指向数组元素的指针
- 指向数组元素和指向普通变量没有区别
- 数组名是数组首元素的地址
- 数组的地址
- 数组名代表数组首元素的地址
- 数组名相当于指向数组第一个元素的指针
- 数组名不是变量,不能赋值
- 利用指针变量引用数组元素
- 若定义
- 数组int a[10]; 指针int *pointer;
- 则:
- pointer = a; 等价于pointer = &a[10];
- 数组访问:
- pointer + i ; 等价于a + i; 等价于&a[i];
- *(pointer + i) 等价于*(a+i)等价于a[i];
- 表示形式
- pointer[i] 等价于*(pointer + i)
- 若定义
- 需要注意的问题
- int *p = &a[0]
- a++是没有意义的,但p++会引起p变化
- p可以指向数组最后一个元素以后的元素
- 所以指针做加减运算时一定注意有效的范围
- int *p = &a[0]
- 指向二维数组的指针
- 因为存储方式是把二维数组“拉直”,所以使用方法和一位数组区别不大
int main()
{
int a[3][4] = {1,3,5,7,9,11,13,15,17,19,21,23};
int _____,i,j; //填空:完成变量p的定义
p = a;
cin >> i >> j;
cout<<setw(4)<<*(*(p+i)+j); //正误判断,访问元素a[i][j]
return 0;
}
从p = a开始
- a相当于指向a[3][4]的“第一个元素”的指针
- 所谓“第一个元素”是指一个”包含4个int型元素的一维数组“
- 所以,a相当于一个”包含4个int型元素的一维数组“的地址
- 因此,p的基类型是:“包含4个int型元素的一维数组”
问题:如何定义一个指向 “包含4个int型元素的一维数组”的指针变量?
答案:变量定义语句:int (*p)[4];
*(*(p+i)+j)是什么?
- p指向一个“包含4个int型元素的一维数组”
- p+i是第i+1个“包含4个int型元素的一维数组”的地址
- p + i 等价于&a[i];
- *(p+i)等价于a[i];
- *(p+i)+j等价于 a[i] + j
- 因为:a[i] + j 等价于&a[i][j]
- *(*(p+i)+j)等价于a[i][j]
- 结果正确
详解
指针变量可以指向一维数组中的元素,当然也就可以指向二维数组中的元素。但是在概念和使用方法上,二维数组的指针比一维数组的指针要复杂一些。要理解指针和二维数组的关系首先要记住一句话:二维数组就是一维数组,这句话该怎么理解呢?
假如有一个二维数组:
int a[3][4] = {{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}};
其中,a 是二维数组名。a 数组包含 3 行,即 3 个行元素:a[0],a[1],a[2]。每个行元素都可以看成含有 4 个元素的一维数组。而且 C 语言规定,a[0]、a[1]、a[2]分别是这三个一维数组的数组名。如下所示:
a[0]、a[1]、a[2] 既然是一维数组名,一维数组的数组名表示的就是数组第一个元素的地址,所以 a[0] 表示的就是元素 a[0][0] 的地址,即 a[0]&a[0][0];a[1] 表示的就是元素 a[1][0] 的地址,即 a[1]&a[1][0];a[2] 表示的就是元素 a[2][0] 的地址,即 a[2]==&a[2][0]。
所以二维数组a[M][N]中,a[i]表示的就是元素a[i][0]的地址,即(式一):
a[i] == &a[i][0];
我们知道,在一维数组 b 中,数组名 b 代表数组的首地址,即数组第一个元素的地址,b+1 代表数组第二个元素的地址,…,b+n 代表数组第 n+1 个元素的地址。所以既然 a[0]、a[1]、a[2]、…、a[M–1] 分别表示二维数组 a[M][N] 第 0 行、第 1 行、第 2 行、…、第 M–1 行各一维数组的首地址,那么同样的道理,a[0]+1 就表示元素 a[0][1] 的地址,a[0]+2 就表示元素 a[0][2] 的地址,a[1]+1 就表示元素 a[1][1] 的地址,a[1]+2 就表示元素 a[1][2] 的地址……a[i]+j 就表示 a[i][j] 的地址,即(式二):
a[i]+j == &a[i][j];
将式一代入式二得(式三):
&a[i][0]+j == &a[i][j]
在一维数组中 a[i] 和 *(a+i) 等价,即(式四):
a[i] == *(a+i);
这个关系在二维数组中同样适用,二维数组 a[M][N] 就是有 M 个元素 a[0]、a[1]、…、a[M–1] 的一维数组。将式四代入式二得(式五):
*(a+i)+j == &a[i][j];
由式二和式五可知,a[i]+j 和 *(a+i)+j 等价,都表示元素 a[i][j] 的地址。
上面几个公式很“绕”,理清楚了也很简单,关键是把式二和式五记住。
习题选解
注:只分析较难的答案,不代表是唯一的答案
- 有double num = 3.14; double * pi = & num; 现在pi指向的地址的内容为3.14。然而我们又想要提高精度,将它变成3.14159。在不考虑代码优美性、易读性的情况下,以下操作正确的有哪些?
✅ pi[0] = 3.14159
解析:虽然pi看上去不是指向数组,但确实可以通过pi[0]引用到我们需要修改的数。但是,这不是一种良好的代码风格,因为一旦使用pi[1]就会出现不可预料的后果。
- 已知字符串char str[] = "hello,world"; 现在我们想输出字符串的后半部分,即",world",以下操作正确的包括哪些?
✅cout << str + 5 << endl;
解析:str+5指向',',并且是字符指针,对它使用cout,输出从str+5开始的字符串
以下函数的输出结果是:
int fun( ){
char a[10] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 0}, *p;
int i = 8;
p = a + i;
cout << p - 3 << endl;
return 0;
}
✅ 6789
解析:p - 3指向a+5,即内容为'6'的那个地址。由于p-3为字符指针,所以使用cout时输出字符串,以0(即'\0')结尾
4.对于基类型相同的两个指针变量之间,以下哪一项操作缺乏有价值的语义?
✅ +
Coursera课程笔记----C程序设计进阶----Week 4的更多相关文章
- Coursera课程笔记----C程序设计进阶----Week 5
指针(二) (Week 5) 字符串与指针 指向数组的指针 int a[10]; int *p; p = a; 指向字符串的指针 指向字符串的指针变量 char a[10]; char *p; p = ...
- Coursera课程笔记----C程序设计进阶----Week 3
函数的递归(Week 3) 什么是递归 引入 函数可以嵌套调用:无论嵌套多少层,原理都一样 函数不能嵌套定义:不能在一个函数里再定义另一个函数,因为所有函数一律平等 问题:一个函数能调用它自己吗? 举 ...
- Coursera课程笔记----C程序设计进阶----Week 1&2
C程序中的函数(Week 1&2) 函数 函数的定义 对函数的普遍认识:y=f(x) C语言中的常用函数: 平方根: r = sqrt(100.0) 底数x的y次幂:k = pow(x,y) ...
- Coursera课程笔记----C++程序设计----Week3
类和对象(Week 3) 内联成员函数和重载成员函数 内联成员函数 inline + 成员函数 整个函数题出现在类定义内部 class B{ inline void func1(); //方式1 vo ...
- 操作系统学习笔记----进程/线程模型----Coursera课程笔记
操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...
- Coursera课程笔记----Write Professional Emails in English----Week 3
Introduction and Announcement Emails (Week 3) Overview of Introduction & Announcement Emails Bas ...
- Coursera课程笔记----Write Professional Emails in English----Week 1
Get to Know Basic Email Writing Structures(Week 1) Introduction to Course Email and Editing Basics S ...
- Coursera课程笔记----计算导论与C语言基础----Week 6
理性认识C程序 导论(Week 6) 明确学习进度 讲课内容 感性➡️理性➡️函数➡️指针等 作业练习 初级阶段 ➡️正常作业练习 C语言的由来 程序设计语言的分类 低级语言之机器语言 0010101 ...
- Coursera课程笔记----计算导论与C语言基础----Week 4
感性认识计算机程序(Week 4) 引入 编程序 = 给计算机设计好运行步骤 程序 = 人们用来告诉计算机应该做什么的东西 问题➡️该告诉计算机什么?用什么形式告诉? 如果要创造一门"程序设 ...
随机推荐
- python填写金数据
''' 将 main 中的{url}改为真 url 将 setd_data中 {姓名} {纬度} {经度} {地址} 改为确切数据 数据自行参考post 结果判断基于响应中是否包含“谢谢参与”字样 ' ...
- 小说光看还不够?用Python做有声小说!
文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http:// ...
- Daily Scrum 12/14/2015
Progress: Dong&Minlong: 基于Oxford Speech API成功实现语音输入的功能,但由于服务器存在访问次数的限制(每分钟6次),所以暂不准备将此功能加入ALPHA版 ...
- [转]ThinkCMF框架任意内容包含漏洞分析复现
0x00 简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建.ThinkCMF提出灵活的应用机制,框架自身提供基础的管理功能,而开发者可以 ...
- 二叉树中两节点的最近公共父节点(360的c++一面问题)
面试官的问题:写一个函数 TreeNode* Find(TreeNode* root, TreeNode* p, TreeNode* q) ,返回二叉树中p和q的最近公共父节点. 本人反应:当时有点 ...
- Android | 教你如何快速集成机器学习能力
背景 继上篇博文说了如何快速集成扫码以后 我又上官网去了解了一下其他的功能,其中机器学习服务是当下比较火的,而且还是免费的.就赶紧点进去学习一下.看看能够快速实现哪些功能. 链接在这里:https ...
- tp5--开发规范
在日常开发的过程中,写代码都要有一定的规范,不然可读取就太差了,所以为了以后的维护.对接,好的代码规定是必须的. 以下是我自己对自己提出的要求: 全部: 1) 每个方法都要写好备注(@retrun作 ...
- Django ORM 查询表中某列字段值
场景: 有一个表中的某一列,你需要获取到这一列的所有值,你怎么操作? 解决办法: 有一个model为:Event 方式一: 获取内容: Event.objects.values('title') 输出 ...
- 总结:js世界中的特殊符号
常用符号:+ ++ - -- || / /' && 等 这些基本上每天都能用到,但是 js 世界中有些特殊符号是不常用的,我也是偶然在阅读大神代码的时候发现的,一番查找之后得出了以下结 ...
- weblogic补丁升级详细步骤,18.7.17补丁更新
weblogic打补丁 到weblogic官网下载补丁包 对应的补丁包 如: p22248372_1036012_Generic.zip 一 安装补丁步骤 1.登录linux的weblogic用户 ...