1. Q:为什么我不能对void *指针进行算术运算?

A:因为编译器不知道所值对象的大小,而指针的算法运算总是基于所指对象的大小的。

2. Q:C语言可以“按引用传参”吗?

A:不可以。严格来说,C语言总是按值传参,你可以模拟按引用传参,定义接受指针的函数,然后在调用时使用&操作符。但C没有任何真正等同于按引用传参的东西。

3. Q:怎样在整型和指针之间进行转换?能否暂时把整数放入指针变量,或者相反?

A:C标准中规定整数与指针之间的相互转换是实现定义的,因此不保证指针和整数之间无需修改就能相互转换。事实上强制进行整数和指针的相互转换从来就不是什么好的实践。当需要同时保存两种类型数据的存储结构时,使用联合是更好的办法。

4. Q:空指针到底是什么?

A:根据C语言定义,每一种指针类型都有一个特殊值——“空指针”,它与同类型的其他所有指针值都不相同,它“保证与任何对象或函数的指针值都不相等”。也就是说,空指针不会指向任何地方,它不是任何对象或函数的地址。取地址操作符&永远也不会返回空指针,对malloc的成功调用也不会返回空指针。注意,空指针在概念上不同于未初始化的指针,空指针可以确保不指向任何对象或函数,而未初始化的指针则可能指向任何地方。

5. Q:怎样在程序里获得一个空指针?

A:使用空指针常量。空指针常量可以是0或NULL(在stdio.h文件中)。根据C语言定义,在指针上下文中的“值为0的整型常量表达式”会在编译时转换为空指针。然而,传入函数的参数不一定被当作指针上下文,此时生成空指针需要显式的类型转换。下表总结了何时可以直接使用空指针常量,何时需要进行显式类型转换:

6. Q:如果NULL的值改变了,比如在使用非零内部空指针的机器上,用NULL(而不是0)不是更好吗?

A:不,尽管符号常量经常代替数字使用以备数字的改变,但这不是用NULL代替0的原因。C语言本身确保了源码中用于指针上下文的0会生成空指针。

7. Q:有没有什么简单的方法理解所有这些与空指针有关的东西?

A:遵循两条简单规则:(a) 当源码中需要空指针常量时,使用"0"或"NULL";(b) 如果在函数调用中"0"或"NULL"用作参数,把它转换成被调函数需要的指针类型。

8. Q:空指针是指向地址0的指针吗?

A:不能将空指针看作指向地址0的指针,空指针不指向任何地方。如果需要访问地址0,应该阅读厂商文档,使用机器提供的技巧来访问。

9. Q:在C语言中“指针和数组等价”到底是什么意思?

A:意思是数组和指针的算法定义使得可以用指针方便地访问数组或者模拟数组,换言之,在C语言中只是指针算术和数组下标运算等价,指针和数组是不同的。特别地,等价的基础来自这个关键定义:一个T数组类型的对象如果出现在表达式中会退化为一个指向数组第一个元素的指针,指针的类型是指向T的指针。

10. Q:如果你不能给它赋值,那么数组如何能成为左值呢?

A:术语“左值”并不完全表示“能赋值的东西”,更好的定义应该是“在内存中有特定位置的东西”。

11. Q:既然数组引用会退化为指针,如果array为数组,那么array和&array又有什么区别?

A:区别在于类型。在标准C中,&array生成一个“T型数组”的指针,指向整个数组;而array生成一个T型的指针,指向数组的首元素。

int a[];
int *pInt = a; // a的类型是"int型的指针"
int (*pArr)[] = &a; // &a的类型是"10个int的数组的指针"
int array[NROWS][NCOLUMNS];
int (*pArr2)[NCOLUMNS] = array; // array的类型是"NCOLUMNS个int的数组的指针"
int (*pArr3)[NROWS][NCOLUMNS] = &array; // array的类型是"NROWS个NCOLUMNS个int的数组的数组的指针"

12. Q:malloc(0)返回一个空指针还是指向0字节的指针?

A:ANSI/ISO标准声称它可能返回任意一种,其行为由实现定义。可移植的代码要么别调用malloc(0),要么做好它可能返回空指针的准备。

13. Q:当我调用malloc()为一个函数的局部指针分配内存时,我还需要用free()显式地释放吗?

A:是的。函数返回时,局部指针会被释放,而不是它所指的对象。用malloc()分配的内存在你显式释放它之前都会保留在那里。一般地,每一个malloc()都必须有个对应的free()调用。

14. Q:我有个程序分配了大量的内存,然后又释放了,但我发现操作系统的内存占用率并没有降低?

A:多数malloc/free的实现并不把释放的内存返回操作系统,而是留着供同一程序的后续malloc()使用。

15. Q:我的程序总是崩溃,显然发生在malloc内部的某个地方,但是我看不出哪里有问题,是malloc有bug吗?

A:很不幸,malloc的内部数据结构很容易被破坏,而由此引起的问题会十分棘手。最常见的问题来源是向malloc分配的区域写入比所分配的还多的数据,如malloc(strlen(s))而不是strlen(s)+1。其他问题包括指向已经释放了的内存的指针,分配大小为0 的对象,重分配空指针,释放未从malloc获得的指针、空指针或者已经释放的指针。这些错误的后果可能会在真正出错很久以后才显现出来或在不相关的代码段出现,从而导致排错十分困难。多数malloc的实现在这些问题面前显得十分脆弱,因为它们直接在它们返回的内存旁边存储至关重要的内部信息片段,这些信息很容易被用户指针破坏。

16. Q:free()怎么知道有多少字节需要释放?

A:malloc/free的实现会在分配的时候记下每一块的大小,所以在释放时就不必再考虑它的大小了。(通常,这个大小就记录在分配的内存块旁边,因此对超出分配内存块边界的内存哪怕是轻微的改写,也会导致严重的后果)。

17. Q:为什么sizeof不能告诉我它所指的内存块的大小?

A:sizeof操作符并不知道你使用了malloc为指针分配内存,sizeof只能得到指针本身的大小。

18. Q:动态分配数组之后,还能改变它的大小吗?

A:能,使用realloc。可以使用下边的代码。

dynarray = (int *)realloc((void *)dynarray,  * sizeof(int));

如果realloc能在原地扩大内存区域,它就返回传入的指针;如果它必须到内存中的其他地方去寻找足够大的连续空间,则它会返回一个不同的指针,而原来的指针值变得不可用;如果它根本找不到足够的空间,则它会返回空指针,而原来分配的内存会保留。因此,通常不应立即将新指针赋给旧指针,最好使用一个临时指针。

int *newarray = (int *)realloc((void *)dynarray,  * sizeof(int));
if (newarray != NULL) {
dynarray = newarray;
}
else {
fprintf(stderr, "Can't reallocate memory.\n");
/* dynarray remains allocated. */
}

《你必须知道的495个C语言问题》读书笔记之第4-7章:指针的更多相关文章

  1. 你必须知道的495个c语言问题(笔记)

    1.1我该如何决定使用哪种整数类型? 用到较大的数用long:空间很重要(例如有很大的数组或很多的结构)用short:此外用int. win32: int 32bit    4byte char 8b ...

  2. 你必须知道的495个C语言问题,学习体会一

    C语言作为一门古老的语言,其灵活性和容易出错都让人 又爱又恨,书籍<你必须知道的495个C语言问题>,使用问答的形式,告诉读者 C语言使用的各个方面的知识,包括一些冷知识等.以下,我要摘录 ...

  3. C语言学习书籍推荐《你必须知道的495个C语言问题》

    萨米特 (Steve summit) (作者), 孙云 (译者), 朱群英 (译者) 下载地址:点我 <你必须知道的495个C语言问题>以问答的形式组织内容,讨论了学习或使用C语言的过程中 ...

  4. 《你必须知道的495个C语言问题》知识笔记及补充

    1. extern在函数声明中是什么意思? 它能够用作一种格式上的提示表明函数的定义可能在还有一个源文件里.但在 extern int f(); 和 int f(); 之间并没有实质的差别. 补充:e ...

  5. 你必须知道的495个C语言问题,学习体会四

    本文,我们来学习下指针,这是个梦魇啊.无数次折磨着C语言学习者,无数次的内存泄露,无数次的访问失败,无数次的越界溢出, 这些错误造就的仅仅是一个 跟随者,真正的优秀者必须要正视语言的局限,同时在最大限 ...

  6. 你必须知道的495个C语言问题,学习体会三

    本文是 本系列的第三篇,本文主要对C语言的表达式做个小结 先从两个坑爹的表达式说起:i++ 与++i 上大学的时候,学长告诉我,这两个表达式,意义是一样的,后来老师纠正说,还是有区别的,于是让我们记住 ...

  7. 你必须知道的495个C语言问题,学习体会二

    这是本主题的第二篇文章,主要就结构体,枚举.联合体做一些解释 1.结构体 现代C语言编程 结构化的基石,diy时代的最好代言人,是面向对象编程中类的老祖宗. 我们很容易定义一个结构体,比如学生: st ...

  8. 《你必须知道的495个C语言问题》读书笔记之第11-14章:ANSI C标准、库函数、浮点数

    一.ANSI C标准 1. ANSI向C语言预处理器引入了几项新的功能,包括“字符串化”操作符(#).“符号粘贴”操作符(##).#pragma指令. 2. Q:char a[3] = "a ...

  9. 《你必须知道的495个C语言问题》读书笔记之第8-10章:字符串、布尔类型和预处理器

    一.字符和字符串 1. Q:为什么strcat(string, '!')不行? A:strcat()用于拼接字符串,所以应该写成strcat(string, "!")." ...

随机推荐

  1. PC端使用program來CHGUSRPRF

    執行CHGUSRPRF命令需要*SECADM 權限,但通常Security部門不允許Grant這個這麼大的權限,爲了達到目的,改用下面的方法 1. Create CL program 注意裏面一定要用 ...

  2. C语言学习笔记2-程序基础和变量

    本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/50751977 作者:jadeshu   邮箱: jades ...

  3. 2019.6.28 校内测试 T1 Jelly的难题1

    这题面有点难理解,建议直接跳到题意解释那一部分(虽然我觉得解释的不大对,但按照解释来做确实能AC): 按照“题意解释”的思路来思考这个题,那么就十分的简单了: 1.首先要读入这个字符矩阵,可以用cin ...

  4. pandas入门之DataFrame

    创建DataFrame - DataFrame是一个[表格型]的数据结构.DataFrame由按一定顺序排列的多列数据组成.设计初衷是将Series的使用场景从一维拓展到多维.DataFrame既有行 ...

  5. 冲刺阶段——Day5

    [今日进展] 完成注册功能代码 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionLi ...

  6. golang sqlx查询时, struct字段冲突

    type TA struct { Id int64 `db:"id"` } type TB struct { Id int64 `db:"id"` } type ...

  7. Flutter移动电商实战 --(15)商品推荐区域制作

    1.推荐商品类的编写 这个类接收一个List参数,就是推荐商品的列表,这个列表是可以左右滚动的. /*商品推荐*/ class Recommend extends StatelessWidget { ...

  8. linux 中gcc的·安装、编译过程

    一.安装gcc编译器 通过命令gcc -v查看当前的GCC版本 [root@localhost /]# gcc -v Reading specs from /usr/i386-glibc-2.1-li ...

  9. python 调用父类方法, 重写父类构造方法, 不显式调用,会报错

    子类不显式调用父类的构造方法,而父类构造函数初始化了一些属性,就会出现问题 如果子类和父类都有构造函数,子类其实是重写了父类的构造函数,如果不显式调用父类构造函数,父类的构造函数就不会被执行,导致子类 ...

  10. 2.5 Go语言基础之map

    Go语言中提供的映射关系容器为map, Go中内置类型,其内部使用散列表(hash)实现,为引用类型. 无序键值对(key-value)集合,通过key(类似索引)快速检索数据 必须初始化才能使用. ...