3460|3

7815

帖子

57

TA的资源

裸片初长成(中级)

楼主
 

俺的C习题(6)——这是一个相对复杂一些的字符串处理函数 [复制链接]

其实昨晚就开始修改。
发现了很多当初没有留意的bug。还对一些子函数做了修改。
不过至今,对于最后一个去掉重复词项的代码块还没有完全理解。拖了两天,先贴上来,静待圈哥批判.....

还发现了一个奇怪的字符串长度的奇怪问题。
具体问题都写在 注释里。

  1. /*practise 8.4*/
    /*题目:
    定义一个函数,其参数是一个字符串,返回该字符串中的单词数。
    单词以空格或标点符号来分隔,假设字符串不含单双引号,也就是说不存在像isn't这样的词。
    定义第二个函数,它的第一个参数是一个字符串,第二个参数是一个数组,该函数将第一个字符串变元分割成单词,把这些单词存储在第二个数组变元中,最后返回这些单词。
    第三个函数,其参数是一个字符串,返回该字符串中的字母数。
    使用这些函数实现一个程序,从键盘读入含有文本的字符串,输出文本中的所有单词,输出顺序按照单词字母数由短到长。
    */
    /*
    关于 isalpha()
    */
    #include<stdio.h>
    #include<stdlib.h>
    #include<ctype.h>
    #include<string.h>

    #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);

    /*这一部分属于一开始写程序时,一个阶段一个阶段检查已有结果时所用*/
    /*结果最后忘了关闭测试。另外是,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++) //过去我真的是干了太多这种事情
    //过去,我一直以为是C99和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;
    }
    }

    }
    /*下面这一段居然是画蛇添足?!!*/
    //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[i] != '\0')
    {
    if(!isalpha(pstring[i]))
    {
    i++;
    continue;
    }
    j = 0;
    while(isalpha(pstring[i]))
    pwords[count][j++] = pstring[i++];
    pwords[count++][j] = '\0';
    }
    */

    /*原来的写法很蠢,其实可以while,不用if*/
    /*改完了,花了半个小时修正,发现其实没进步多少,还是要两个循环变量*/

    while(pstring[++i] != '\0')
    {

    if(isalpha(pstring[i]))
    pwords[count][j++] = pstring[i];
    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));
    //char temp[WORDLEN];

    for(int i = 0;i < words;i++)
    {
    for(int j = 0;j < words;j++)
    {
    if(Get_length(pwords[i]) < Get_length(pwords[j]))
    {
    temp = pwords[j];
    pwords[j] = pwords[i];
    pwords[i] = temp;
    }
    }
    //free(temp);// = NULL;
    }
    //free(temp);
    return pwords;
    }
复制代码

此帖出自编程基础论坛

最新回复

辛昕这个程序着实不短,这次我采用直接在原程序中加注的办法来挑刺,不然的话,实在不好对照/*practise 8.4*//*题目:定义一个函数,其参数是一个字符串,返回该字符串中的单词数。单词以空格或标点符号来分隔,假设字符串不含单双引号,也就是说不存在像isn't这样的词。定义第二个函数,它的第一个参数是一个字符串,第二个参数是一个数组,该函数将第一个字符串变元分割成单词,把这些单词存储在第二个数组变元中,最后返回这些单词。第三个函数,其参数是一个字符串,返回该字符串中的字母数。使用这些函数实现一个程序,从键盘读入含有文本的字符串,输出文本中的所有单词,输出顺序按照单词字母数由短到长。*//*关于 isalpha()*/#include#include#include#include#define increment 10#define WORDLEN 10int 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++;}}elseflag = 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;}  详情 回复 发表于 2012-1-10 14:48
点赞 关注
个人签名

强者为尊,弱者,死无葬身之地

 

回复
举报

3404

帖子

6

TA的资源

裸片初长成(初级)

沙发
 
顶,不过没仔细看
此帖出自编程基础论坛
 
 
 

回复

44

帖子

0

TA的资源

一粒金砂(高级)

板凳
 

辛昕这个程序着实不短,这次我采用直接在原程序中加注的办法来挑刺,不然的话,实在不好对照


/*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;
}

此帖出自编程基础论坛
 
个人签名能力越大,责任越大;知道越多,未知更多
 
 

回复

7815

帖子

57

TA的资源

裸片初长成(中级)

4
 

回复 板凳 能圈就圈 的帖子


刚刚加班完......明天再一个一个细看哈。
那个count++的地方明白了。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表