C语言陷阱和缺陷
c语言遇到的问题和解决方法
c语言遇到的问题和解决方法C语言是一种广泛使用的编程语言,广泛应用于系统编程、嵌入式系统、游戏开发等领域。
虽然C语言有着广泛的应用,但也存在一些常见问题和解决方法。
以下是一些常见的C语言问题及其解决方法:1. 编译错误编译错误通常是由于语法错误、变量类型错误、数组越界等引起的。
解决方法是仔细检查代码,确保语法正确,变量类型正确,数组边界正确等。
此外,可以使用C编译器提供的调试功能来查找编译错误。
2. 内存泄漏内存泄漏是指在程序运行期间,未释放的内存空间导致程序崩溃。
内存泄漏可能是由于分配的内存对象不再被使用而导致的。
解决方法是在使用内存对象时,要注意内存的分配和释放,避免不必要的内存泄漏。
3. 指针错误指针错误是由于未正确使用指针而导致的。
指针可以用来访问和修改内存中的数据,因此必须正确使用指针。
指针的类型和指向的变量必须正确声明,并且必须在正确的位置使用指针。
此外,还需要避免使用动态内存分配,因为动态内存分配可能会导致指针错误。
4. 运算符重载运算符重载是指程序能够重载算术运算、逻辑运算等基本运算符,使得它们的行为与定义不符。
运算符重载可能会导致程序出现异常,因此必须谨慎使用。
解决方法是仔细阅读C语言标准库中的函数声明,确保函数的行为符合定义。
5. 字符数组大小字符数组的大小必须正确声明并指定。
如果字符数组大小不正确,程序可能会出现字符数组越界的错误。
解决方法是在使用字符数组时,要注意数组的大小,确保数组声明的字符数组大小与变量所指向的字符数组大小相同。
以上是C语言常见问题及其解决方法的示例。
在实际编写C程序时,应该仔细审查代码,确保没有语法错误和内存泄漏等问题。
C语言中常见的安全漏洞及防范方法
C语言中常见的安全漏洞及防范方法C语言作为一种广泛应用于系统开发和嵌入式设备的编程语言,虽然具有高效性和灵活性,但在安全性方面却存在一些常见的漏洞。
本文将介绍C语言中常见的安全漏洞,并提供相应的防范方法。
一、缓冲区溢出漏洞缓冲区溢出是C语言中最常见的安全漏洞之一。
当程序试图向一个已经装满数据的缓冲区写入更多的数据时,就会导致缓冲区溢出。
攻击者可以利用这个漏洞来修改程序的执行流,执行恶意代码或者获取敏感信息。
防范方法:1. 使用安全的函数:应该使用安全的函数,如`strncpy`、`snprintf`等,而不是不安全的函数`strcpy`、`sprintf`等。
安全的函数会检查数据长度,避免发生缓冲区溢出。
2. 输入验证:对于用户输入的数据,应该进行输入验证,确保输入的数据不会超出缓冲区的长度。
3. 使用堆栈保护技术:可以使用堆栈保护技术,如栈溢出检测、堆栈随机化等,在一定程度上提高程序对缓冲区溢出漏洞的防护能力。
二、格式化字符串漏洞格式化字符串漏洞是由于未正确使用格式化字符串函数(如`printf`、`sprintf`等)导致的安全问题。
当攻击者能够控制格式化字符串的参数时,就可能导致信息泄露或者任意代码执行。
防范方法:1. 限制格式化字符串的输入:应该限制用户输入的格式化字符串,确保输入的格式化字符串参数是合法且不含恶意代码。
2. 使用安全的格式化函数:使用安全的格式化函数,如`snprintf`等,这些函数会检查参数的有效性,避免格式化字符串漏洞的发生。
3. 程序审计:对于已经存在的代码,应进行定期的程序审计,识别和修复潜在的格式化字符串漏洞。
三、整数溢出漏洞整数溢出漏洞是由于未对输入数据进行正确的检查和验证,导致整数值超出其数据类型范围,从而引发安全问题。
攻击者可以利用这个漏洞来改变程序的行为,执行未经授权的操作。
防范方法:1. 输入验证:对于用户输入的数据,应该进行输入验证,确保输入的数据范围在合理的范围内。
C语言技术中常见的安全漏洞及预防措施
C语言技术中常见的安全漏洞及预防措施近年来,计算机应用逐渐深入到我们的生活中的各个领域,而软件作为计算机系统中最重要的组成部分之一,其安全性一直备受关注。
在软件开发过程中,C语言常作为首选语言,但由于C语言的灵活性和强大的底层控制能力,导致C语言程序容易受到各种安全漏洞的侵害。
本文将详细介绍C语言技术中常见的安全漏洞以及相应的预防措施。
一、缓冲区溢出缓冲区溢出是C语言中最常见的安全漏洞之一。
它通常出现在程序中使用了不安全的字符串处理函数,如strcpy、strcat等。
当输入的数据超过了目标缓冲区的大小时,溢出数据会覆盖其他内存区域,从而导致程序崩溃或者执行恶意代码。
预防措施:1. 使用安全的字符串处理函数,如strncpy、strncat等,可以指定拷贝或追加的最大长度。
2. 对输入数据进行合法性检查,确保输入长度不超过目标缓冲区的大小。
3. 使用堆栈保护技术,如栈溢出保护(StackGuard)、堆溢出保护(HeapGuard)等。
二、格式化字符串漏洞格式化字符串漏洞也是C语言中常见的安全漏洞之一。
当程序使用了不安全的格式化输出函数,如printf、sprintf等,且使用者可控的输入作为格式化字符串的参数时,就有可能导致格式化字符串漏洞。
预防措施:1. 使用安全的格式化输出函数,如snprintf、sprintf_s等,可以指定输出字符串的最大长度。
2. 避免使用用户可控的输入作为格式化字符串的参数,或者对输入进行严格的合法性检查。
三、整数溢出漏洞整数溢出漏洞常出现在处理算术运算、数组索引等情况下,当一个数值超出了该类型的表示范围时,溢出的部分将被截断,导致运算结果不正确,甚至引发程序崩溃或漏洞利用。
预防措施:1. 在进行数值计算时,进行溢出检查,避免直接使用可能溢出的运算结果。
2. 对于需要存储大数值的情况,采用更加安全的数据类型,如stdint.h头文件中的int64_t等。
四、空指针引用漏洞当程序中对一个空指针进行解引用,即访问空指针所指向的内存区域时,将导致程序崩溃。
(经典)C语言陷阱和缺陷
C语言陷阱和缺陷[1]原著:Andrew Koenig - AT&T Bell Laboratories Murray Hill, New Jersey 07094原文:收藏翻译:lover_P[译序]那些自认为已经“学完”C语言的人,请你们仔细读阅读这篇文章吧。
路还长,很多东西要学。
我也是……[概述]C语言像一把雕刻刀,锋利,并且在技师手中非常有用。
和任何锋利的工具一样,C会伤到那些不能掌握它的人。
本文介绍C语言伤害粗心的人的方法,以及如何避免伤害。
[内容]·0 简介· 1 词法缺陷o 1.1 =不是==o 1.2 &和|不是&&和||o 1.3 多字符记号o 1.4 例外o 1.5 字符串和字符· 2 句法缺陷o 2.1 理解声明o 2.2 运算符并不总是具有你所想象的优先级o 2.3 看看这些分号!o 2.4 switch语句o 2.5 函数调用o 2.6 悬挂else问题· 3 链接o 3.1 你必须自己检查外部类型· 4 语义缺陷o 4.1 表达式求值顺序o 4.2 &&、||和!运算符o 4.3 下标从零开始o 4.4 C并不总是转换实参o 4.5 指针不是数组o 4.6 避免提喻法o 4.7 空指针不是空字符串o 4.8 整数溢出o 4.9 移位运算符· 5 库函数o 5.1 getc()返回整数o 5.2 缓冲输出和内存分配· 6 预处理器o 6.1 宏不是函数o 6.2 宏不是类型定义·7 可移植性缺陷o7.1 一个名字中都有什么?o7.2 一个整数有多大?o7.3 字符是带符号的还是无符号的?o7.4 右移位是带符号的还是无符号的?o7.5 除法如何舍入?o7.6 一个随机数有多大?o7.7 大小写转换o7.8 先释放,再重新分配o7.9 可移植性问题的一个实例·8 这里是空闲空间·参考·脚注0 简介C语言及其典型实现被设计为能被专家们容易地使用。
C语言的优点与缺点
C语言的优点与缺点C语言是一种通用的编程语言,它具有许多优点和一些缺点。
下面是对C语言优点和缺点的详细论述:1.优点:1.1简洁高效:C语言具有简洁高效的特点,它的语法简单明了,代码精炼,适用于开发高效的程序。
1.2应用广泛:C语言具有广泛的应用领域,可以应用于系统编程、嵌入式系统、驱动程序、图形界面、网络应用等多个领域。
许多大型软件项目也是使用C语言开发的。
1.3可移植性强:C语言具有强大的可移植性,可以在不同的硬件平台和操作系统上编写和运行代码。
这使得开发者能够更方便地将程序移植到不同的环境中。
1.4高效的编程能力:C语言提供了丰富的数据类型、运算符和控制结构,使得开发者能够更高效地编写程序。
同时,C语言还提供了强大的指针操作功能,可以更灵活地处理内存和数据。
1.5强大的性能:C语言可以生成高效的机器码,因此在需要高性能的场景下,使用C语言能够获得更好的执行效率。
这使得C语言成为许多计算密集型和实时系统的首选语言。
1.6丰富的库支持:C语言拥有丰富的标准库和第三方库支持,这些库包括数学库、字符串处理库、文件操作库等,为开发者提供了丰富的函数和工具,便于快速开发和调试程序。
1.7易于学习和使用:相对于其他编程语言,C语言具有较低的学习曲线。
它的语法简单明了,没有太多的特殊规则,开发者可以很快上手使用。
2.缺点:2.1缺乏面向对象支持:C语言是一种过程化的语言,没有直接支持面向对象的特性,例如封装、继承和多态等。
这使得开发者在开发大型、复杂的软件项目时需要耗费更多的时间和精力。
2.2缺乏自动内存管理:C语言没有提供自动内存管理的功能,开发者需要手动分配和释放内存。
如果开发者在代码中不小心处理内存,容易导致内存泄漏和段错误等问题。
2.3安全性问题:C语言对于编程错误没有太多的保护机制,例如数组越界、空指针引用等问题,如果开发者不小心处理这些问题,容易导致程序崩溃或安全漏洞。
2.4 较低的抽象层级:C语言的抽象能力相对较低,不如一些面向对象的语言如Java和C#。
c陷阱与缺陷读后感
在阅读《C陷阱与缺陷》这本书之后,我对C语言编程有了更深入的理解和认识。
这本书详细地揭示了C语言中可能出现的陷阱和缺陷,让我意识到编程并非只是写代码,而是需要深入理解语言特性、注意细节、善于发现问题并解决问题。
首先,我了解到C语言虽然功能强大,但也有很多潜在的陷阱和缺陷。
比如,C语言中的指针和内存管理容易让人犯错误,不正确的使用可能导致程序崩溃或者出现不可预期的行为。
此外,C语言中的类型转换和类型提升也可能让人感到困惑,不注意细节就可能导致错误的程序结果。
其次,这本书强调了防御性编程的重要性。
在编程过程中,我们应该始终保持警惕,对可能出错的地方进行预防性编程。
这不仅可以帮助我们发现和避免错误,还可以使我们的程序更加健壮和可靠。
同时,书中还介绍了如何使用一些工具和技术来辅助编程,如代码审查、测试和调试等,这些都是非常有用的实践方法。
最后,我认为这本书对于C语言的学习者和使用者都有很大的参考价值。
通过阅读这本书,我不仅对C语言有了更深入的理解,还学到了很多实用的编程技巧和方法。
这些
知识和经验将对我未来的编程工作产生积极的影响。
总之,《C陷阱与缺陷》是一本非常有价值的书籍,它让我认识到编程不仅需要技术能力,更需要良好的习惯和严谨的态度。
我相信这本书对于任何一位从事编程工作的人都会有很大的帮助。
C语言中常见的安全性问题及解决方案
C语言中常见的安全性问题及解决方案C语言是一种广泛应用于系统软件、嵌入式系统和高性能计算领域的编程语言。
然而,由于其灵活性和底层特性,C语言也存在一些常见的安全性问题。
本文将探讨C语言中常见的安全性问题,并提供一些解决方案。
一、缓冲区溢出缓冲区溢出是C语言中最常见的安全漏洞之一。
当程序试图向一个已满的缓冲区中写入数据时,超出缓冲区边界的数据可能会覆盖其他内存区域,导致程序崩溃或被黑客利用。
为了避免缓冲区溢出,可以采取以下几种措施:1. 使用安全的字符串处理函数,如`strncpy`代替`strcpy`,`strncat`代替`strcat`,并且确保目标缓冲区足够大。
2. 对输入进行验证,确保输入的长度不超过缓冲区的容量。
3. 使用编译器提供的安全选项,如GCC中的`-fstack-protector`选项,可以在编译时检测栈溢出。
二、空指针解引用空指针解引用是另一个常见的C语言安全问题。
当程序试图对空指针进行解引用操作时,会导致程序崩溃。
为了避免空指针解引用,可以采取以下几种措施:1. 在使用指针之前,始终对其进行空指针检查。
2. 在指针解引用之前,使用条件语句判断指针是否为空。
3. 尽量避免使用未初始化的指针。
三、整数溢出整数溢出是C语言中常见的安全问题之一。
当一个整数变量超出其数据类型的表示范围时,会产生溢出,导致计算结果错误或产生未定义行为。
为了避免整数溢出,可以采取以下几种措施:1. 使用适当的数据类型,确保变量能够容纳可能的最大值。
2. 在进行数值计算之前,对参与计算的变量进行范围检查。
3. 使用编译器提供的警告选项,如GCC中的`-Woverflow`选项,可以在编译时检测整数溢出。
四、格式化字符串漏洞格式化字符串漏洞是一种常见的安全漏洞,可以被黑客用于执行任意代码或读取敏感信息。
当程序使用用户提供的格式化字符串作为参数调用`printf`或`sprintf`等函数时,如果没有正确验证输入,黑客可以通过构造恶意格式化字符串来执行任意代码。
黑洞陷阱c语言
黑洞陷阱c语言黑洞陷阱是一个经典的算法问题,通常用于测试编程技能和解决问题的能力。
这个问题要求编写一个程序,该程序接受一个整数数组,并找到一个“黑洞”元素,该元素将数组中的其他元素“吸引”到黑洞中,即每个元素被黑洞吸引后,数组中只剩下一个元素,即黑洞。
下面是一个使用C语言解决黑洞陷阱问题的示例代码:c#include <stdio.h>int main() {int arr[] = {1, 2, 3, 4, 5};int n = sizeof(arr) / sizeof(arr[0]);int i, j, sum = 0;int blackhole;// 计算数组元素的总和for (i = 0; i < n; i++) {sum += arr[i];}// 找到黑洞元素for (i = 0; i < n; i++) {if (sum == 0) {blackhole = arr[i];break;}if (arr[i] == sum) {blackhole = arr[i];break;}sum -= arr[i];}// 将数组中的其他元素“吸引”到黑洞中for (i = 0; i < n; i++) {if (arr[i] != blackhole) {sum += arr[i];}}// 输出结果printf("The blackhole element is %d\n", blackhole);printf("The remaining elements after attracted by the blackholeare %d\n", sum);return 0;}在上面的代码中,我们首先定义了一个整数数组arr,并计算了数组元素的总和。
然后,我们使用一个循环遍历数组,找到黑洞元素。
最后,我们使用另一个循环将数组中的其他元素“吸引”到黑洞中,并输出结果。
c语言遇到的问题、解决方法及结果
C语言遇到的问题、解决方法及结果1.引言C语言作为一种广泛应用的高级编程语言,常常用于开发系统软件、嵌入式软件以及数据结构等领域。
在使用C语言进行开发过程中,我们会遇到各种问题,本文将讨论常见的问题,并提供相应的解决方法及结果。
2.内存管理问题2.1内存泄漏问题描述:C语言中没有自动内存管理机制,因此在使用动态分配内存时,如果没有释放已使用的内存,就会导致内存泄漏。
解决方法:及时释放已使用的内存是避免内存泄漏的关键。
在每次动态分配内存后,务必记得使用`f re e()`函数释放内存。
结果:通过及时释放内存,可以有效避免内存泄漏问题,提高程序的内存利用效率。
2.2指针问题问题描述:由于C语言中指针的概念较为复杂,容易出现指针使用错误、野指针等问题。
解决方法:在使用指针时,需要保证指针的合法性,避免野指针问题。
同时,可以使用调试工具检查指针的值,以便及时发现和修复指针相关的问题。
结果:通过正确使用指针,可以避免指针相关的错误,提高程序的稳定性。
3.编译问题3.1编译错误问题描述:在使用C语言进行开发时,常常会遇到编译错误,如语法错误、缺少头文件等。
解决方法:仔细检查编译错误的提示信息,根据提示信息进行错误排查。
合理使用编译器提供的调试工具,例如使用`-W al l`选项开启所有警告信息,帮助发现潜在的问题。
结果:通过仔细排查编译错误并进行修复,可以确保程序的正确编译,提高开发效率。
3.2编译器兼容性问题描述:不同的编译器可能对C语言标准的支持程度不同,导致同一份代码在不同编译器下的行为不一致。
解决方法:在开发时,要考虑到目标平台使用的编译器,并根据编译器的要求进行相应的调整和优化。
可以使用条件编译等技术,在不同的编译器下使用不同的代码逻辑。
结果:通过确保程序在目标平台下编译通过,可以提高程序的可移植性和兼容性。
4.性能优化问题4.1程序运行缓慢问题描述:C语言程序在运行过程中可能会因为算法设计不合理、性能瓶颈等原因导致运行缓慢。
编程中常见的陷阱及如何避免
编程中常见的陷阱及如何避免在编程过程中,我们常常会遇到各种各样的陷阱,这些陷阱可能会导致bug的产生,代码效率低下,甚至是系统崩溃。
为了提高编程质量,我们应该了解并避免这些常见的陷阱。
本文将介绍一些编程中常见的陷阱,并提供相应的解决方法。
一、空指针异常(Null Pointer Exception)空指针异常是编程中最常见的陷阱之一。
当我们尝试使用未初始化的对象或者空对象时,就会出现空指针异常。
为了避免这个问题,我们应该在使用对象之前,对其进行有效的初始化操作。
在使用对象前,可以通过判断对象是否为空来避免空指针异常的发生。
二、内存泄漏(Memory Leaks)内存泄漏是指在程序运行过程中,由于没有及时释放不再使用的内存,导致内存占用不断增加的问题。
内存泄漏可能会导致系统资源耗尽,进而导致程序崩溃。
为了避免内存泄漏,我们应该注意及时释放不再使用的对象,避免产生无用的引用。
三、数组越界(Array Out of Bounds)数组越界是指当我们尝试访问数组中不存在的索引时,会出现数组越界异常。
为了避免数组越界的问题,我们应该在访问数组元素前,先判断索引是否在合法范围内。
可以使用条件语句或者循环结构来避免数组越界。
四、死锁(Deadlock)死锁是指在多线程编程中,两个或多个线程相互等待对方释放资源,导致程序无法继续执行的情况。
为了避免死锁的发生,我们应该避免使用多个锁,并合理安排代码的执行顺序。
在调试过程中,可以使用死锁检测工具来帮助我们发现潜在的死锁问题。
五、性能问题(Performance Issues)性能问题是指程序在运行过程中,消耗过多的时间或者内存资源,导致程序执行效率低下。
为了避免性能问题,我们可以使用合适的数据结构和算法,避免多余的计算和内存占用。
在编程过程中,可以使用性能分析工具来查找并解决性能问题。
六、安全漏洞(Security Vulnerabilities)安全漏洞是指在程序设计或者实现中存在漏洞,导致系统容易受到攻击或者数据泄露的风险。
C语言技术中需要注意的常见陷阱
C语言技术中需要注意的常见陷阱C语言作为一门广泛应用于系统开发和嵌入式领域的编程语言,其灵活性和高效性备受开发者青睐。
然而,正是由于其底层性质和灵活性,C语言也存在一些常见的陷阱,容易导致程序错误和安全问题。
本文将探讨一些常见的C语言陷阱,并提供相应的解决方案。
1. 内存管理错误C语言中的内存管理是开发者必须重视的问题之一。
常见的内存管理错误包括内存泄漏、野指针和缓冲区溢出。
内存泄漏指的是程序在分配内存后未及时释放,导致内存资源浪费。
野指针则是指指向已经释放或未分配的内存地址,使用野指针可能导致程序崩溃或产生不可预料的行为。
缓冲区溢出是指向数组或缓冲区写入超过其容量的数据,可能导致数据覆盖和安全漏洞。
解决这些问题的方法包括合理使用malloc和free函数进行内存分配和释放、及时检查指针的有效性,以及使用安全的字符串处理函数(如strcpy_s和strcat_s)来避免缓冲区溢出。
2. 整数溢出C语言中整数溢出是一个常见的错误,特别是在进行数值计算时。
当一个整数超过其数据类型所能表示的范围时,会发生溢出,导致结果错误。
例如,当一个无符号整数变量达到最大值后再加1,结果会变为0,而不是正确的数值。
解决整数溢出的方法包括使用适当的数据类型来存储数值,进行溢出检查,以及使用安全的数值计算函数(如加法函数add_with_overflow)来避免溢出问题。
3. 字符串处理C语言中的字符串处理需要格外小心,容易导致缓冲区溢出和安全漏洞。
常见的问题包括未对字符串长度进行检查,使用不安全的字符串处理函数(如strcpy和strcat),以及未对输入进行验证和过滤。
解决这些问题的方法包括使用安全的字符串处理函数(如strncpy和strncat),对字符串长度进行检查,以及对用户输入进行验证和过滤,以防止恶意输入导致的安全问题。
4. 多线程并发在多线程并发编程中,C语言需要特别注意线程同步和竞态条件问题。
竞态条件指的是多个线程同时访问共享资源,导致结果不确定或错误。
C语言常见错误分析汇总
C语言常见错误分析汇总C语言是一种广泛应用的编程语言,但由于语法相对复杂,初学者容易犯一些常见的错误。
下面将汇总一些常见的C语言错误,以便帮助初学者更好地理解和避免这些问题。
1.语法错误:C语言对语法要求非常严格,一些错误的语法表达会导致编译错误。
例如,缺少分号、括号不成对等。
2.逻辑错误:这类错误通常是代码逻辑错误,导致程序运行结果与预期不同。
例如,条件判断错误、循环错误等。
3.变量未初始化:在使用变量之前,未对其进行初始化操作会导致不确定的结果。
这种错误可能会导致程序崩溃或产生意外结果。
4.数组越界:在C语言中,数组的下标从0开始,如果使用了超出数组范围的下标,会导致越界错误。
这可能会修改其他内存空间的值,导致程序错误。
5.内存泄漏:动态分配内存后没有正确释放会导致内存泄漏。
这在长时间运行的程序中可能导致内存耗尽。
6.不匹配的数据类型:数据类型不匹配会导致计算错误或编译错误。
例如,对整型变量使用浮点数运算符,或使用未定义的数据类型。
7.空指针解引用:解引用空指针会导致程序崩溃。
在使用指针之前,一定要确保其指向有效的内存空间。
8.死循环:循环条件错误或循环体内没有正确的终止条件会导致死循环,程序无法正常退出。
9.多次释放同一块内存:多次释放同一块动态分配的内存会导致程序错误或崩溃。
10.缺少返回语句:在函数中缺少返回语句或返回语句在多个分支中没有覆盖所有情况,会导致未定义的行为。
11.使用未定义的变量:在使用变量之前,必须先定义该变量。
否则会导致编译错误。
12.逻辑短路错误:逻辑运算符中,逻辑短路原则是如果已经可以确定逻辑表达式的结果,后续的表达式不会被执行。
如果依赖于后续表达式的计算结果,会导致逻辑错误。
13.误解优先级和结合性:C语言中运算符有优先级和结合性,如果不理解运算符的优先级和结合性,会导致计算错误。
14.使用未声明的函数:在调用函数之前,必须先声明函数。
否则会导致编译错误。
15. 不正确的格式化字符串:在使用printf等函数进行格式化输出时,必须提供与格式字符串匹配的参数,否则会导致未定义的行为。
c语言进阶的书籍
c语言进阶的书籍C语言是一门广泛应用于系统开发、嵌入式系统和科学计算等领域的编程语言。
对于初学者来说,学会基本的语法和常用的函数可能并不困难,但要想进一步提升自己的C语言编程能力,深入理解C 语言的特性和高级技巧是必不可少的。
下面我将为大家推荐几本适合进阶学习的C语言书籍。
1.《C专家编程》《C专家编程》是由Peter Van der Linden所著,是一本经典的C语言进阶书籍。
该书通过大量实例和深入的讲解,帮助读者掌握C语言的高级编程技巧和陷阱避免方法。
涵盖了指针、内存管理、函数指针、位操作等高级主题,对于想要成为C语言专家的读者来说是一本不可多得的参考书。
2.《C陷阱与缺陷》《C陷阱与缺陷》是由Andrew Koenig和David R. Hanson合著,是一本揭示C语言常见陷阱和缺陷的书籍。
通过对各种C语言常见错误的深入分析和解释,帮助读者避免在编程中犯类似错误。
阅读该书可以帮助读者更加深入地理解C语言的语法和语义,提高编程的准确性和效率。
3.《C和指针》《C和指针》是由Kenneth A. Reek所著,是一本重点讲解C语言指针的书籍。
指针是C语言中非常重要的概念,也是初学者常常困惑的地方。
该书通过大量的示例和详细的讲解,帮助读者理解指针的概念、用法和实际应用。
掌握指针的知识可以提高编程的灵活性和效率,是进阶学习C语言的重要一步。
4.《深入理解计算机系统》《深入理解计算机系统》是由Randal E. Bryant和David R. O'Hallaron合著,虽然不是一本专门讲解C语言的书籍,但对于想要深入理解C语言底层原理和系统编程的读者来说是一本非常有价值的参考书。
该书通过介绍计算机系统的各个层次,包括硬件、操作系统和编译器等,帮助读者理解C语言程序在计算机系统中的运行机制和优化方法。
5.《C程序设计语言》《C程序设计语言》是由Brian W. Kernighan和Dennis M. Ritchie合著,被誉为C语言的圣经。
C语言中的常见错误及解决方法
C语言中的常见错误及解决方法C语言是一门广泛应用于计算机编程领域的高级编程语言。
它的简洁性和高效性使得它成为了许多程序员的首选。
然而,即使对于有经验的程序员来说,C语言中也存在一些常见的错误。
本文将探讨一些常见的C语言错误,并提供相应的解决方法。
1. 内存泄漏内存泄漏是C语言中最常见的错误之一。
它发生在程序分配了内存空间,但在使用完毕后未正确释放。
这导致内存空间被占用,最终可能导致程序崩溃或者系统变慢。
解决方法:- 使用malloc函数分配内存后,一定要使用free函数释放内存。
- 为了避免出现遗漏的情况,可以在每次使用完内存后立即释放。
2. 数组越界在C语言中,数组越界是一个常见的错误。
当程序试图访问数组中超出其边界的元素时,会导致未定义的行为,可能引发程序崩溃或产生错误的结果。
解决方法:- 在使用数组时,一定要确保索引值不会超出数组的边界。
- 可以使用循环结构和条件语句来检查数组索引的合法性。
3. 未初始化变量在C语言中,未初始化变量的使用是一个常见的错误。
当程序试图使用未初始化的变量时,它的值是不确定的,可能导致程序产生错误的结果。
解决方法:- 在使用变量之前,一定要确保它已经被正确地初始化。
- 可以使用赋值语句或者初始化函数来初始化变量。
4. 类型不匹配类型不匹配是C语言中另一个常见的错误。
它发生在程序试图将一个类型的值赋给另一个类型的变量,或者将不同类型的变量进行运算。
解决方法:- 在进行类型转换时,可以使用强制类型转换运算符来确保类型匹配。
- 在进行运算时,要确保参与运算的变量类型一致。
5. 逻辑错误逻辑错误是指程序中的逻辑错误或算法错误。
这种错误不会导致程序崩溃,但会导致程序产生错误的结果。
解决方法:- 仔细检查程序中的逻辑,确保算法的正确性。
- 使用调试工具来跟踪程序的执行过程,找出错误所在。
总结:C语言中的常见错误包括内存泄漏、数组越界、未初始化变量、类型不匹配和逻辑错误。
为了避免这些错误,程序员应该养成良好的编程习惯,如及时释放内存、检查数组索引的合法性、正确初始化变量、确保类型匹配和仔细检查程序逻辑。
C语言中的常见错误及解决方法
C语言中的常见错误及解决方法C语言作为一种广泛应用于软件开发领域的编程语言,常常出现一些让初学者或经验不足的程序员困惑的错误。
本文将介绍C语言中常见的错误,并提供解决这些错误的方法。
一、语法错误语法错误是编程过程中最常见的错误之一。
它们通常由于代码中存在语法错误或书写错误而导致。
以下是一些常见的语法错误和解决方法:1.1 缺少分号分号是C语言中语句结束的标志,如果未在语句末尾添加分号,编译器会报错。
解决方法是仔细检查代码,确保每个语句的末尾都有分号。
1.2 括号不匹配在C语言中,括号必须成对出现。
如果括号未正确匹配,编译器会报错。
解决方法是仔细检查代码,确保每个左括号都有对应的右括号。
1.3 大小写错误C语言对大小写敏感,因此函数和变量的命名必须与其声明中的大小写完全匹配。
解决方法是检查代码中的命名,并确保其大小写匹配。
1.4 未定义的变量使用未定义的变量会导致编译器报错。
解决方法是确保在使用变量之前先进行声明或定义。
二、逻辑错误逻辑错误在语法上没有问题,但程序的逻辑流程存在缺陷,导致程序运行不符合预期。
以下是一些常见的逻辑错误和解决方法:2.1 数组越界访问在C语言中,数组的索引从0开始。
如果超出数组的索引范围进行访问,会导致程序崩溃或产生意想不到的结果。
解决方法是检查数组索引,并确保它们在合法范围内。
2.2 逻辑运算错误逻辑运算符(如&&、||和!)在C语言中用于组合表达式。
但是,如果这些运算符的使用不当,可能会导致逻辑错误。
解决方法是仔细检查逻辑运算表达式,并确保其符合预期的逻辑规则。
2.3 循环错误循环是C语言中常用的结构之一,但循环中的错误可能导致程序无限循环或不执行循环体。
解决方法是检查循环条件和循环变量,确保它们能正确地控制循环的执行。
三、内存错误内存错误是C语言中常见的错误类型之一。
以下是一些常见的内存错误和解决方法:3.1 内存泄漏内存泄漏指的是在程序中未正确释放分配的内存空间。
C语言的缺点有哪些
C语言的缺点有哪些
C语言是一门通用计算机编程语言,应用广泛。
C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。
接下来,小编为您介绍了C语言的缺点,一起辩*看看吧!
1、C语言它的最大的缺点就是,如果你的项目很复杂,大量的开发人员互相之间需要更新大段代码时,C语言可能会使事情变得异常麻烦。
因为C是在面向对象方法流行之前开发的,这大大降低了C语言复杂设计的可能*。
(不要以为C语言做不了大项目--世界上有太多的经典都是用C语言完成的,如果你想了解C语言的能力,不妨看看QUAKE3的源代码——很敬佩ID的无私,这份代码完全是公开的,任何人都可以使用它与修改它。
);
2、输入输出相对很多语言都较为复杂。
对于字符串的处理,只能通过字符数组实现。
绘图*作较为复杂;
3、C语言的缺点主要表现在数据的封装*上,这一点使得C在数据的安全*上有很大缺陷,这也是C和C++的一大区别;
4、C语言的语法限制不太严格,对变量的类型约束不严格,影响程序的安全*,对数组下标越界不作检查等。
从应用的角度,C语言比其他高级语言较难掌握;
5、指针是C语言的一大特*,可以说是C语言优于其它高级语言的一个重要原因。
就是因为它有指针,可以直接进行靠近硬件的*作,但是C的指针*作也给它带来了很多不安全的因素。
C++在这方面做了很好的改进,在保留了指针*作的同时又增强了安全*。
Java取消了指针*作,提高了安全*;
6、类型检查机制相对较弱、缺少支持代码重用的语言结构。
c陷阱与缺陷《C陷阱和缺陷》读书笔记 ——前车的覆 后车的鉴
c陷阱与缺陷:《C陷阱和缺陷》读书笔记——前车的覆 后车的鉴疯狂代码 / ĵ:http://BlogDigest/Article76354.html《C陷阱与缺陷》,作者:Andrew Koenig [美], 译:高 巍 。
; ; ; 这本书是作者以自己发表过的一篇论文为基础,结合自己的工作经验扩展而成。
我看过之后“吃了一斤”,它跟以往我看过的教程完全不一样,它涉及到C的各个方面,细微、精辟。
用两个字形容,那就是实用。
我不打算把整本书抄一遍,只对我认为“比较重要”(其实没有哪一点是不重要的)的部分做了笔记,并且是简要提取了其中的主要内容,以及相应的小例子,希望再次回顾的时候提高效率。
如果你感到意犹未尽,可以下载来看。
C陷阱与缺陷 下载 ; 1.1 = 不同于 ==; ; ; 来看这样一个例子,while (c=' ' || c== '\t' || c=='\n'); ; ; c = getc(f);; ; ; 由于程序员在比较字符‘ ’和变量c时,误将 == 写成 = ,那么while后的表达式恒为 1,因为' '不等于零,它的ASCII码值为32。
; ; ; 为了避免这种情况,我们可以这样写 while(''==c || '\t'== c || '\n'==c) ,这样即使不小心将 == 写成 =,编译器也会报错。
; ★ ★ 在C中,单引号括起来表示一个整数,双引号括起来表示指针。
例如,字符和字符串。
1.3 词法分析中的“贪心法”; ; ; C编译器读入一个符号的规则:每一个符号应该包含尽可能多的字符,方向为自左向右。
; ; ; 例如,a---b <==> (a--) -b; ; ; 而 y = x/*p; 中 /* 被编译器理解为一段注释的开始,如果本意是用x除以p所指向的值,应该重写如下y = x/ *p; 或更加清楚一点,写作 y = x/(*p);; ★ ★ 在用双引号括起来的字符串中,注释符 /* 属于字符串的一部分,而在注释中出现的双引号""属于注释的一部分。
不要这样学习C语言,这是个坑!
不要这样学习C语言,这是个坑!对于大部分初学者,学习C语言的目的是希望做一名合格的程序员,开发出靠谱的软件来。
但是学了C语言的基本语法后,发现只能开发“黑底白字”的DOS程序,完全没有漂亮的界面和生动的交互。
于是学数据结构,学算法,越陷越深,越来越难,最后迷失了,不知道学C语言能做什么,认为学习编程很难。
其实,这是很多初学者都会踩到的一个坑!C语言本身是一门很简单的语言,提供的实用功能不多,大部分要借助操作系统和其他库来完成。
第一阶段:学习软件开发基础1) 首先学习C语言的基础语法,也就是本教程的前十章,这些都是编程的基础。
2) 学习Windows开发,你就能够使用C语言开发出带界面的软件来了,可以有窗口、输入框、菜单等,也可以响应键盘和鼠标事件,可以播放音乐、视频等。
但是,你会发现比较麻烦,要使用很多API,还要手动写资源脚本。
3) 学习Visual C++开发,通过VC或VS来拖拽各种控件、编辑各种参数。
这个时候,你就可以用C语言做出小规模的软件了,了解了软件的底层是怎么回事,也学会了使用VC或VS来编辑界面。
第二阶段:提高软件开发效率Windows API是软件开发的基础,如果你希望走得更加长远,拿到的工资更高,跟大家拉开差距,那么一定要学。
接下来是提高开发效率,有好几条路可以选择,众多大神争论不一。
第一条路:学习C++,包括C++基础语法、MFC、QT等。
MFC 和QT都是界面库,对Windows API做了封装,会大大提高开发效率。
第二条路:学习C#。
C#语言本身对底层API做了很好的封装,可以使用面向对象的方式来开发软件。
第三条路:学习Delphi。
Delphi是著名的Borland(现在已和Inprise合并)公司开发的可视化软件开发工具。
“聪明的程序员用Delphi,真正的程序员用C++,偷懒的程序员用PowerShell”已经成为对 Delphi 的最真实写照。
一款大型软件,例如QQ、迅雷、360 等,往往是多种技术的集合。
黑洞陷阱c语言 -回复
黑洞陷阱c语言-回复什么是黑洞陷阱?黑洞陷阱是一种在计算机编程中常见的陷阱。
当开发人员不小心或不正确地编写代码时,程序可能会陷入一个无限循环或无法正常退出的状态。
这种情况被称为黑洞陷阱,因为它像是代码被吸入了一个黑洞一样,无法自由运行。
为什么会出现黑洞陷阱?黑洞陷阱通常是由编程错误引起的。
这些错误有很多种,包括逻辑错误、语法错误、模块间的错误调用等等。
当这些错误出现时,程序可能会出现无限循环、死锁或其它无法正常退出的情况。
这些错误可能是由于编写的代码逻辑有问题,导致程序陷入无限循环的状态。
比如,一个简单的错误可能是忘记增加循环变量的值,导致循环条件永远为真。
另外,如果不正确地使用锁或者线程同步机制,可能会导致死锁的情况,使程序陷入无法退出的状态。
黑洞陷阱还可能发生在递归函数的使用中。
如果递归函数没有正确地设置递归终止条件,那么程序将永远不会结束,进入无限循环的状态。
如何避免黑洞陷阱?避免黑洞陷阱是一项重要的任务,它可以提高程序的稳定性和可靠性。
下面是一些避免黑洞陷阱的方法:1. 仔细检查代码逻辑:在编写代码之前,仔细思考代码的逻辑,确保所有分支和条件都正确处理,并且不会导致无限循环或死锁的情况。
2. 对代码进行测试:在编写完代码后,进行测试是非常重要的。
通过编写测试用例,并运行这些测试用例,可以发现代码中的错误和潜在的黑洞陷阱。
测试是一种非常重要的工具,可以帮助开发人员找出并修复代码中的问题。
3. 使用调试工具:调试工具是开发人员的得力助手,可以帮助开发人员分析程序的执行过程,找到代码中的错误位置,并进行修复。
调试工具可以提供断点、变量跟踪等功能,帮助开发人员更好地理解程序的执行过程。
4. 学习和应用最佳实践:学习和应用最佳实践是避免黑洞陷阱的关键。
了解编程语言的最佳实践,并将其应用于代码编写过程中,可以大大减少出现黑洞陷阱的概率。
总结:黑洞陷阱是计算机编程中常见的陷阱,它可能导致程序进入无限循环或无法正常退出的状态。
c语言return 的用法
c语言return 的用法在C语言中,return语句是一个非常重要的控制流工具,它用于在函数执行结束时返回一个值给调用者。
这个返回的值可以是任何数据类型,包括基本数据类型和复杂数据结构,如数组、结构体等。
本文将详细介绍return语句的用法、注意事项以及一些常见的错误和陷阱。
一、return语句的基本用法return语句用于结束函数的执行,并将一个值返回给调用者。
在C语言中,函数返回值必须与函数声明的类型一致。
如果函数没有返回值,则可以使用void 类型。
下面是一个简单的示例:```c#include <stdio.h>int add(int a, int b) {return a + b; // 返回两个参数的和}int main() {int result = add(2, 3); // 调用add函数并保存返回值printf("%d\n", result); // 输出结果5return 0; // 程序正常结束}```在上面的示例中,add函数返回两个参数的和,并在执行结束后使用return 语句返回结果。
在main函数中,我们调用add函数并将返回值保存到result变量中,最后输出结果。
二、return语句的注意事项1. 返回值类型必须与函数声明一致。
如果函数声明为返回int类型,则必须返回一个int类型的值。
否则,编译器会报错。
2. 函数内部的数据必须适当地被清理和释放,以确保不会造成内存泄漏或资源泄露。
如果函数中使用了动态分配的内存或文件描述符等资源,必须在使用完毕后释放它们。
3. 不要在函数内部使用非法的内存地址或无效的指针进行操作。
这可能会导致程序崩溃或数据损坏。
4. 在多线程环境中,使用return语句时要特别小心。
如果多个线程同时访问和修改同一个变量或数据结构,可能会导致数据竞争和不一致的结果。
三、常见的错误和陷阱1. 忘记使用return语句:有些开发者在函数执行结束后没有使用return语句返回值,导致调用者无法获取到正确的结果。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
在本文中,我们将会看到这些未可知的益处。正是由于它的未可知,我们无法为其进行完全的分类。不过,我们仍然通过研究为了一个C程序的运行所需要做的事来做到这些。我们假设读者对C语言至少有个粗浅的了解。
第一部分研究了当程序被划分为记号时会发生的问题。第二部分继续研究了当程序的记号被编译器组合为声明、表达式和语句时会出现的问题。第三部分研究了由多个部分组成、分别编译并绑定到一起的C程序。第四部分处理了概念上的误解:当一个程序具体执行时会发生的事情。第五部分研究了我们的程序和它们所使用的常用库之间的关系。在第六部分中,我们注意到了我们所写的程序也许并不是我们所运行的程序;预处理器将首先运行。最后,第七部分讨论了可移植性问题:一个能在一个实现中运行的程序无法在另一个实现中运行的原因。
在这一节中,我们将探索对记号的意义的普遍的误解以及记号和组成它们的字符之间的关系。稍后我们将谈到预处理器。
1.1 = 不是 ==
从Algol派生出来的语言,如Pascal和Ada,用:=表示赋值而用=表示比较。而C语言则是用=表示赋值而用==表示比较。这是因为赋值的频率要高于比较,因此为其分配更短的符号。
或者干脆是
y = x / (*p) /* p指向除数 */;
它就可以做注释所暗示的除法了。
这种模棱两可的写法在其他环境中就会引起麻烦。例如,老版本的C使用=+表示现在版本中的+=。这样的编译器会将
a=-1;
视为
a =- 1;
或
a = a - 1;,考虑下面的语句:
if(x > big) big = x;
该语句中的每一个分离的字符都被划分为一个记号,除了关键字if和标识符big的两个实例。
事实上,C程序被两次划分为记号。首先是预处理器读取程序。它必须对程序进行记号划分以发现标识宏的标识符。它必须通过对每个宏进行求值来替换宏调用。最后,经过宏替换的程序又被汇集成字符流送给编译器。编译器再第二次将这个流划分为记号。
4.9 移位运算符
5 库函数
5.1 getc()返回整数
5.2 缓冲输出和内存分配
6 预处理器
6.1 宏不是函数
6.2 宏不是类型定义
7 可移植性缺陷
7.1 一个名字中都有什么?
7.2 一个整数有多大?
7.3 字符是带符号的还是无符号的?
7.4 右移位是带符号的还是无符号的?
[内容]
0 简介
1 词法缺陷
1.1 = 不是 ==
1.2 & 和 | 不是 && 和 ||
1.3 多字符记号
1.4 例外
1.5 字符串和字符
2 句法缺陷
2.1 理解声明
2.2 运算符并不总是具有你所想象的优先级
2.3 看看这些分号!
2.4 switch语句
表示表达式ff()是一个float,因此ff是一个返回一个float的函数。类似地,
float *pf;
表示*pf是一个float并且因此pf是一个指向一个float的指针。
这些形式的组合声明对表达式是一样的。因此,
float *g(), (*h)();
表示*g()和(*h)()都是float表达式。由于()比*绑定得更紧密,*g()和*(g())表示同样的东西:g是一个返回指float指针的函数,而h是一个指向返回float的函数的指针。
2 句法缺陷
要理解C语言程序,仅了解构成它的记号是不够的。还要理解这些记号是如何构成声明、表达式、语句和程序的。尽管这些构成通常都是定义良好的,但这些定义有时候是有悖于直觉的或混乱的。
在这一节中,我们将着眼于一些不明显句法构造。
2.1 理解声明
我曾经和一些人聊过天,他们那时正在在编写在一个小型的微处理器上单机运行的C程序。当这台机器的开关打开的时候,硬件会调用地址为0处的子程序。
a = -1;
的程序员感到吃惊。
另一方面,这种老版本的C编译器会将
a=/*b;
断句为
a =/ *b;
尽管/*看起来像一个注释。
1.4 例外
组合赋值运算符如+=实际上是两个记号。因此,
a + /* strange */ = 1
和
a += 1
float f, g;
说明表达式f和g——在求值的时候——具有类型float。由于待求值的是表达式,因此可以自由地使用圆括号:
float ((f));
这表示((f))求值为float并且因此,通过推断,f也是一个float。
同样的逻辑用在函数和指针类型。例如:
float ff();
2.5 函数调用
2.6 悬挂else问题
3 连接
3.1 你必须自己检查外部类型
4 语义缺陷
4.1 表达式求值顺序
4.2 &&、||和!运算符
4.3 下标从零开始
4.4 C并不总是转换实参
4.5 指针不是数组
4.6 避免提喻法
4.7 空指针不是空字符串
4.8 整数溢出
是一个意思。看起来像一个单独的记号而实际上是多个记号的只有这一个特例。特别地,
p - > a
是不合法的。它和
p -> a
不是同义词。
另一方面,有些老式编译器还是将=+视为一个单独的记号并且和+=是同义词。
1.5 字符串和字符
单引号和双引号在C中的意义完全不同,在一些混乱的上下文中它们会导致奇怪的结果而不是错误消息。
1.3 多字符记号
一些C记号,如/、*和=只有一个字符。而其他一些C记号,如/*和==,以及标识符,具有多个字符。当C编译器遇到紧连在一起的/和*时,它必须能够决定是将这两个字符识别为两个分离的记号还是一个单独的记号。C语言参考手册说明了如何决定:“如果输入流到一个给定的字符串为止已经被识别为记号,则应该包含下一个字符以组成能够构成记号的最长的字符串”([译注]即通常所说的“最长子串原则”)。因此,如果/是一个记号的第一个字符,并且/后面紧随了一个*,则这两个字符构成了注释的开始,不管其他上下文环境。
而实际上是将x设置为y的值并检查结果是否非零。再考虑下面的一个希望跳过空格、制表符和换行符的循环:
while(c == ' ' || c = '\t' || c == '\n')
c = getc(f);
在与'\t'进行比较的地方程序员错误地使用=代替了==。这个“比较”实际上是将'\t'赋给c,然后判断c的(新的)值是否为零。因为'\t'不为零,这个“比较”将一直为真,因此这个循环会吃尽整个文件。这之后会发生什么取决于特定的实现是否允许一个程序读取超过文件尾部的部分。如果允许,这个循环会一直运行。
下面的两个程序片断是等价的:
printf("Hello world\n");
char hello[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\n', 0 };
printf(hello);
使用一个指针来代替一个整数通常会得到一个警告消息(反之亦然),使用双引号来代替单引号也会得到一个警告消息(反之亦然)。但对于不检查参数类型的编译器却除外。因此,用
这样可以清晰地表示你的意图。
1.2 & 和 | 不是 && 和 ||
容易将==错写为=是因为很多其他语言使用=表示比较运算。 其他容易写错的运算符还有&和&&,以及|和||,这主要是因为C语言中的&和|运算符于其他语言中具有类似功能的运算符大为不同。我们将在第4节中贴近地观察这些运算符。
此外,C还将赋值视为一个运算符,因此可以很容易地写出多重赋值(如a = b = c),并且可以将赋值嵌入到一个大的表达式中。
这种便捷导致了一个潜在的问题:可能将需要比较的地方写成赋值。因此,下面的语句好像看起来是要检查x是否等于y:
if(x = y)
foo();
[修订说明]
改正了文中的大部分错别字和格式错误,并对一些句子依照中文的习惯进行了改写。
[译序]
那些自认为已经“学完”C语言的人,请你们仔细读阅读这篇文章吧。路还长,很多东西要学。我也是……
[概述]
C语言像一把雕刻刀,锋利,并且在技师手中非常有用。和任何锋利的工具一样,C会伤到那些不能掌握它的人。本文介绍C语言伤害粗心的人的方法,以及如何避免伤害。
7.5 除法如何舍入?
7.6 一个随机数有多大?
7.7 大小写转换
7.8 先释放,再重新分配
7.9 可移植性问题的一个实例
8 这里是空闲空间
参考
脚注
0 简介
C语言及其典型实现被设计为能被专家们容易地使用。这门语言简洁并附有表达力。但有一些限制可以保护那些浮躁的人。一个浮躁的人可以从这些条款中获得一些帮助。
下面的语句看起来像是将y的值设置为x的值除以p所指向的值:
y = x/*p /* p 指向除数 */;
实际上,/*开始了一个注释,因此编译器简单地吞噬程序文本,直到*/的出现。换句话说,这条语句仅仅把y的值设置为x的值,而根本没有看到p。将这条语句重写为:
y = x / *p /* p 指向除数 */;