1. C标准中并没有精确定义数值类型的大小,但作了以下约束:

(1) char类型可以存放小于等于127的值;

(2) short int和int可以存放小于等于32767的值;

(3) long int可以存放小于等于2147483647;

(4) char至少有8位,short int和int至少有16位,long int至少有32位,long long至少有64位。

可以在头文件<limits.h>中找到特定机器下上述类型的最大值和最小值。

2. Q:C语言为什么不精确定义标准类型的大小?

A: C语言认为对象的具体大小应该由具体的实现来决定。多数程序不需要精确控制这些大小,那些试图达到这一目的的程序如果不这样做也许会更好。

3. Q:"char *p1,p2;"是什么意思?

A: 在C语言中,声明的语法并非“类型 标识符”,而是"基本类型 声明符"。其中的“声明符”或者是一个简单标识符,或者是如同*p, a[10], f()这样的符号,表明被声明的变量是指向基本类型的指针、基本类型的数组或返回基本类型的函数。上述声明中基本类型是char,第一个声明符是"*p1",表明p1是指向char类型的指针;第二个声明符是"p2",表明p2是char型变量。如果想声明两个指针,应该写成"char *p1, *p2;"。(由于*是声明符的一部分,所以应该让*紧挨p1旁边)

4. Q:怎样声明和定义全局变量和函数最好?

A:当希望在多个源文件中共享变量和函数时,需要确保定义和声明的一致性。最好的做法是在某个相关的.c文件中定义,然后在.h文件中进行外部声明,在需要使用时只要包含对应的头文件即可。定义变量的.c文件也应该包含该头文件,以便编译器检查定义和声明的一致性。注意,永远不要把外部函数的原型放到.c文件中,因为如果函数的定义发生改变,会很容易忘记修改原型,而错误的原型贻害无穷。

5. Q:extern在函数声明中是什么意思?

A:存储类型extern只对数据声明有意义,对于函数声明,它可以用作提示函数的定义可能在另一个源文件,但"extern int f();"和"int f()"并无实质区别。

6. Q:auto有什么用?

A:毫无用途,auto已经过时了。它是从C语言的无类型前身B语言中继承下来的。在B语言中,没有像int这样的关键字,声明必须包含存储类型。

7. Q:下面的声明中,为什么是p而不是它所指向的字符为const?

typedef char *charp;
const charp p;

A:typedef的替换并不完全基于文本的。在声明"const charp p;"中,p被声明为const的原因跟"const int i;"将i声明为const的原因一样,编译器不会“深入”typedef的内容来发现涉及了指针。

8. Q:为什么不能在初始化和数组维度中使用const值?

const int n = ;
int a[n];

A:const限定词真正的含义是read-only,用它限定的对象通常是运行时不能被赋值的对象。因此用const限定的对象的值并不是真正的常量,不能用作数组维度、case行标或类似环境。在C++中则可以。

9. Q:"const char *p", "char const *p", "char *const p"有什么区别?

A:从里往外看。前两个可以互换,它们都声明了一个指向字符常量的指针,第三个则声明了一个指向字符的指针常量。解读复杂C声明的一种方法是遵循“从内到外”的阅读顺序,并谨记[], ()的优先级比*高。

10. Q:如下所示,为什么在file2.c中sizeof取不到array的大小?

// file1.c
int array[] = {,,};
// file2.c
extern int array[];

A:未指定大小的extern数组是不完全类型,不能对它使用sizeof,因为sizeof在编译时发生作用,它不能获得定义在另一个文件中的数组的大小。

11. Q:main的正确定义是什么?void main正确吗?

A: main的正确定义只有以下四种:

int main();
int main(void);
int main(int argc, char **argv);
int main(int argc, char *argv[]);

void main不正确。将main函数声明为void不仅关掉或重新排列了警告信息,它可能还会导致跟调用者(C的运行时启动代码)的期望不同的函数调用/返回序列。就是说,如果返回void和返回int的函数调用序列不同,则启动代码会使用返回int的调用序列调用main函数。如果main被错误地声明为void,它可能不会运行。

12. Q:如何判断哪些标识符可用、哪些被保留了?

A:首先我们必须理解标识符的3个属性:作用域、命名空间和连接类型。

(1) 作用域:4种,分别是函数、文件、块和原型(原型仅仅存在于函数原型声明的参数列表中)。

(2) 命名空间:4种,分别是行标(label, 即goto的目的地)、标签(tag, 结构、联合和枚举的名称)、结构或联合成员、其他普通标识符(函数、变量、类型定义名称和枚举常量)。

(3) 连接类型:3种,分别是外部连接(全局、非静态变量和函数)、内部连接(限于文件作用域内的静态函数和变量)、无连接(局部变量、typedef名称和枚举常量)。

然后,我们来看ANSI关于命名空间的规则:

(1) 所有以下划线开头,后跟一个大写字母或另一个下划线的标识符永远保留。

(2) 所有以下划线开头的标识符作为文件作用域的普通标识符(函数、变量、类型定义和枚举变量)保留。

(3) 被包含的标准头文件中的宏名称的所有用法保留。

(4) 标准库中的所有具有外部连接属性的标识符(即函数名)永远保留用作外部连接标识符。

(5) 在标准头文件中定义的类型定义和标签名称,如果对应的头文件被包含,则在(同一个命名空间中的)文件作用域内保留。

13. Q:没有显式初始化的变量的初始值是什么?

A:具有静态生存期的未初始化变量(即在函数外声明的变量及静态存储类型变量,包括数组和结构)可以确保初始值为零,具有自动生存期的变量(即非静态存储类型的局部变量)如果没有显式初始化,则包含的是垃圾内容,对垃圾内容不能做任何有用的假定。

14. Q:以下的初始化有什么区别?为什么向p[i]赋值时程序会崩溃?

char a[] = "string literal";
char *a = "string literal";

A:字符串字面量(string literal)有两种稍有区别的用法:

(1) 用作数组初始值时,它指明该数组中字符的初始值;

(2) 其他情况下,它会转化为一个无名的静态字符数组,可能会存储在只读内存中,这就导致它不能被修改。在表达式环境下,数组通常被立即转化为一个指针,因此第二个声明把

p初始化成指向无名数组的第一个元素。

15. Q:下面两个声明有何区别?

struct x1 {...};
typedef struct {...} x2;

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

16. Q:在C语言中是否有模拟继承等面向对象程序设计特性的好方法?

A:把函数指针直接加入到结构中就可以实现简单的“方法”。你可以使用各种不雅而暴力的方法来实现继承,例如通过预处理器或让“基类”的结构作为初始的子集,但这些方法都不完美。另外,也没有操作符的重载和覆盖。

17. Q:为什么不能用內建的==和!=操作符比较结构?

A:简单的按字节比较的方法可能会在遇到结构中没有使用的“洞”的随机内容的时候失败(这些补位是用来保证后续的成员正确对齐的)。而按域比较在处理大结构时可能需要难以接受的大量重复代码。任何编译器生成的比较代码都不能期望在所有情况下都正确比较指针域,例如比较char *域的时候一般都希望使用strcmp而不是==。如果需要比较两个结构,必须自己写函数按域比较。

18. Q:怎样从/向数据文件读/写结构?

A:使用fwrite可以写一个结构:"fwrite(&somestruct, sizeof somestruct, 1, fp);"但这样用内存映像写出的数据文件却不能移植,尤其是当结构中包含浮点成员或指针的时候。结构的内存布局跟机器和编译器都有关。不同的编译器可能使用不同数量的填充位,不同机器上基本类型的大小和字节顺序也不尽相同。一致性更好的方案是写一对函数,用可移植的方式按域读写结构。

19. Q:为什么我的编译器在结构体中留下了“空洞”?能否关掉“空洞”?

A:当内存中的值合理对齐时,很多机器都能非常高效地访问,而且某些机器甚至根本不能访问没有对齐的地址,因此必须要求所有的数据都正确地对齐。

20. Q:如何确定域在结构中的字节偏移量?

A:在<stddef.h>中定义了offsetof()宏,用offsetof(structs, f)可以计算出域在结构s中的偏移量。(offsetof只能求结构体非位域成员的偏移量,不能求位域成员的偏移量)

21. Q:有办法初始化联合吗?

A:C99引入了“指定初始式”,可以用来初始化任意成员。

《你必须知道的495个C语言问题》读书笔记之第1-2章:声明和初始化的更多相关文章

  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, "!")." ...

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

    1. Q:为什么我不能对void *指针进行算术运算? A:因为编译器不知道所值对象的大小,而指针的算法运算总是基于所指对象的大小的. 2. Q:C语言可以“按引用传参”吗? A:不可以.严格来说,C ...

随机推荐

  1. 使List<userClass>.Contains可以查找重復的對象

    List.Contains实现对比 http://blog.csdn.net/yswucn/article/details/4091469

  2. learning express step(二)

    install express-generator C:\Users\admin\WebstormProjects\learning-express-step2>npm install expr ...

  3. F. Make Them Similar ( 暴力折半枚举 + 小技巧 )

    传送门 题意: 给你 n 个数 a[ 1 ]  ~ a[ n ], n <= 100: 让你找一个 x , 使得 a[ 1 ] = a[ 1 ] ^ x ~ a[ n ] = a[ n ] ^ ...

  4. webpack+vue+Eslint+husky+lint-staged 统一项目编码规范

    一. Eslint: 为什么我们要在项目中使用ESLint ESLint可以校验我们写的代码,给代码定义一个规范,项目里的代码必须按照这个规范写. 加入ESLint有非常多的好处,比如说可以帮助我们避 ...

  5. Bzoj 1086: [SCOI2005]王室联邦(分块)

    1086: [SCOI2005]王室联邦 Time Limit: 10 Sec Memory Limit: 162 MBSec Special Judge Submit: 1557 Solved: 9 ...

  6. 快速幂 x

    快速幂! 模板如下: #include<iostream> #include<cmath> #include<cstdio> #define LL long lon ...

  7. Django-中间件实现1分钟内只允许三次访问

    代码 class Throttle(MiddlewareMixin): def process_request(self, request): # 1. 拿到用户请求的IP # print(reque ...

  8. Java Collection Framework 备忘点

    最顶端是两个接口,集合和映射——  Collection<T>  /  Map<K, V> List 列表 保持插入顺序 ArrayList 擅长随机读 LinkedList ...

  9. Echarts-复杂关系图(源码)

    关系图: 代码: <!DOCTYPE html> <head> <meta charset="utf-8"> <script type=& ...

  10. 微信小程序之简单记账本开发记录(四)

    昨天搭建了大致界面 今天需要将用到的一系列样式表配置出来并检查错误