你必须知道的495个C语言问题
### 重要知识点解析 #### 1. 声明和初始化 **1.1 我如何决定使用那种整数类型?** 在C语言中选择合适的整数类型取决于多个因素: - **需求范围**:考虑所需的整数范围。例如,`short int`用于小范围整数,`long int`用于大范围整数。 - **存储效率**:某些平台可能对特定类型的整数有更好的存储优化。 - **性能**:不同类型的整数操作在不同平台上可能有不同的性能表现。 **1.2 64位机上的64位类型是什么样的?** 在64位系统上,通常`long int`和`long long int`被定义为64位整数类型。这些类型的大小和范围可以确保在大多数情况下足够宽泛,能够处理大整数数据。 **1.3 怎样定义和声明全局变量和函数最好?** - **全局变量**:最好将其作用域限制在必要的范围内,以减少潜在的副作用。可以使用`static`关键字来限制全局变量的作用域到当前文件。 - **函数声明**:确保所有函数都有明确的原型声明,以增强代码可读性和编译时检查。 **1.4 `extern`在函数声明中是什么意思?** `extern`关键字用来声明一个变量或函数是在其他文件中定义的。它告诉编译器该变量或函数存在,但在当前文件中不需要定义它。 **1.5 关键字`auto`到底有什么用途?** `auto`关键字用于声明变量,告诉编译器该变量将在程序运行时获得存储位置(栈)。在现代C中,几乎所有的局部变量都是`auto`类型的,因此这个关键字很少使用。 **1.6 我似乎不能成功定义一个链表。** 在定义链表时,可以使用结构体(`struct`)来定义节点类型,并允许结构体包含指向自身类型的指针。例如: ```c typedef struct Node { char *item; struct Node *next; } NODE; ``` **1.7 怎样建立和理解非常复杂的声明?** 理解复杂声明的关键在于逐步拆解声明。例如,对于声明“`int (*ptr)[N][M];`”,它表示一个指向`N`个包含`M`个整数的数组的指针。 **1.8 函数只定义了一次,调用了一次,但编译器提示非法重定义了。** 这种错误通常是由于多次定义相同的函数造成的。确保每个函数在一个源文件中仅定义一次,并且在其他文件中使用`extern`关键字声明。 **1.9 `main()`的正确定义是什么?** `main()`函数是程序的入口点,其标准定义形式是`int main(void)`或`int main(int argc, char *argv[])`。`void main()`不是标准的定义形式。 **1.10 对于没有初始化的变量的初始值可以作怎样的假定?** 未初始化的局部变量具有不确定的值。全局变量默认初始化为零(0),可以作为空指针或浮点零使用。 **1.11 代码`int f() { char a[] = "Hello, world!"; }`不能编译。** 这是因为`char a[] = "Hello, world!";`试图在一个局部数组中初始化字符串字面量。这种情况下,应该使用`const char *a = "Hello, world!";`。 **1.12 这样的初始化有什么问题?** `char *p = malloc(10);`不是一个有效的初始化形式。`malloc()`返回的是动态分配的内存地址,不能直接用于初始化指针变量。正确的做法是先分配内存,然后通过指针操作来访问。 **1.13 以下的初始化有什么区别?** `char a[] = "string literal";`定义了一个包含字符串字面量的字符数组,而`char *p = "string literal";`定义了一个指向字符串字面量的字符指针。当尝试修改`p[i]`时,因为字符串字面量是只读的,所以会导致程序异常。 **1.14 我总算弄清除函数指针的声明方法了,但怎样才能初始化呢?** 函数指针可以通过指向一个函数的方式来初始化。例如,假设有一个名为`func`的函数,那么可以通过如下方式初始化函数指针: ```c int func(int x); int (*ptr)(int) = func; ``` ### 结构、联合和枚举 **2.1 声明`struct x1 {};`和`typedef struct {} x2;`有什么不同?** `struct x1 {};`声明了一个结构体类型`x1`,而`typedef struct {} x2;`创建了一个别名`x2`来代表一个新的匿名结构体类型。使用`typedef`可以简化后续的类型引用。 **2.2 为什么`struct x {}; x the_struct;`不对?** 在C语言中,结构体类型定义后需要显式地声明变量。正确的形式是`struct x the_struct;`。 **2.3 一个结构可以包含指向自己的指针吗?** 可以。结构体可以包含指向自身类型的指针成员。这是一种常见的实现自引用数据结构的方式,比如链表和树。 **2.4 在C语言中实现抽象数据类型什么方法最好?** 实现抽象数据类型的最佳方法是使用结构体和函数封装数据。可以定义结构体来保存数据,并通过函数接口暴露所需的操作,同时隐藏内部实现细节。 **2.5 在C中是否有模拟继承等面向对象程序设计特性的好方法?** C语言本身并不支持面向对象编程特性,但可以通过结构体和函数指针来模拟一些概念。例如,可以定义一个结构体包含指向成员函数的指针,从而实现一种简单的多态行为。 **2.6 我遇到这样声明结构的代码: `struct name { int namelen; char namestr[1]; };`** 这种结构体定义利用了“结构体扩展成员”技术,通常与动态内存分配一起使用。虽然这种方法在某些情况下可以节省空间,但要注意它的移植性问题,因为不同的编译器和操作系统可能会有不同的实现。 **2.7 是否有自动比较结构的方法?** C语言标准库并没有提供直接比较整个结构体的函数。可以通过遍历结构体的每个成员并逐个比较来实现手动比较。 **2.8 如何向接受结构参数的函数传入常数值?** 可以使用常量结构体变量作为函数参数。例如,定义一个常量结构体变量,并将它传递给函数。 **2.9 怎样从/向数据文件读/写结构?** 读写结构体到文件可以通过`fwrite()`和`fread()`函数实现。需要注意的是,不同平台的字节序可能导致数据不一致。 **2.10 我的编译器在结构中留下了空洞,这导致空间浪费而且无法与外部数据文件进行”二进制”读写。能否关掉填充,或者控制结构域的对齐方式?** 大多数编译器提供了选项或宏定义来关闭结构体填充。例如,在GCC中可以使用`#pragma pack`来控制对齐。 **2.11 为什么`sizeof`返回的值大于结构的期望值,是不是尾部有填充?** `sizeof`返回的值可能大于结构体实际成员占用的空间,这是因为编译器为了性能考虑会对结构体成员进行填充,以满足特定的对齐要求。 **2.12 如何确定域在结构中的字节偏移?** 可以使用`offsetof`宏来确定结构体成员的字节偏移量。例如,`offsetof(struct name, namestr)`返回`namestr`字段相对于`struct name`起始位置的偏移量。 **2.13 怎样在运行时用名字访问结构中的域?** C语言不支持直接通过名字访问结构体成员。可以在运行时构建一个映射表来间接访问成员,但这通常涉及到额外的数据结构和逻辑。 **2.14 程序运行正确,但退出时却“core dump”了,怎么回事?** “core dump”通常意味着程序在运行过程中遇到了严重错误,如访问无效内存。检查是否正确释放了动态分配的内存,以及是否访问了已释放的内存。 **2.15 可以初始化一个联合吗?** 联合成员只能单独初始化。可以初始化联合中的第一个成员来间接初始化整个联合。 **2.16 枚举和一组预处理的`#define`有什么不同?** 枚举提供了一种类型安全的方式来定义一组命名的整数常量。与`#define`相比,枚举具有更好的类型检查和支持更丰富的语法。 **2.17 有什么容易的显示枚举值符号的方法?** 显示枚举值的符号名称通常需要自定义函数或宏。可以定义一个查找表,将枚举值映射到对应的符号名称。 ### 表达式 **3.1 为什么这样的代码:`a[i] = i++;`不能工作?** 这个表达式中存在副作用,即`i`在被使用后还进行了自增。根据表达式的计算顺序,`i`的值可能在赋值操作之前或之后改变,导致不可预测的结果。 **3.2 使用我的编译器,下面的代码`int i = 7; printf("%d\n", i++ * i++);`返回49?** 这种情况下,表达式的结果依赖于编译器的具体实现。`i`的值在每次自增操作后都会改变,但具体改变的时间点是未定义的。 **3.3 对于代码`int i = 3; i = i++;`不同编译器给出不同的结果,有的为3,有的为4,哪个是正确的?** 这个表达式同样存在副作用。`i++`先返回`i`的旧值,然后才递增`i`。因此,最终结果取决于编译器如何处理这种副作用。 **3.4 这是个巧妙的表达式:`a ^= b ^= a ^= b`它不需要临时变量就可以交换a和b的值。** 这个表达式利用了异或操作的特殊性质来实现值的交换。尽管如此,这种方式不如使用临时变量直观且易于理解。 **3.5 我可否用括号来强制执行我所需要的计算顺序?** 括号可以用来显式指定计算顺序,特别是在涉及多个操作符时尤为重要。例如,`(a + b) * c`确保首先执行加法。 **3.6 可是`&&`和`||`运算符呢?我看到过类似`while ((c = getchar()) != EOF && c != '\n')`的代码...** 逻辑与(`&&`)和逻辑或(`||`)运算符遵循短路求值原则,这意味着如果左侧表达式足以确定整个表达式的值,则右侧表达式不会被计算。 **3.7 我怎样才能理解复杂表达式?“序列点”是什么?** 序列点是一个编译器保证所有副作用都已完成的地方。在C语言中,逗号运算符、赋值运算符和函数调用之后都是序列点。 **3.8 那么,对于`a[i] = i++;`我们不知道`a[]`的哪一个分量会被改写,但`i`的确会增加1,对吗?** 正确。`i++`在表达式中只保证`i`的值最终会增加1,但对于`a[i]`的访问顺序则未定义,可能因编译器而异。 **3.9 `++i`和`i++`有什么区别?** `++i`是前缀自增,它首先增加`i`的值,然后再使用;而`i++`是后缀自增,它先返回`i`的当前值,然后再增加`i`。 **3.10 如果我不使用表达式的值,我应该用`++i`或`i++`来自增一个变量吗?** 如果自增的结果不会被使用,通常建议使用`++i`,因为它通常比`i++`更高效。 **3.11 为什么如下的代码`int a = 100, b = 100; long int c = a * b;`不能工作?** 这个表达式中,`a`和`b`都是`int`类型,它们的乘积也默认为`int`类型。如果乘积超过了`int`的最大值,会导致溢出。为了避免这个问题,可以显式将其中一个操作数转换为`long int`类型,如`long int c = (long int)a * b;`。 **3.12 我需要根据条件把一个复杂的表达式赋值给两个变量中的一个。可以用下边这样的代码吗?`((condition) ? a : b) = complicated_expression;`** 不推荐这样做,因为三元运算符的结果是一个值,而不是一个可赋值的表达式。正确的做法是先计算复杂的表达式,然后根据条件选择赋值的目标变量。 以上是对给定文件内容中提到的一些关键知识点的详细解析,希望对你有所帮助。
剩余152页未读,继续阅读
- 粉丝: 6
- 资源: 10
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
- weixin小程序项目电子竞技信息交流平台+ssm.zip
- 基于MPC的三相变流器设计及仿真,仿真平台基于MATLAB Simulink搭建 内含仿真文件,源代码,设计文档,仿真图 设计文档包括建模,各部分仿真模块设计,控制算法详解
- weixin小程序项目电子购物系统的设计与实现+ssm.zip
- weixin小程序项目电影院订票选座小程序+ssm.zip
- weixin小程序项目大学生闲置物品交易平台的分析与设计+ssm.zip
- weixin小程序项目大学生心理健康服务+ssm.zip
- weixin小程序项目电影院订票选座系统设计及实现+ssm.zip
- weixin小程序项目宠物小程序+ssm.zip
- weixin小程序项目传染病防控宣传系统的设计与实现+springboot.zip
- weixin小程序项目大学生就业平台微信小程序+ssm.zip
- weixin小程序项目畅阅读微信小程序+ssm.zip
- 依据双碳而产生的模型,低碳优化调度 以系统运行维护成本,购能等方向作为优化目标 通过模型计算使各部分能达到最优值 考虑设备有燃气轮机、余热锅炉、燃气锅炉、热泵、电制冷机、储电系统
- 00-【管理制度】07-企业师带徒培训管理制度.doc
- 01-【师带徒协议】03-师带徒协议书.doc
- 01-【师带徒协议】02-师带徒协议书.doc
- 01-【师带徒协议】04-导师辅导协议书(师带徒协议书).docx
- 1
- 2
- 3
- 4
- 5
前往页