K&R exercise 4-9、4-10
4-9
Our getch and ungetch do not handle a pushed-back EOF correctly. Decide what their properties ought to be if an EOF is pushed back, then implement your design.
思考:
int类型-1在内存中的表示(16位的系统int占两个字节,而32位机器中它占4个字节,所以int型至少为16位):
(1字节(Byte) = 8个二进制位 = 8bits)
原码:1000 0000, 0000 0001
取反:1111 1111,1111 1110
加一:1111 1111,1111 1111
转化为十六进制为FFFF
char占一个字节,所以由int转化为char时高位丢失
字符(二进制表示):1111 1111
转化为十六进制为FF
当char再次转化为int时,有的机器可能将其转化为FF,而有的会转化为FFFF
为了避免“宽类型”(int)转化为“窄类型”(char)时可能导致数据信息丢失这种情况的发生,可以将缓存区buf数组由原来的char类型转化为int类型
也就是将
char buf[bufsize];
转化为
int buf[bufsize];
其余内容不变。
4-10
An alternate organization uses getline to read an entire input line; this makes getch and ungetch unnecessary. Revise the calculator to use this approach.
思考1:
对所读取数组line的索引Li的初始化
int Li = 0;//input line index
int getop(char s[])
{
int c, i;
if (line[Li] == '\0')//the end of input line
{
if (GetLine(line, MaxLine) == 0)//input line length is 0
return EOF;
else
Li = 0;
}
当getop函数到达输入行line的末尾时,需要调用GetLine函数再读取一行。若读取的行长度不为0,就需要重新对索引Li进行初始化操作。
为什么要重新初始化呢,不多余吗?
解释:
这次对line数组的索引Li的初始化并不多余,虽然在第一次读取输入时本来Li就等于0。但当第二次读取输入时,索引位置还停留在上一次读取结束的位置
,所以应该将其位置更新到line数组起始位置。
思考2:
当程序要确定读取数字的完整性,需要多读一个字符。此时只需要对Li减一即可达到后退一个字符的效果。那么此时需不需要判断字符c是否等于EOF呢(也就是说要不要判断到达文本结尾处)。
解释:
此处不需要判断是否到达文档结尾处(EOF),因为读取的line数组是从GetLine函数传递过来的。若长度为0,在前面的程序段就会将其定义为EOF,并返回。当其长度不为0时,才会对字符串进行读写操作
完整程序:
#define MaxLine 100
int GetLine(char[], int);
char line[MaxLine];//one input line
int Li = 0;//input line index
int getop(char s[])
{
int c, i;
if (line[Li] == '\0')//the end of input line
{
if (GetLine(line, MaxLine) == 0)//input line length is 0
return EOF;
else
Li = 0;
}
while ((s[0] = c = line[Li++]) == ' ' || c == '\t')//assign to c variable the value
; //present at line character array
s[1] = '\0';
i = 0;
if (!isdigit(c) && c != '.' && c != '-' && !islower(c))//遵循从左到右的顺序进行判断
return c;
if (c == '-')
{
if (isdigit(c = line[Li++]) || c == '.')
s[++i] = c;
else
{
Li--;
return '-';//返回输入的结尾
}
}
if (islower(c))//如果c为小写字母
{
while (islower(s[++i] = c = line[Li++]))
;
s[i] = '\0';
if (c != EOF)//不管所读取的是单个小写字母,还是一个小写字母组成的字符串
//为了确定所读取内容的准确性,都需要多读取一个字符,然后将其“压回”栈中
Li--;
if (strlen(s) > 1)
return Name;
else
return s[--i];//return c;是不正确的,因为此时c是程序为了确定字符串完整性所多读取的字符
//而在其之前的那个字符才是执行相应操作的字符标志
}
if (isdigit(c))//收集整数部分
while (isdigit(s[++i] = c = line[Li++]));
if (c == '.')//收集小数部分
while (isdigit(s[++i] = c = line[Li++]));
s[i] = '\0';
Li--;
return number;
}
//GetLine:take input in the character array
int GetLine(char s[], int limit)
{
int i = 0;
char c;
while (i < limit - 1 && (c = getchar()) != '\n' && c != EOF)
s[i++] = c;
if (c == '\n')
s[i++] = c;
s[i] = '\0';
return i;
}