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

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[10];
int *pInt = a; // a的类型是"int型的指针"
int (*pArr)[10] = &a; // &a的类型是"10个int的数组的指针"
int array[NROWS][NCOLUMNS];
int (*pArr2)[NCOLUMNS] = array; // array的类型是"NCOLUMNS个int的数组的指针"
int (*pArr3)[NROWS][NCOLUMNS] = &array; // array的类型是"NROWS个NCOLUMNS个int的数组的数组的指针"
时间: 2024-10-07 05:07:39

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

《你必须知道的495个C语言问题》笔记--库函数

怎样把数字转为字符串(与atoi相反)?有itoa函数吗? 用sprintf就可以了: sprintf(string, "%d", number); 同理,也可以同sprintf把long型或浮点型转换成字符串(使用%ld或%f),也就是说,可以把sprintf看成是atol或者atof的 反函数. 怎样在日期上加n天?怎样取得两个日期的时间间隔? 第一个问题,mktime接受没有规范话的日期,所以可以用一个日期的struct tm结构,直接在tm_mday域上进行加减,然后 调用mk

《你必须知道的495个C语言问题》笔记--杂项

如何进行移位操作? 因为左移操作(<<)不会导致符号位出现缺位,不考虑符号位,低位补0即可.所以对于无符号和有符号数来说,均为逻辑左移. 右移操作(>>)会涉及到符号位出现缺位的问题,所以在有符号数的右移操作时要考虑符号位怎么补的问题.对于无符号数来说, 最左侧补0,即逻辑右移:对于有符号来说,最左侧补符号位,即符号右移. 实践: #include <stdio.h> int main(void) { unsigned rui; int ri; unsigned int

《你必须知道的495个C语言问题》笔记--标准输入输出

getchar的返回值 这样的代码有什么问题: char c; while((c = getchar()) != EOF).... getchar返回值变量必须是int型.因为EOF通常定义为-1,二十进制为255的字符会被符号扩展,和EOF比较时会相等,从而 过早第结束输入. feof函数的使用 为什么这些代码最后一行复制了两遍? #include <stdio.h> #include <unistd.h> #include <fcntl.h> #define MAX

《你必须知道的495个C语言问题》笔记--数组和指针

一.如何动态分配多维数组? 1.分配一个指针数组,然后把每个指针初始化为动态分配的行 代码如下: int **array = (int **)malloc(ROW * sizeof(int*)); int i = 0; for(i=0; i<ROW; i++){ array[i] = (int *)malloc(COL * sizeof(int)); } 2.让数组的内容连续,但在后来重新分配行. 代码如下: int **array = (int**)malloc(ROW * sizeof(in

《你必须知道的495个C语言问题》笔记--表达式

1.怎样才能避免这些未定义的求值顺序问题呢? 有几条简单的规则: 1.确保一个表达式最多只修改一个对象:一个简单变量.一个数组或者一个指针指向的位置. 2.如果一个对象在一个表达式中出现一次以上而且在表达式中被修改,则要确保对该对象的所有读访问都被用于计算它的 最终值.这条规则允许表达式i=i+1,尽管i出现了两次而且被修改了,但对i的旧值读取是用于计算i的新值. 3.如果想破坏第一条规则,就要确保修改的对象互不相同.同时,尽量限制到最多2至3个修改并参照下面例子的风格.在 这条规则下,c=*p

《你必须知道的495个C语言问题》笔记

1.10 对于没有初始化的变量的初始值可以作怎样的假定?如果一个全局变量初始值为 "零", 它可否作为空指针或浮点零? 答: 具有 "静态" 生存期的未初始化变量 (即, 在函数外声明的变量和有静态存储类型的变量) 可以确保初始值为零, 就像程序员键入了 "=0" 一样. 因此, 这些变量如果是指针会被初始化为正确的空指针, 如果是浮点数会被初始化为 0.0 (或正确的类型, 参见第 5 章).具有 "自动" 生存期的变量 (

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

本文是 你必须知道的495个C语言问题 系列的第五篇,主要还是来了解下字符和字符串相关的东西,同时也会涉及内存相关的知识. 一般来说,字符串以及字符的处理都是编程语言中的常客,在C语言中,我们被给予了很好的灵活性,但是同时字符也成了最诡秘的处理单元. 在指针的内容里,我基本上讲解了字符串和字符数组的差异,所以这里就不再赘述了. 我们知道字符的英语翻译是character,这也是为什么字符类型为char的原因,我们使用单引号''来标示一个字符而使用双引号""来标示字符串.实际上,在C语言

《你必须知道的495个C语言问题》读书笔记之第2章:结构、联合和枚举

1. Q:下面两个声明有何区别? struct x1 {...}; typedef struct {...} x2; A:第一种形式声明了一个“结构标签”,第2种形式声明了一个“类型定义”.前者在声明结构的实例时必须使用struct关键字,如"struct x1 a;",后者则不需要使用struct关键字,如"x2 b;".但这个区别在C++编译器和某些模仿C++的C编译器中已经完全不存在了,在C++中结构标签在本质上都自动声明为类型定义. 2. Q:在C语言中是否

C#刨根究底:《你必须知道的.NET》读书笔记系列

一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP-王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心得和感悟,将技术问题以生动易懂的语言展开,层层深入,以例说理.全书主要,包括了.NET基础知识及其深度分析,以.NET Framework和CLR研究为核心展开.NET本质论述,涵盖了.NET基本知识几乎所有的重点内容.全书分为5个部分,第1部分讲述.NET与面向对象,从底层实现角度分析了.NET如何实现面向