你必须知道的495个c语⾔问题(笔记)
1.1我该如何决定使⽤哪种整数类型?
  ⽤到较⼤的数⽤long;空间很重要(例如有很⼤的数组或很多的结构)⽤short;此外⽤int。
  win32:
  int    32bit      4byte
  char   8bit      1byte       
  short    16bit    2byte
  long   32bit    4byte
  float    32bit    4byte
  double  64bit      8bit
注:wchar_t在Windows中是2byte,在Linux中是4byte
1.2为什么不精确定义标准类型的⼤⼩?
  C语⾔认为对象的具体⼤⼩应该由具体的实现来决定
1.4新的64位机上的64位类型是什么样的?
  long long
1.10同⼀个静态(static)函数或变量的所有声明都必须包含static储存类型吗?
  语⾔标准没有严格规定这⼀点,最安全的做法是让static⼀致的出现在定义和声明中
1.11extern在函数声明中是什么意思?
  ⽐较正规的写法;
    a.告诉编译器建⽴外部链接;
    b.告诉读程序的⼈,去别的⽂件
  其实你不写extern,编译器也知道去外⾯。
typedef:定义新的类型名称
1.13typedef和define有什么区别?
  typedef能更好的处理指针
const:静态,常量(只读变量)
1.24我在⼀个⽂件中定义了⼀个extern的数组,然后在另⼀个⽂件中使⽤:
  file1.c          file2.c
  int array[] = {1, 2, 3};    extern int array[];
  为什么在file2中,sizeof娶不到array的⼤⼩?
  未指定⼤⼩的extern数组是不完全类型,不能对它使⽤sizeof
1.31对于没有显⽰初始化的变量的初始值可以怎样的假定?如果⼀个全局变量初始值为“零”,它可否作为空指针或浮点零?  具有静态(static)⽣存周期的末初变化量(即函数声明外的变量和静态存储类型的变量)可以确保初始值为零。
  具有动态⽣存周期的变量(即⾮静态存储类型的局部变量)如果没有显⽰的初始化,则包含的是垃圾内容。
1.33下⾯的初始化有什么问题?编译器提⽰“invalid initializers”或其他信息?
  char  *p = malloc(10);
  初始中函数调⽤只能出现在⾃动变量(即局部⾮静态变量)。
1.34以下初始化有什么区别?
  char a[] = "string literal";
  char *p = "string literal";
  a.a[]分配了15个字节内存,去存储string literal;⽽p分配的是string literal的地址。
  b.前者内容可变,⽽后者不可变(因为后者被定义为了const char *)。
2.9为什么不⽤内建的==和!=操作符来⽐较结构?
  a.==和!=是简单的按字节⽐较,因为内存的值合理对齐时,机器的访问效率⾮常⾼效。因此结构体中会按字符类型对齐,因此会留下没有使⽤的空洞。使简单的按字节
   ⽐较不能实现。
  b.就算能够实现,也会产⽣⼤量难以接受的代码。
2.23枚举和⼀组预处理的#define有什么不同?
  c标准规定枚举为整型,枚举常量为int型。
表达式取值顺序:编译器有相对⾃由的选择权,编译器选择的顺序通常并⽆实质影响。
3.4设计⼀个巧妙的表达式:
a ^=
b ^= a ^= b;
  它不需要临时变量就可以交换a和b的值。
3.8为什么表达式
  printf(“%d %d”,f1(), f2());
  先调⽤f2?我觉得逗号表达式应该确保从左到右的求值顺序。
  printf函数对参数的计算是从右到左,输出是从左到右。
3.9
  a.在⼀个表⽰式中对同⼀个对象进⾏2次或2次以上的修改(未定义)
    eg:printf(“%d\n”,  i++ * i++);
    在⼀个表达式中对i进⾏了两次修改
  b.右边⼀个对象对⾃⾝进⾏修改时,不能同时出现在左边。
    eg: i = i++;
3.16
  对类型的转换应该是作⽤于⼀个数上的
  eg: long int c = (long int)a * b;
void **:⼆级指针指向另⼀个指针的地址
void  *:⼀级指针指向⼀个变量的地址
(void **)&a:讲变量a的地址强制为void **型指针,即认为a是指针变量并取这个指针变量的地址。将这个地址强制为忽略原有类型只有地址的指针
4.13通⽤指针是什么?当我把函数指针赋向void *类型的时候编译通不过。
  没有通⽤指针,void *指针只能保存对象(也就是数据)指针(普通指针),将函数指针转换为void *指针是不可移植的。
5.1空指针到底是什么?
  空指针不指向任何对象或函数;
  未初始化的指针则可能指向任何地⽅。
5.4 NULL是什么,它怎么定义的?
  #define  NULL  ((void *) 0)
空指针不是指向0地址的指针,⽽是什么都不指向(或者说它指向⼀个为空的虚⽆空间)。但是访问0地址的指针却要考虑空指针的影响。
6.4既然他们不同,那么为什么作为函数形参的数组和指针声明可以互换呢?
  由于数组会马上退化为指针,数组事实上从来没有传⼊到函数。允许指针参数声明为数组只不过是为让它看起来好像传⼊了数组。形参的数组,在编译器中都被当做
  指针来处理,因此在传⼊数组的时候,函数接收到的正是指针。
char *型指针可以直接赋值其他不⾏
  eg:char *p = "abc";  (正确)
    int   *i = 123;  (错误)
7.19为什么malloc返回了离谱的指针值?我的确读过7.9,⽽且在调⽤之前包含了extern void *malloc();声明。
  malloc分配的空间不能超过前⾯字符类型所能容纳的范围⼤⼩
7.24动态分配的内存⼀旦释放之后就不能再使⽤?
  是的,因为它被保留给后续程序使⽤,没有返还给系统。见7.29。
7.25为什么在调⽤free()之后指针没有变空?使⽤(赋值,⽐较)释放之后的指针有多么不安全?
  当你调⽤free()的时候,传⼊的指针指向的内存被释放,但调⽤函数的指针值可能保持不变,因为c的按值传参的语义意味着被调函数永远不会永久改变参数的值。
  通常最好在释放之后⽴即把它们置为NULL。
7.29我有个程序分配了⼤量的内存,然后⼜释放了。但从操作系统看,内存的占⽤率却没有变回去。
  多数malloc/free的实现并不把释放的内存返回给操作系统。⽽是留着供同⼀程序的后续malloc使⽤
8.9我注意到sizeof(‘a’)是4⽽不是1(既不是sizeof(char)),是不是我的编译器有问题?
  c语⾔中的字符常量是int型(c语⾔中将char按int型来存储:ASCII值),因此sizeof('a')是sizeof(int)。sizeof(char)是1
10.3怎么写⼀个交换两个值的通⽤宏?
  #define   swap(a, b)  (a ^= b ^= a ^= b)
10.13 sizeof(sizeof是关键字)操作符可以⽤在#if预处理指令中吗?
  不⾏。预处理编译过程之前,此时尚未对类型名称进⾏分析。
11.9为什么不能再初始化维度中使⽤const值?例如:
  const int n = 5;
  int a[n];
  const限定词的真正的含义是“只读”,⽤它限定的对象是运⾏时不能被赋值的对象。因此⽤const限定的对象的值并不完全是⼀个真正的常量。不能⽤作数组维度,case⾏表或类
  似的环境。
11.10 "const char *p", "char const *p", "char * const p"有何区别? 
  前两者可以互换。
  const char *p:内容不能被改变。(内容不变)
  char * const p:p指针不能修改(地址不变)
11.13能否通过将main声明为void来关掉“main没有返回值”的警告?
  不能。main函数只有两种和法的声明:
  int main(void);
  int main(int argc, char **argv);
12.7如何在printf的格式串中输出⼀个'%'字符?
  只需要重复百分号:%%。
12.8为什么这么写不对?
  long int n = 123456;
  printf("%d\n", n);
  因为printf不知道传⼊的数据类型所以这样要使⽤%ld
  结合12.9理解
12.9有⼈告诉我不能再printf中使⽤%lf,为很么printf()⽤%f输出double型,⽽scanf却⽤%lf呢?
  printf的%f说明符的确既可以输出float也可以输出double。根据“默认参数提升”规则。float型会被提升为double型。因此在printf中只能看到双精度数。
  scanf它接受指针,这⾥没有参数提升。所以还是%f和%lf。
c语言编译器怎么用?
12.11如何⽤printf实现可变的域宽度?就是说,我在想运⾏时确定宽度⽽不是使⽤%08d?
  使⽤printf(%*d, width, x)。
这本书太⽼了