常见的c语言的编程问题,C语言编程中的常见问题

【摘要】C语言的发展伴随着计算机的发展历程,最初程序设计的基本概念、基本思想等都孕育其中,它一直是刚入学的大学新生普遍反映难学的科目之一,在学习过程中遇到各种常见又突出的问题,比如缓冲区溢出、指针和系统调用等等,本文对这些问题提出了解决的办法。

【关键词】堆栈;缓冲区;函数调用;指针

中图分类号:TP39文献标识码A文章编号1006-0278(2015)09-122-01

C语言是一种面向过程的计算机语言,它的表现能力和处理能力极强,具有丰富的运算符和数据类型,便于实现各类复杂的数据结构。它还可以直接访问内存的物理地址,进行基于bit位的操作。它的编写不依赖计算机硬件的应用程序,又可以编写多种程序。

虽然C语言具备多种优点,但也其存在着不少的缺点。常常会出现很多问题从而导致程序运行错误。循环语句是一个非常好的结构,它可以节省很多代码,使程序代码看起来非常简单。而对于嵌套循环更是非常精妙,能够解决很多问题,但是由于内循环和外循环的退出条件不同,在某种没有考虑到的异常情况下容易导致死循环,从而造成灾难性的后果。因此,对于一个可靠性要求比较高的程序来说,尽可能减少嵌套循环的使用,只要有可能就把它写成几个单独的循环,对于有十足把握的嵌套循环,也不建议使用。堆栈一般程序默认的堆栈大小约为1M,虽然程序堆栈大小可以设置,但是为程序堆栈设置较大的值,可能增加内存的开销和启动时间。因此在程序设计时不盲目的为程序设置很大的堆栈空间。因此对于一个大型程序开发,必须要考虑每个函数的堆栈的使用,对于多线程来说,每个函数尽可能节省有限的堆栈空间。特别忌讳在函数中定义局部变量的大型数组,如果在函数中定义一个局部变量的大型数组,就有可能导致定义的数组覆盖堆栈段或代码段中的数据,从而造成程序的崩溃。为节省有限的堆栈段空间:避免使用局部变量的大型数组;尽量避免用长调用或递归函数;避免传递大型结构体,建议用指针代替;定义短寿命变量(像auto类型)。在熟悉汇编语言的人眼里,C语言编写的程序不值得一提,就像C语言和其它高级语言相比。这种说法虽然有些偏激,但是却有它的道理,因为汇编语言是效率最高的计算机语言。不过汇编语言也有它明显的缺点,它太繁琐,不宜阅读,我们不能用汇编语言来写一个几十万行没有什么人能够读懂代码的程序。所以,为了写一个复杂的大型软件,同时为了获得程序的高效率,我们可以采用变通的方法,在C代码中嵌入汇编,混合编程。这样既提高了效率,又增加了可读性。

上面几种问题是初学者经常遇到的几种典型问题,随着学习的深入,还有一些初学者不易发现的问题也是至关重要的。

一、缓冲区溢出问题

缓冲区用于存放给定类型的数据,是内存的连续块。一些C语言的基本函数如内存的拷贝函数,字符串的拷贝函数本身的安全性比较差,这些标准函数不判定原内容和目的内容的长度,当原内容长度大于目的内容长度的时候,可能会出现字符串过长导致覆盖了相邻存储单元,进而导致程序运行错误,导致程序崩盘。

这种情况可以在编写的代码中检查所有对数组的读/写操作,以确保对数组的操作在正确的范围,但是这样会使程序在性能上受到很大影响。例如strcpy函数经常被用错,进而造成了缓冲区溢出的风险。在执行strcpy函数前,必须保证目标源有足够的空间容纳数据,这个是极为重要的。另外,对源数据存储空间的限制也是一种较好的办法,这不仅会使得应用程序更为有效,而且也降低了缓冲区溢出问题。当然这个函数相对应的安全函数是strncpy函数。但这个函数常见的错误就是在人们对于这个函数的count值计算来源:很多人是用目标缓冲区的字节总数作为count值,而实际上应该是留在缓冲区的字符数目作为count值。

二、指针的使用

C语言的难点和精华就是C语言的指针,指针的种类就有很多,例如:整数指针变量、字符指针变量、指向整数指针的指针、整数数组指针、整数指针数组、指向整数数组指针的指针等。对于初学者来说,还没有看完估计就没有信心了。其实指针也非常简单,别看它的定义很复杂,和普通变量相比,普通变量是用来表示一个数据,每一个数据都存在计算机的地址中;而指针是用来表示一个计算机的地址,对于一个32位程序,所有类型的指针的值都是一个32位整数,它的值是0x0000-0xffff中的一个。只要把指针理解为汇编中的计算机内存地址,应该就能更好的理解指针的功能了。上面这些指针是比较常见的,其实C语言中还有一种“野指针”,我们都知道“野指针”不是NULL指针,是指向“垃圾”内存的指针。“野指针”是很危险的,有时会让人误以为该指针合法,有时候会让程序崩溃。

避免“野指针”的产生要注意这几种情况,例如:指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的;第二种是指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针;第三种情况发生在指针操作超越了变量的作用域范围。

三、系统调用

系统调用就是在用户层和核心层之间的层次与接口。系统调用模块的预先设定,提供了用户与应用程序的核心程序服务。在一般的操作系统中,只有操作系统才能有权访问系统硬件,而用户和程序是无法对设备直接访问。所以需要系统调用来为应用程序提供硬件资源或重要软件资源。

在进行编程的时候尽量保证机密数据不出现在自己编写的任何临时文件。如果必须要包含机密数据,那么需要对文件设置进行权限设置,以保证临时文件仅可由自己读写,只需要在程序运行前调用umask(077),如果对权限更改,其他人可以对文件可读,那么就调用chmod(),当然也可以通过建立隐藏临时文件来解决。还有一种情况就是确保要运行的命令(system(),open(),execlp()运行命令)的确是自身需要运行的命令,而不是其他命令,特别是SUID或SGID许可时要小心。由于(system(),open(),execlp()在执行时,如果不给于执行路径,那么很容易引导用户去执行其他命令。最为安全的方式就是在调用system()前把有效的转化成实际的UID;另外一种可取的方式就是将全路径命令作为参数。

本文从几个问题出发,对C语言中堆栈,指针,系统调用等问题的产生和解决进行了分析探讨。但由于作者水平有限,无法对C语言编程中出现的的所有问题进行全面分析,未来还有待扩充和更为详细的验证。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值