辛昕这个程序着实不短,这次我采用直接在原程序中加注的办法来挑刺,不然的话,实在不好对照
/*practise 8.4*/
/*题目:
定义一个函数,其参数是一个字符串,返回该字符串中的单词数。
单词以空格或标点符号来分隔,假设字符串不含单双引号,也就是说不存在像isn't这样的词。
定义第二个函数,它的第一个参数是一个字符串,第二个参数是一个数组,该函数将第一个字符串变元分割成单词,把这些单词存储在第二个数组变元中,最后返回这些单词。
第三个函数,其参数是一个字符串,返回该字符串中的字母数。
使用这些函数实现一个程序,从键盘读入含有文本的字符串,输出文本中的所有单词,输出顺序按照单词字母数由短到长。
*/
/*
关于 isalpha()
*/
#include
#include
#include
#include
#define increment 10
#define WORDLEN 10
int account(char *pstring); //统计词数
void get_words(char pstring[],char* pwords[]); //拆分成词项,存入pwords[]
int Get_length(char str[]);
char** arrangement(char* pwords[],int);
int main(void)
{
int capacity = 20;
int count = 0;
char *pstring = NULL;
char *temp = NULL;
int words = 0;
char **pwords = NULL;
char **buffer = NULL;
int position = 0;
int number = 0;
pstring = (char *)malloc(capacity * sizeof(char));
printf(\"Enter a string:\n\");
do
{
if(count == capacity)
{
capacity += increment;
temp = (char *)malloc(capacity * sizeof(char));
if(!temp)
{
printf(\"Allocation failed.\n\");
return -1;
}
if(!pstring)
{
for(int i = 0;i < count;i++)
*(temp + i) = *(pstring + i);
pstring = temp;
free(temp);
}
}
}while((*(pstring + count++) = getchar()) != '\n');
/*结束字符串*/
*(pstring + count) = 0;
/*统计词数*/
words = account(pstring);
/*根据词数分配数组容纳词数*/
pwords = (char **)malloc(words * sizeof(char *));
/*为每个词分配空间*/
for(int n = 0; n < words;n++)
pwords[n] = (char*)malloc(WORDLEN*sizeof(char));//当年的恶习,这个小写,我半天没看出原来是个宏
//看来这个正确版本和那个错误版本都是我写的,不是参考答案
get_words(pstring,pwords);
pwords = arrangement(pwords,words);//圈注,这个地方也有点危险,象pwords这种由malloc赋值的指针,在free之前赋值都是隐患,尽管在这个地方是自己赋值给了自己
//圈注,稳妥的写法还是 arrangement(pwords,words);
/*这一部分属于一开始写程序时,一个阶段一个阶段检查已有结果时所用*/
/*结果最后忘了关闭测试。另外是,number先赋值为1,而在其后输出的时候*/
/*又用的先使用再加1,这种做法不好,所以我选择初始化为0,然后先加加再使用*/
for(number = 0;number < words;number++)
printf(\"%s\n\",pwords[number]);
// number = 1;
/*从题目出发,这一部分是没用的*/
/*但我忘记了打问号那一句的作用和意义*/
buffer = (char **)malloc(words * sizeof(char *));
buffer[0] = pwords[0];//?????
for(int k = 1;k < words;k++)
{
for(int j= 0;j <= position;j++)
{
if(!strcmp(buffer[j],pwords[k]))
break;
if(j == position && strcmp(buffer[j],pwords[k]))
buffer[++position] = pwords[k];
}
}
/*看到这一部分,才会想起这是用来剔除重复的单词,所以上面的那个输出是用来测试是否读取正确的*/
/*但上述代码并未实现该功能*/
for(int l = 0;l < position;l++)
printf(\"%s\n\",buffer[l]);
free(pwords);
pwords = NULL;
free(buffer);
buffer = NULL;
return 0;
}
int account(char *pstring)
{
int count = 0;
char flag = 0;
int i = 0;
/*
for(unsigned int i = 0; i < strlen(pstring);i++) //过去我真的是干了太多这种事
//圈注:象上边写的 i < strlen(pstring) ;从语法来看尽管没错,但是每判一次循环条件,就要调用一次 strlen(pstring)函数,
//大大增加了运行时的负担(尤其是对实时,嵌入式系统而言
// 正确的方法是,将strlen(pstring)先赋值给某个临时变量,或者改为,for(i=strlen(pstring)-1;i>=0;)
//过去,我一直以为是99和ansi的区别,但刚刚看的C和指针,
//即应该把定义放在所有语句之前。
//我怀疑我是不是弄错了?
{
if(!isalpha(*(pstring + i)) && isalpha(*(pstring + i + 1)) )
count++;
}
if(isalpha(*(pstring)) )//????
count++;
*/
/*这种计数方法,使得这个程序弱不禁风*/
/*这样的输入就能让它报废:a big big, (space)de */
/*合理的方法应该是按顺序遍历整个字符串,逢字母开始坐标志,隔了一个以上的非字母,再碰到字母,计数*/
/*
充分考虑几种可能的输入情况:
\" I am a big big girl\"
\"I am a big big girl, in the big big world\"
\"I am a big big girl.\"
*/
while(*(pstring + i) != '\0')
{
if(isalpha(*(pstring + i++)))
{
if(!flag)
flag = 1;
}
else
{
if(flag)
{
count++;
flag = 0;
}
}
}
//圈注,上边这段话明显有问题,具体分析我就不写了,下边改为正确的写法,对比一下.
while(*(pstring + i) != '\0')
{
if(isalpha(*(pstring + i++)))
{
if(!flag)
{
flag = 1;
count++;
}
}
else
flag = 0;
}
//圈注,上边的flag=的1和0最好定义成一个有名字意义的宏,这样不容易搞错.
/*下面这一段居然是画蛇添足?!!*/
//if(isalpha(*(pstring+i)) && !flag)
// count++;
return count;
}
void get_words(char pstring[],char* pwords[])
{
int count = 0;
int i = -1; //这里是为了配合后边的“先加再用”,让i从零开始,但是,赋值为-1是否有什么危险呢?
int j = 0;
/*
while(pstring != '\0')
{
if(!isalpha(pstring))
{
i++;
continue;
}
j = 0;
while(isalpha(pstring))
pwords[count][j++] = pstring[i++];
pwords[count++][j] = '\0';
}
*/
/*原来的写法很蠢,其实可以while,不用if*/
/*改完了,花了半个小时修正,发现其实没进步多少,还是要两个循环变量*/
while(pstring[++i] != '\0')
{
if(isalpha(pstring))
pwords[count][j++] = pstring;
else if(j/*strlen(pwords[count])*/)
{
pwords[count++][j] = '\0';
j = 0;
}
//printf(\"length of %d is %d\n\",count,strlen(pwords[count]));
/*这里有个很奇怪的问题,为什么pwords[count]的长度总是17?????*/
}
}
int Get_length(char str[])
{
int length = 0;
while(str[length] != '\0')
length++;
return length;
}
char** arrangement(char* pwords[],int words)
{
char* temp = NULL;
temp = (char *)malloc(WORDLEN * sizeof(char));
//圈注,上边这个temp只是用来临时交换 pwords[j] 和 pwords的指针变量,,这里却给它分配了WORDLEN字符变量的空间,简直是莫名其妙
//char temp[WORDLEN];
for(int i = 0;i < words;i++)
{
for(int j = 0;j < words;j++)
{
if(Get_length(pwords) < Get_length(pwords[j]))
{
temp = pwords[j];//续前圈注,这里对temp赋值,把malloc分配给它的空间丢了,副作用是产生内存泄露,这也说明对temp分配空间毫无道理
pwords[j] = pwords;
pwords = temp;
}
}
//free(temp);// = NULL;
}
//free(temp);
return pwords;
}