博文
[069] 函数实参表列的求值顺序(2006-11-19 16:21:00)
摘要:《C程序设计第二版》(谭浩强)
如果实参表列包括多个实参,对实参求值的顺序并不是确定的,有的系统按自左至右顺序求实参的值,有的系统则按自右至左顺序。许多C版本(例如Turbo C和MS C)是按自右而左的顺序求值。例:
int f(int a, int b);
void main()
{
int i = 2;
int p;
p = f(i, ++i)
}
如果按自左至右顺序求实参的值,则函数调用相当于f(2, 3)。若按自右至左顺序求实参值,则它相当于f(3, 3)。可以在不同的环境中试一试, 就可知所用系统的处理方法。由于存在上述情况,使程序通用性受到影响。因此应避免这种容易引起不同理解的情况。
如果本意是按自右而左顺序求实参的值,可以改写为
j = i;
k = ++i;
p = f(j, k);
如果本意是按自左而右顺序求实参的值,可以改写为
j = ++i;
p = f(j, j);
这种情况在printf函数中也同样存在,如
printf("%d, %d", i, i++);
也发生上述同样的问题,使用时应注意,避免使用这种容易混淆的用法。
......
[068] 函数的返回值(2006-11-19 16:02:00)
摘要:《C程序设计第二版》(谭浩强)
<1> 函数的返回值是通过函数中的return语句获得的。return z 与 return(z)等价。
<2> 定义函数时应指明函数值的类型。C语言规定,凡不加类型说明的函数,一律自动按整形处理。
<3> 如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准。对数值型数据,可以自动进行转换。即函数值决定返回值的类型。
<4> 如果被调用函数中没有return语句,并不带回一个确定的、用户所希望得到的函数值,但实际上,函数并不是不带回值,只是不带回有用的值,带回的是一个不确定的值。即如果将一个没有返回值的函数赋值绐一个变量是合法的,只是没有什么实际意义而已。(P149)
<5> 为了明确表示“不带回值”,可以用“void”定义“无类型”(或“空类型”)。这样系统就能保证不使函数带回任何值,即禁止在调用函数中使用被调用函数的返回值。此时如果将函数赋值绐一个变量就是错误的。
......
[067] 关于形参与实参的说明(2006-11-19 15:41:00)
摘要:《C程序设计第二版》(谭浩强)
<1> 在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元.只有在发生函数调用时,函数中形参才被分配内存单元.在调用结束后,形参所占的内存单元也被释放。
<2> 实参可以是常量、变量或表达式,如:max(3, a+b); 但要求它们有确定的值。在调用时将实参的值赋绐形参(如果形参是数组名,则传递的是数组首地址而不是数组的值。)
<3> 在被定义的函数中,必须指定形参的类型。
<4> 实参与形参的类型应相同或赋值兼容。类型不相同时,按赋值运算时的类型转换规则进行转换([064] 不同类型数据转换规则)。
<5> C语言规定,实参变量对形参变量的数据传递是“值传递”,即单向传递,只由实参传绐形参,而不能由形参传回来绐实参,这是和fortran不同的。在内存中,实参单元与形参单元是不同的单元。
调用函数时,绐形参分配内存单元,并将实参对应的值传递绐形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。因此在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调用函数的实参的值。
......
[066] 筛选法求素数(2006-11-18 22:39:00)
摘要:《C程序设计第二版》(谭浩强)
关于素数的判定,参见: [031] 判断m是否是素数。
所谓“筛选法”指的是“埃拉托色尼(Eratosthenes)筛法”。他是古希腊的著名数学家。他采取的方法是,在一张纸上写上1到100全部整数,然后逐个判断它们是否是素数,找出一个非素数,就把它挖掉,最后剩下的就是素数。
具体做法如下:
<1> 先将1挖掉(因为1不是素数)。
<2> 用2去除它后面的各个数,把能被2整除的数挖掉,即把2的倍数挖掉。
<3> 用3去除它后面的各数,把3的倍数挖掉。
<4> 分别用4、5…各数作为除数去除这些数以后的各数。这个过程一直进行到在除数后面的数已全被挖掉为止。例如找1~50的素数,要一直进行到除数为47为止(事实上,可以简化,如果需要找1~n范围内素数表,只需进行到除数为n^2(根号n),取其整数即可。例如对1~50,只需进行到将50^2作为除数即可。)
如上算法可表示为:
<1> 挖去1;
<2> 用刚才被挖去的数的下一个数p去除p后面各数,把p的倍数挖掉;
<3> 检查p是否小于n^2的整数部分(如果n=1000, 则检查p<31?),如果是,则返回(2)继续执行,否则就结束;
<4> 纸上剩下的数就是素数。
#include <stdio.h>
#include <math.h>
int main(void)
{
int i;
int j;
int a[101]; // 为直观表示,各元素与下标对应,0号元素不用
for (i = 1; i <= 100; i++) // 数组各元素赋值
......
[065] 赋值运算中的类型转换(2006-11-11 21:28:00)
摘要: 如果赋值运算符两侧的类型不一致,但都是数值型或字符型时,在赋值时要进行类型转换。
<1> 将实型数据(包括单、双精度)赋值绐整型变量时,舍弃实数的小数部分。如i为整型变量,执行“i=3.56”的结果是使i的值为3,在内存中以整数型式存储。
<2> 将整型数据赋绐单、双精度变量时,数值不变,但以浮点数形式存储到变量中,如将23赋值绐float变量f,即f=23,先将23转换成23.00000,再存储在f中。如将23赋绐double型变量d,即d=23,则将23补足有效位数字为23.00000000000000,然后以双精度浮点形式存储到d中。
<3> 将一个float型数据赋绐double变量时,数值不变,有效位数扩展到16位,在内存中以64位(bit)存储。将一个double型数据赋绐float变量时,截取其前面7位有效数字,存放到float变量的存储单元(32位)中。但应注意数值范围不能溢出。如:
float f;
double d = 123.456789e100;
f = d;
就出现溢出的错误。
★ 为了验证是否真的会溢出,写如下程序试验:
#include <stdio.h>
#include <string.h>
int main()
{
float f;
double d = 123.456789e100;
f = d;
printf("%f\n", f);
return 0;
}
在TC(Win-TC)中运行会溢出,程序会自动退出,无任何显示( TC中欲使结果窗口停留,需在最后加一句getch(); )。而在VC中运行可以得到如下结果:
=================================================================================
1234567890000000100000000000000......
[064] 不同类型数据转换规则(2006-11-10 22:55:00)
摘要:高↑ double ← float
ㄧ ↑
ㄧ long
ㄧ ↑
ㄧ unsigned
ㄧ ↑
低ㄧ int ← char,short
向左箭头表示必定的转换,如字符数据必定先转换为整数,short型转换为int型,float型数据在运算时一律选转换成双精度型,以提高运算精度(即使是两个float型数据相加,也先都化成double型,然后再相加)。
纵向箭头表示当运算对象为不同类型时转换的方向。如int型与double型数据进行运算,先将int型的数据转换成double型,然后在两个同类型(double型)数据间进行运算,结果为double型。注意箭头方向只表示数据类型级别的高低,由低向高转换。比如一个int型数与一个double型数据运算,是直接将int型转成double型,而不是经过中间的unsigned和long后再转为double。
《C程序设计(第二版)》
......
<015> AVR Studio中常用快捷键(2006-11-10 11:43:00)
摘要:┌───────┬─────────────┬─────────┐
ㄧ 名称 ㄧ 功能 ㄧ 快捷键 ㄧ
├───────┼─────────────┼─────────┤
ㄧ Run ㄧ 在Simulator上运行目标程序ㄧ F5 ㄧ
├───────┼─────────────┼─────────┤
ㄧ Stop ㄧ 终止Debug调试 ㄧ Ctrl + Alt + F5 ㄧ
├───────┼─────────────┼─────────┤
ㄧ Reset ㄧ 复位目标程序 ㄧ Shift + F5 ㄧ
├───────┼─────────────┼─────────┤
ㄧ Break &nb......
<014> AVR-GCC中常用Make操作的功能(2006-11-09 22:42:00)
摘要:┌───────┬─────────────────────────┐
ㄧ 操作 ㄧ 功能 ㄧ
├───────┼─────────────────────────┤
ㄧ make all ㄧ 编译源文件,生成输出文件 ㄧ
├───────┼─────────────────────────┤
ㄧ make clean ㄧ 清除所有编译生成的文件 ㄧ
ㄧ ㄧ (在编译之前,应该先清除上一次编译生成的旧文件) ㄧ
├───────┼────────────......
<013> PN中常用快捷键&PN中添加Make工具各参数含义(2006-11-09 22:17:00)
摘要:┌────────────┬─────────────┐
ㄧ 快捷键 ㄧ 对应功能 ㄧ
├────────────┼─────────────┤
ㄧ Ctrl F2 ㄧ 设置普通书签 ㄧ
├────────────┼─────────────┤
ㄧ Ctrl K, x(x=0,1,2,…,9)ㄧ 设置数字书签 ㄧ
├────────────┼─────────────┤
ㄧ F2 ㄧ 在各个书签位置跳转 ㄧ
├────────────┼─────────────┤
ㄧ Ctrl Q, x ㄧ 跳转到指定数字书签位置 ㄧ
├────────────┼─────────────┤
ㄧ C......
[063] C语言整型变量所占内存字节数(2006-11-08 22:19:00)
摘要: C标准没有具体规定各类整型数据所占内存字节数,只要求long型数据长度不短于int型,short型不长于int型。具体如何实现,由各计算机系统自行决定。如在微机上,int型和short都是16位,而long是32位。在VAX 750上,short是16位,而int和long都是32位,一般以一个机器字(word)存放一个int数据。前一阶段,微机的字长一般为16位,故以16位存放一个整数,但整数的范围太小,往往不够用,故将long型定为32位。而VAX的字长为32位,以32位存放一个整数,范围可达正负21亿,已足够用了,不必再将long型定为64位。所以将int和long都定为32位。通常的做法是:把long定为32位,把short定为16位,而int可以是16位,也可以是32位。这主要取决于机器字长。在微机上用long型可以得到大范围的整数,但同时会降低运算速度,因此除非不得已,不要随便使用long型。
ANSI标准定义的整数类型
┌───────────┬────┬─────────────────────┐
ㄧ 类型 ㄧ 比特数 ㄧ 数值范围 ㄧ
├───────────┼────┼─────────────────────┤
ㄧ [signed] int ㄧ 16 ㄧ -32768~32767 &......