练习1-13
编写一个程序,打印输入中单词长度的直方图(水平方向)。
方法1
int main()
{
int c,wlen,state,nw;
int word[10] = { 0 };
wlen = 1;
state = OUT;
nw = -1;//解决了Word[0]=0的问题
while ((c=getchar())!=EOF)
{
if (c == ' ' || c == '\n' || c == '\t')
{
state = OUT;
}
else if (state == OUT)
{
state = IN;
nw++;
word[nw]++;
}
else
{
word[nw]++;
}
}
for (nw = 0; nw < 10; nw++)
{
printf("%d ", word[nw]);
}
int i,j;
printf("\n");
for ( j = 0; j < 10; j++)
{
for (i = 1; i <= 7; i++)
{
printf(" ");
}
printf("|");
for ( i = 1; i <= word[j]; i++)
{
printf("_");
}
printf("\n");
printf("word %d |", j);
for ( i = 1; i <= word[j]; i++)
{
printf("_");
}
printf("|");
printf("\n");
}
return 0;
}
方法2
#include<stdio.h>
#define IN 1
#define OUT 0
#define MAXNUMBER 11
#define MAXHIST 15
int main()
{
int c,i,nc,state;
int overflow;
int maxvalue;
int nl[MAXNUMBER];
nc = 0;
state = OUT;
overflow = 0;
for (i=0;i< MAXNUMBER;i++)
{
nl[i] = 0 ;
}
while ((c=getchar())!=EOF)
{
if (c==' '||c=='\n'||c=='\t')
{
state = OUT;//在结束时,开始记录对应单词长度的个数
if (nc > 0)
{
if (nc <= MAXNUMBER)
{
nl[nc]++;
}
else
{
overflow++;
}
}
nc = 0;
}
else if (state==OUT)
{
state = IN;
nc++;
}
else
{
nc++;
}
}
maxvalue = 0;
int len = 0;
for (i=1;i< MAXNUMBER;i++)//find nl[i] maxvalue
{
if (nl[i] > maxvalue)
{
maxvalue = nl[i];
}
}
for (i = 1; i < MAXNUMBER; i++)
{
if (nl[i] > 0)
{
if ((len = nl[i] * MAXHIST / maxvalue) <= 0)//此处将程序编的更加简单
//len = nl[i] * MAXHIST / maxvalue这样的赋值操作是一个表达式
//因此可以作为更大表达式的一部分出现,所以说len并不是只在if分支语句中起作用的局部变量。
//这里进行完该操作语句后,持续进行while循环语句。
//同时,该语句可以看成len = nl[i] / maxvalue * MAXHIST,nl[i]表示长度为i单词的个数
//maxvalue表示最大频数,两者之比再乘以直方图最大高度,所以得到的便是相应高度。
//同时这样也起到了限制打印长度的作用
{
len = 1;
}
}
else
{
len = 0;
}
while (len > 0)
{
putchar('*');
len--;
}
putchar('\n');
}
if (overflow > 0)
{
printf("there are %d words >=%d\n",overflow,MAXNUMBER);
}
return 0;
}
注意:上面程序中的这部分程序段,此处是为了防止nl[i] * MAXHIST的结果溢出.也就是说int类型值的范围是-231 ~ 231-1即-2147483648~2147483647。当nl[i]>2147483647/MAXHIST=143165576时,就会出现溢出。此时len<0,表明长度为i的行出现的次数已经超出int类型的限制。
改进:可以直接定义一个符号常量限制一下nl[i]的最大值maxvalue。
if (nl[i] > 0)
{
if ((len = nl[i] * MAXHIST / maxvalue) <= 0)
{
len = 1;
}
}
C programming language 练习1-16
#define MAXLINE 1000
int getline(char s[], int lim);
void copy(char to[], char from[]);
int main()
{
int len=0;
int max=0;
char line[MAXLINE];
char longest[MAXLINE];
while ((len=getline(line, MAXLINE))>0)
{
printf("%d,%s", len,line);
if (len > max)
{
max = len;
copy(longest,line);
}
}
if (max > 0)
{
printf("%d\n", max);
printf("%s\n", longest);
}
return 0;
}
int getline(char s[], int lim)
{
int c,i,j;
j = 0;
for (i=0;(c=getchar())!=EOF && c != '\n';i++)
//由于题目当中说要可以打印任意长度的输入行长度,并尽可能打印其文本
//所以不用检查字符数是否超出数组s的限制,变量i记录输入行的长度,其值完全可以大于lim-1
//这里的变量j只是为了防止数组s发生数据溢出。也就是因为要为'\0','\n'这两个字符留下存储空间
//所以在下标为lim-2的元素处不能再填入输入内容,但依旧可以计入输入行的长度
//只不过多出来的输入内容不放在数组s中罢了
{
if (i<lim-2)
{
s[j] = c;//还能读入字符,表明行目前还在边界内
j++;
}
}
if (c == '\n')
{
s[j] = c;
j++;
i++;
}
s[j] = '\0';
return i;
}
void copy(char to[], char from[])
{
int i = 0;
while ((to[i]=from[i])!='\0')
{
i++;
}
}
练习1-18
#define MAXLINE 1000
int getline(char s[], int lim);
int remove(char s[]);
int main()
{
int len = 0;
char line[MAXLINE];
while ((len=getline(line,MAXLINE))>0)
{
if (remove(line) > 0)
{
printf("%d,%s", remove(line),line);
}
else
{
printf("%d\n", remove(line));
}
}
return 0;
}
int remove(char s[])
{
int i=0;//变量i代表字符长度,末尾的字符为'\0',所以不能计入在长度内
//所以变量i初始值为0,而不是1。getline函数同理。
while (s[i]!='\n')//首先找到换行符
{
i++;
}
i--;//从'\n'往回倒退一个位置
while (i >= 0 && (s[i] == ' ' || s[i] == '\t'))//循环读取,直到读取的数组元素不是空格或者是制表符
//同时字符串还要有元素可以读取
{
i--;
}//若一行都是空格或制表符,则返回的长度为-1
//while循环条件中的i >= 0若改为i>0,返回值为0。而正常情况最终系统也返回0
//为了区分这两种情况,所以这里是i >= 0
if (i >= 0)
{
i++;
s[i] = '\n';
i++;
s[i] = '\0';
}
return i;
}
int getline(char s[], int lim)
{
char c;
int i = 0;
int j = 0;
while ((c = getchar())!=EOF && c != '\n')
{
i++;
if (i<lim-2)
{
s[j] = c;
j++;
}
}
if (c == '\n')
{
s[j] = '\n';
j++;
i++;
}
s[j] = '\0';
return i;
}