作者:巨同升

“C语言程序设计”这门课程在国内高校普遍开设已有近三十年,课程的建设和研究取得了长足的进步,涌现出了数量众多、各具特色的C语言教材。尽管如此,在许多C语言教材中还或多或少地存在着一些不准确甚至是值得商榷的说法。下面将对国内教材中常见的几种说法进行辨析,并期望与广大同行商榷。

1. 关于C语言的输入输出语句

有的教材中说“C语言中没有输入输出语句,只有输入输出函数”,果真如此吗?

完整的C语言是由语言标准和标准库两部分组成的[1]。语言标准相当于C语言的内核,标准库(主体是库函数)相当于C语言的扩展部分。这种设计极大地增强了C语言实现的灵活性和程序的可移植性,因为可以根据某类计算机的硬件特点而单独修改C语言标准库部分的实现。

在C语言的语言标准部分的确没有输入输出语句,也没有输入输出函数。不过在C语言的标准库部分,明确地定义了各种输入输出函数,从而可以在C语言程序中以语句的形式来调用这些输入输出函数。

既然这种函数调用语句可以实现输入输出的功能,将它们称为“输入输出语句”(而不必称为输入输出函数调用语句)也是顺理成章的。

因此正确的说法是:在C语言的语言标准部分没有输入输出语句,但在C语言的标准库部分有输入输出函数,从而在完整的C语言中有输入输出语句。

2.关于八进制和十六进制负整数

有的教材中说“在C语言中,八进制和十六进制整数只有正数,没有负数”,这种说法是有问题的。实际上,在C语言中,八进制和十六进制整数既可以使用正数,也可以使用负数。下面的程序就是一个很好的证据。

#include <stdio.h>

int main(void)

{int a,b,c,d;

a=0127;

b=-0127;

c=0x1af;

d=-0x1af;

printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);

printf("a=%o,b=%o,c=%x,d=%x\n",a,b,c,d);

return 0;

}

该程序的运行结果如下图所示。

从该程序的运行结果可以发现,程序中可以使用八进制和十六进制的负整数,但是不能以负数形式输出八进制和十六进制的整数。

因此正确的说法是:在C语言中,以八进制和十六进制形式输出整数时,只能输出正数和0,不能输出负数。

3. 关于整数在内存中的表示形式

有的教材中说“在C语言中,整数是以二进制补码的形式在内存中存储的”。其实,这种说法是不准确的。在C语言中,有符号整数的确是以二进制补码形式在内存中存储的,其最高位为符号位,用以表示该整数的正负。但是对于无符号整数来说,由于不存在负数,并不需要表示正负的符号位,因而它的每一位都是数值位,这种表示形式应称为“无符号二进制形式”。

因此正确的说法是:在C语言中,有符号整数是以二进制补码形式在内存中存储的,无符号整数是以无符号二进制形式在内存中存储的。

4. 关于后自增(减)运算符的优先级

国内绝大多数的C语言教材都说“在C语言中,后自增(减)运算符的优先级与前自增(减)运算符相同”。其实,这种说法是有问题的。

在传统C语言(即C89标准之前的C语言)规范中,后自增(减)的优先级的确是与前自增(减)相同的,都是2级。但是,从C89标准开始,已经将后自增(减)的优先级调整为1级,而前自增(减)的优先级依然为2级,从而使得后自增(减)的优先级高于前自增(减)[1] [2]。遗憾的是,这种调整并未在国内的绝大多数C语言教材中反映出来。

5. 关于scanf函数中的第二个参数

为什么scanf函数中的第二个参数只能是变量的地址,而不能是变量名本身呢?大多数教材中并未给出解释,而有的教材则认为是为了提高编程的灵活性,使得scanf函数中的第二个参数既可以是若干个变量的地址,也可以是指向某些内存单元的指针。其实,真正的原因在于C语言中函数参数的单向传递规则,即只能将实参的值传递给对应的形参,而不能将形参的值传递给对应的实参[3]。

在程序中调用scanf函数完成数据的输入,是通过执行该函数的函数体语句实现的。不过在执行该函数的函数体时所输入的数据,首先存放于函数体中定义的局部变量中。调用scanf函数时,若直接以待存储数据的变量名作为实参,则函数体中局部变量(包括形参)的值并不能直接传递给实参;若改用待存储数据的变量的地址作为实参,就可以通过跨函数间接引用的方式,将函数体中局部变量的值传递给主调函数中的变量了。

6. 关于malloc函数的返回值类型

在大多数教材中,在调用malloc函数时,总是要对其返回值进行强制类型转换。例如,

int *p;

p=(int *)malloc(sizeof(int));

这些教材中认为这种强制类型转换是必不可少的,其实并非如此。在传统C语言(即C89标准之前的C语言)规范中,malloc函数的返回值为char *类型,由于这种类型与其他的指针类型都不是赋值兼容的,因此不能直接进行赋值运算,而必须先进行强制类型转换,再进行赋值运算[2]。

不过,从C89标准开始,已经将malloc函数的返回值类型改为void *类型。void *是C89标准中定义的通用指针类型,通用指针与所有其他类型的指针都是赋值兼容的,即可以不经过强制类型转换而直接相互赋值[2]。例如,

int *p;

p=malloc(sizeof(int));

此外,calloc函数和realloc函数的用法与malloc函数是类似的。

7. 关于文本打开方式与二进制打开方式

C语言中的各类文件打开方式均包括两种,如读方式包括“r”和“rb”,写方式包括“w”和“wb”。在大多数C语言教材中,将文件的这两种打开方式称为“打开文本文件”与“打开二进制文件”。

这种叫法很容易使人误解为用第一种打开方式创建的就是文本文件,用第二种打开方式创建的就是二进制文件。其实一个新创建的文件是文本文件还是二进制文件的决定因素,是向文件中写入数据的函数,而不是文件的打开方式[3]。一般而言,使用fprintf、fputc和fputs等函数创建的文件,是文本文件;而使用fwrite函数创建的文件,则是二进制文件。相应地,fscanf、fgetc和fgets等函数用于读取文本文件;而fread函数则用于读取二进制文件。

既然如此,为什么还要将文件的打开方式区分为这两种方式呢?其实,这源于两类操作系统对于回车换行的不同处理方式。在第一类操作系统(如UNIX和Linux)的文本编辑软件中,采用与C语言相同的处理方式,只需用一个换行符,即可实现回车换行。而在第二类操作系统(如DOS和Windows)的文本编辑软件中,则采用与C语言不同的处理方式,需要用一个回车符和一个换行符的组合,方可实现回车换行。

因此,在第二类操作系统中,当用第一种方式打开文件并对文件进行写入操作时,将会把每一个换行符替换为一个回车符和一个换行符的组合;当用第一种方式打开文件并对文件进行读出操作时,将会进行相反的替换。然而,当用第二种方式打开文件并对文件进行写入和读出操作时,将不会对字符进行任何替换。

而在第一类操作系统中,第一种打开方式与第二种打开方式是没有区别的。不论用哪种方式打开文件,在对文件进行写入和读出操作时,都不会对字符进行任何替换。

可见,这两种打开方式均是既可以打开文本文件,也可以打开二进制文件,区别在于对回车换行的处理方式不同。因此,正确叫法应该是“文本打开方式”与“二进制打开方式”[3]。

参考文献 :

[1]Samuel P. Harbison Ⅲ.C语言参考手册(第5版).北京:机械工业出版社,2003.

[2]K.N.King.C语言程序设计现代方法(第2版).北京:人民邮电出版社,2010.

[3]巨同升.C语言程序设计新思路[M].北京:科学出版社,2020.

国内C语言教材中几种值得商榷的说法相关推荐

  1. 语言abline画不出线_教材中定性分析的R语言实例

    我们的年级由于疫情,统计这一章被甩在了高二,和前一个版本的教材<必修三>相比,也发生了一些变化. 对于统计图表的呈现,由于个人学艺不精,Geogebra有统计功能,但自己的使用存在着局限性 ...

  2. python语言包含的错误,Python语言程序中包含的错误,一般分为三种,以下____________不是其中的一种...

    Python语言程序中包含的错误,一般分为三种,以下____________不是其中的一种 答:编译错误 人体体温能自动调控在37度,其原因是( ). 答:人体内产生的热能是分批放出的 人体内有完善的 ...

  3. c语言共有几种运算符_【填空题】C语言一共有 ()个关键字,()中控制语句,()种运算符...

    [填空题]C语言一共有 ()个关键字,()中控制语句,()种运算符 更多相关问题 [填空题] 对煤进行工业分析的目的,是为了判断煤的(). [填空题] 钛的比重是不锈钢的一半,抗腐蚀性是不锈钢的(). ...

  4. 请描述定时器初值的计算方式_单片机C语言编程中定时器初值计算的两种方法...

    单片机C语言编程中,定时器的初值对于初学者真的是比较不好计算,因此我总结了以下几种方法. 第1种方法: #define FOSC 11059200L //晶振的频率 #define TIMS (655 ...

  5. C语言中几种输入方式

    当我们输入一串字符或者数字时,需要一种标志作为输入结束的标志,所以我总结了以下几种: 1.输入一串字符串以回车键作为输入结束的标志 char ch; while(((ch=getchar())!='n ...

  6. keil c语言 延迟程序,Keil C51程序设计中几种精确延时方法

    前几天时间在做一个基于51单片机开发板的等精度频率计,用LCD1602液晶显示的,晶振是22.1184MHZ,用得是测频率法,目的是想做到能够测试0--900KHZ的信号. 液晶显示部分花了我好几天才 ...

  7. 在c语言程序设计中函数有两种类型 和,在C语言程序设计中函数有两种类型:__________和__________...

    在C语言程序设计中函数有两种类型:__________和__________ 以下程序的输出结果是()intA:6B:3C:2D:1 红楼梦中提到的名菜有A:酒酿清蒸鸭子B:奶油松瓤卷酥C:四喜丸子D ...

  8. C语言中三种大括号格式的规范

    C语言中三种大括号格式的使用规范 简介: 在C中,使用大括号的方法无所谓对还是错--只要每个开括号后都有一个闭括号,你的程序中就不再会出现与大括号有关的问题.然而,有三种著名的大括号格式:Kernig ...

  9. C语言中几种报错类型的解决方案

    C语言中几种报错类型的解决方案 声明:本人小白,第一次写博客,由于查报错原因比较困难,为了方便记下自己敲代码遇到的问题而随笔写下,文中有诸多错误,希望路过的大佬能够对我的文章批评指正.我也会不断修改完 ...

  10. c语言和python语言分别是一种什么语言_作为入门语言,C语言和Python哪一种更值得选择?...

    初学编程,应该学习哪一门编程语言,有不少人感到困惑,那么我们到底该如何选择呢? C语言和Python作为多种语言中两种语言,只是语法不同而已.以其作为入门语言的话,那还是各有千秋,各有各的好处的. 有 ...

最新文章

  1. leetcode-92 反转链表II
  2. 易点租加速电脑租赁市场布局
  3. 蚂蚁金服“刷脸”支付技术解读:错误率低于百万分之一
  4. html鼠标悬停出现新元素,CSS:我如何将鼠标悬停在一个元素上,并显示另一个元素?...
  5. MySQL: Connection Refused,调整 mysql.ini中的 max_connections
  6. Qt for Python使用Qt中的Properties
  7. 前端学习(983):jquery概念
  8. 浏览器对象模型(BOM)
  9. cad lisp 两侧偏移并删除_CAD做钣金件展开的原理你知道吗?
  10. Oracle oradebug 命令 使用说明
  11. Java开发逻辑思维题
  12. 指标权重确定方法之熵权法
  13. 使用Java将中文转化为拼音
  14. python的十句名言_程序员的二十句励志名言,看看你最喜欢哪句?
  15. 宝付国际跨境知识小课堂 | 人民币外汇市场是个啥?
  16. 计算机和通讯技术对我们生活的改变,信息技术的发展,带来了哪些方面的改变?...
  17. 日语学习-多邻国-问候
  18. 有的人活着他已经死了,有的人死了他还活着
  19. 【深度学习】目标检测之YOLOv3算法
  20. python 矢量化计算

热门文章

  1. python刷课系统教师_让教师只想刷课的继续教育不能继续了
  2. qgis自定义符号库
  3. 胖子哥的大数据之路(二)- 大数据结构化数据存储应用模式
  4. JAVA毕业设计高校实习实训管理系统计算机源码+lw文档+系统+调试部署+数据库
  5. 一键查看MTALAB支持的字体
  6. Via OpenCv Snake算法
  7. 集成电路制造及工艺 主要名词解释
  8. 有什么计算机应用基础的app,计算机应用基础软件
  9. 个人电脑完整重装WINDOWN XP 详解--博主推荐
  10. 考计算机一级用什么软件学,大学计算机一级考试用的是什么word软件