c缺陷与陷阱 第3章 语义陷阱
1. 指针与数组
c语言中的数组要注意以下两点:
下面的方法存在问题,因为数组的大小必须在编译期作为一个常数确定下来。
a[3][4] 本质也是一个一维数组(包含3个元素),只不过一维数组中的元素是也是数组(包含4个元素)。
int ar[10] = { 0 }; 注意:数组名代表的是整个数组空间。由sizeof(ar)=40 可以体现。
三者的内容相同,但解释是不同的。
&a[0] 针对首个元素取地址。
ar 数组名包含的内容,恰好是数组首元素的地址。但是数组名和数组首元素的地址不能划为等号。
&ar 数组空间的地址
&ar[0] 和ar都是普通的整型指针
这里要明白,&ar实际类型是数组指针
二维数组 (实际没有二维数组,只是一维数组的元素还为数组)
对于二维数组而言,数组名同样表示数组首元素的地址,而ar的首元素还是个
数组,因此,对应的指针也应该是数组指针。
二维数组, int ar[3][4];
ar实质上是一个指针的指针, 即二级指针。
一个指针加一个数, 当然还是指针(即a+1是指针)
取值一个二级指针, 是一级指针(即指针), 所以还是指针, 不过类型发生了变化.
a+1的类型为int * [4].
而*(a+1)的类型则为int *, 也就是平常的指针。
因此,为二维 数组中某一元素赋值用*(*(ar+1)+1)= 100.
2. 非数组的指针
r为指针 即地址。
想往r中拷贝 就需要为r开辟空间。
malloc开辟的空间是10,后面的\0没有空间存储。此时不会报错的
原因是恰好第11个位置没有被占用,如果被占用了就会报错。
为了避免上述问题,开辟的空间加1.
char *r = (char *)malloc(strlen(s)+strlen(t)+1)
同理,要想往 char *name中拷贝就需要为name开辟空间
3. 作为参数的数组声明
(1)
a和b中的值均为数组首元素的地址
int a[5] = {1,2,3,4,5};
printf("%p",a); //打印出的是a的地址
由于整型数组没有结束标记,打印时 只能把a当做地址来打印。
char b[ ] = "hello";
printf(b); //打印出的是字符串 hello
原因:字符数组和字符指针可通过首地址输出整个数组,整形数组却不可以。原因分析如下:
String是一个类,会重载toString()函数,toString()返回其本身。所以直接输出String类的对象会输出具体字符串。而字符型数组在内存中的储存方式同String类一样,因此输出数组名并非输出数组首地址,而是直接输出数组内容直到/0;而整形数组只是整形的集合,所以其数组名仅仅是其首地址,需用for循环输出整个整形数组。
举例:
值分别为40和4
说明数组名和数组首元素地址并不能划为等号,只是数组名的值是首元素地址。
因此不能对数组进行整体赋值。即br = ar不可取。
两个fun函数等价。
在调用函数fun(br)时,表面上看起来像传输的是整个br数组,实际传输的是br的首地址
因此注意,如果函数的参数是以数组的形式传递,那么,数组形式要退化为指针。
4. 避免举偶法陷阱
混淆指针与指针所指向的数据。
*p空间存储的并不是hello字符串
系统会开辟两个空间,一是为hello开辟的静态常量空间 其实位置是0x0042201c
二是为指针变量*p在栈区开辟的空间0x0013ff7c。而空间0x0013ff7c存储的是hello空间的首地址0x0042201c。
陷阱一:以下两种操作,字符串的存储方式不同。
char *p = “hello”;
p[0] =‘H’; 程序会崩溃,原因是不允许修改 静态常量空间中的 字符串常量。
而char p[ ] = "hello";
p[0] = 'H'; 则没问题,p[]是数组空间,会在栈区开辟空间,在栈区修改数组的内容是完全可以的。
陷阱二:
char *p = "hello";
char *q = p;
此时,p和q对应的栈区空间地址不同,但是这两个地址中存放的内容是相同的,都是hello的存储空间的首地址,即两个指针指向同一个地址。
陷阱三:
此时,不能重复释放空间。
5. 空指针并非空字符串
char *p = NULL; //p没有任何指向
char *q =""; //q指向的内容为\0
6. 边界计算与不对称边界
数组 左闭右开 栈的生长方向是从高地址到低地址。
图中,内存上边是低地址 下面是高地址,所以i在高地址 a在低地址
如上程序会一直循环,
原因是:在内存中,a[10]的位置恰好为i,a[10]相当于对i赋值,这会导致i的值一直小于10。
栈:它的生长方式是向下的,是向着内存地址减小的方向增长。栈的开口是向下的,上面的底部是栈底,下面的开口是栈顶。
缓冲区设计
7. 求值顺序陷阱
短路求值
8. 运算符&& || ! 按位 & | ~(取反)
逻辑运算的结果只能是真或假
c缺陷与陷阱 第3章 语义陷阱相关推荐
- 《C陷阱与缺陷》----第三章 语义陷阱
第三章. 语义陷阱 3.1 指针与数组 3.2 非数组的指针 3.3 作为参数的数组声明 3.4 空指针并非空字符串 3.5 边界计算与不对称边界 3.6 求值顺序 3.9 整数溢出 3.10 为函数 ...
- 《C陷阱与缺陷》一第1章 词法“陷阱”1.1 =不同于==
本节书摘来自异步社区<C陷阱与缺陷>一书中的第1章,第1.1节,作者 [美]Andrew Koenig,更多章节内容可以访问云栖社区"异步社区"公众号查看 第1章 词法 ...
- C陷阱与缺陷 第3章 语义“陷阱” 3.4 避免“举偶法”
避免"举偶法" "举偶法"(synecdoche)是一种文学修辞上的手段,有点类似于以微笑表示喜悦.赞许之情,或以隐喻表示指代物与被指代物的相互关系.在 ...
- 《C陷阱与缺陷》----第二章 语法陷阱
第二章 语法陷阱 2.1 理解函数声明 2.1.1 如何理解函数声明 2.1.2 举例理解声明 2.1.2.1 例子1 2.1.2.2 例子2 2.2 运算符的优先级 2.2.1 常见错例 2.2.1 ...
- 《C陷阱与缺陷》——第三章(语义陷阱)
文章目录 一.指针与数组 二.非数组指针 三.作为参数的数组声明 四.避免"举隅法" 五.空指针并非空字符串 六.边界计算与不对称边界 七.求值顺序 八.运算符&& ...
- C陷阱与缺陷代码分析之第2章语法陷阱
作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz 陷阱1 理解函数声明 作者提出一个问题:有一个首地址为0的函数,该函数返回值类型为void,没有参数.怎样用C语言的 ...
- C陷阱与缺陷--读书笔记3 语义“陷阱”
第三章 一.知识点 1.C语言中的数组值得注意的地方有以下两点:(P41) (1).C语言中只有一维数组,而且数组的大小必须在编译期就作为一个常数确定下来.然而,C语言中数组的元素可以是任何类型的对象 ...
- 【C缺陷与陷阱】----语义“陷阱”
- C陷阱与缺陷 第2章 语法“陷阱” 2.6 “悬挂”else引发的问题
"悬挂"else引发的问题 if (x == 0) if (y == 0) error(); else { z = x + y; ...
最新文章
- 揭秘PHP深受Web开发者喜爱的原因
- netbeans html 格式化,在NetBeans IDE8.0中怎么把html的文件转换成jsp格式
- iphone-common-codes-ccteam源代码 CCTestMacros.m
- 译 | 将数据从Cosmos DB迁移到本地JSON文件
- 【LeetCode笔记】剑指 Offer 58 - I. 翻转单词顺序(Java、栈、双指针)
- linux用pe大小做逻辑卷,Linux常用命令之--逻辑卷
- mysql存储登录密码_用户身份验证:存储用户ID和密码在一个MySQL数据库
- 《数据库实验》实验一:建立数据库和基本表结构
- U盘修复,U盘量产教程(以台电晶彩NCU,容量为32G的U盘为实例)by aser
- DDOS专题详细讲解
- MySql 查询语句替换换行符
- HTML径向效果,HTML5版径向渐变梯度色彩
- 【云和恩墨大讲堂】高凯 | Oracle 12c 新特性-多租户的维护管理
- 大白菜装机教程win10_win10安装教程
- end kernel panic not syncing
- 杰理之探测芯片最高稳定运行频率【篇】
- 2011 Esri中国开发者大会
- ANSYS流固耦合仿真总结
- 基于Python的江苏大学校园网暴力破解
- 自己制作本地yum源镜像
热门文章
- dock接口_手机统一充电接口,苹果反对无效,安卓手机的充电器接口早已统一...
- Substance Painter - Blender - UE4/5 低模 高模 烘焙 ID 流程
- 开放API接口 练习学习接口
- 数字孪生智慧城市运用于三维可视化管理系统
- java键入时间hhmm_日期-SimpleDateFormat上的Java HH:mm和hh:mm之间的差异
- 总结2019,规划2020,未完待续
- 说话人识别神经网络推理方式
- 为什么商务人都申请163邮箱,163邮箱怎么注册登陆呢?
- 服务器压缩PNG图片
- 如何以Java实现网页截图技术