《你必须知道的495个C语言问题》是一份详尽的指南,旨在帮助学习者和从业者解决在C语言编程中可能遇到的各种难题。本书由Steve Summit编写,朱群英和孙云翻译,修订版0.9.4发布于2005年6月23日。该书覆盖了C语言的基础概念到高级主题,从声明和初始化到结构、联合和枚举,再到表达式,提供了深入的理解和实用的解决方案。
### 1. 声明和初始化
#### 1.1 如何决定使用哪种整数类型?
在C语言中,整数类型包括`int`、`short`、`long`以及`long long`。选择哪种类型取决于数据的大小需求和性能考虑。例如,`short`类型通常占用较少的存储空间,但范围较小;而`long`或`long long`则提供更大的范围,但消耗更多内存。
#### 1.2 64位机上的64位类型是什么样的?
在64位机器上,`long long`类型通常提供64位的存储,这意味着它可以表示从-9,223,372,036,854,775,808到9,223,372,036,854,775,807之间的值。这种类型的使用对于需要大整数计算的应用场景非常重要。
#### 1.3 怎样定义和声明全局变量和函数最好?
全局变量和函数应在最外层作用域定义,通常是在所有函数之外。为了提高代码的可维护性和可读性,应使用`extern`关键字在其他源文件中引用这些变量或函数,而将实际定义放在一个单独的源文件或头文件中。
#### 1.4 `extern`在函数声明中是什么意思?
`extern`关键字用于声明一个在其他地方定义的变量或函数。当在一个源文件中引用另一个源文件中定义的变量或函数时,使用`extern`可以告诉编译器该变量或函数将在链接阶段被解析。
#### 1.5 关键字`auto`到底有什么用途?
`auto`关键字最初用于声明变量,并指定其存储类型为自动(栈上)。然而,在现代C语言中,几乎所有局部变量都默认为`auto`类型,因此这个关键字的使用相对较少。但在C++中,`auto`被广泛用于类型推断,提高代码的灵活性和可读性。
#### 1.6 在C语言中一个结构不能包含指向自己的指针吗?
C语言确实允许结构体包含指向自身的指针。这种结构被称为自引用结构,常用于链表和其他数据结构的实现。然而,正确的定义方式是使用不完全类型声明,例如:
```c
typedef struct node {
int data;
struct node *next;
} Node;
```
#### 1.7 怎样建立和理解非常复杂的声明?
复杂的声明,尤其是涉及多级指针和数组的声明,可以通过逐步分解来理解和构建。例如,理解一个包含N个指向返回指向字符的指针的函数的指针的数组的声明,可以将其拆分为几个简单的部分,然后组合起来。
#### 1.8 函数只定义了一次,调用了一次,但编译器提示非法重定义了。
这通常发生在多个源文件中定义了相同的函数,或者在一个源文件中多次定义同一个函数。确保每个函数只在一个地方定义,并且在需要的地方使用`extern`声明。
#### 1.9 `main()`的正确定义是什么?`void main()`正确吗?
`main()`函数是程序的入口点,它的正确原型应该是`int main(void)`或`int main(int argc, char *argv[])`。`void main()`在某些环境中可能工作,但它不是标准的C语言语法。
#### 1.10 对于没有初始化的变量的初始值可以作怎样的假定?
未初始化的局部变量的值是未定义的,不应依赖其具有任何特定的值。然而,全局变量和静态局部变量默认初始化为零,但这并不意味着它们可以安全地用作空指针或浮点零。
#### 1.11 代码`int f() { char a[] = "Hello, world!"; }`不能编译。
这是因为`char a[]`是在函数内部声明的数组,而字符串文字是常量,不能直接赋值给数组。正确的做法是使用`const char *a = "Hello, world!";`。
#### 1.12 这样的初始化有什么问题?`char *p = malloc(10);` 编译器提示“非法初始式”。
`malloc()`返回的是动态分配的内存地址,不能作为初始化的一部分。正确的做法是在分配内存后显式地初始化指针,例如`char *p; p = (char *)malloc(10);`。
#### 1.13 以下的初始化有什么区别?`char a[] = "string literal";` 和 `char *p = "string literal";`
`char a[]`声明了一个包含字符串文字的字符数组,而`char *p`声明了一个指向字符串文字的指针。当尝试修改`p`指向的字符串时,由于字符串文字是只读的,会导致程序崩溃。
#### 1.14 我总算弄清楚函数指针的声明方法了,但怎样才能初始化呢?
函数指针可以初始化为指向某个函数的地址。例如,如果有一个函数`void func() {}`,可以这样初始化函数指针:`void (*ptr)() = func;`。
以上仅是《你必须知道的495个C语言问题》中声明和初始化部分的概述,每一小节都有更深入的讨论和示例,旨在帮助读者全面掌握C语言的细节和最佳实践。