从字符串中删除重复的单词时出现字符串标记化问题

你的

我在下面的代码中尝试做的是将字符串标记化并将每个标记存储在动态分配的结构中,但排除任何重复项。

在输入包含两个相等单词的字符串之前,这种代码类型有效。例如,字符串“ this this”也将存储第二个单词,即使它是相同的。但是,如果我输入“ this this is”,它将删除第二个“ this”,并完全忽略字符串的最后一个单词,因此,如果字符串中有重复项,则不会被删除。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define dim 70


typedef struct string {
  char* token[25];
} string;

int main() {

  string* New = malloc(dim*sizeof(string));

  char* s;
  char* buffer = NULL;
  int i = 0, r = 0;

  s = malloc(dim * sizeof(char));

  fgets(s, dim, stdin);

  printf("The string is: %s\n", s); 

  New->token[i] = malloc(dim*sizeof(char));
  New->token[i] = strtok(s, " ");
  ++i;

  while((buffer = strtok(NULL, " ")) && buffer != NULL){

    printf("\nbuffer is: %s", buffer);

    for(r = 0; r < i; ++r) {

      if(strcmp(New->token[r], buffer) != 0 && r == i-1) {

        New->token[i] = malloc(strlen(buffer)*sizeof(char)+1);
        New->token[i] = buffer;
        ++i;

      }
      else if(New->token[r] == buffer) {
            break;
      }

    }



  }

printf("\n New string: ");
for(i = 0; New->token[i] != NULL; ++i) {
   printf(" %s", New->token[i]);
}


return 0;
}

在我看来,这应该可以正常工作,但是我很难在这里找到我做错了什么。如果您需要其他信息,请问我,对于最终缺乏清晰度(以及我的英语),我深表歉意。

雷克

完全重写此答案,以解决一些我第一次没有看到的根本错误的事情。请参阅底部代码中的嵌入式注释,以解释一些构造更改:

我完全按原样运行您的代码,并看到了您所描述的内容,除了strcmp在另一个答案中使用的注意事项之外,还发现了几行可以调整或删除的代码行,可以按您所描述的去做:

首先,结构定义创建一个指向char数组的指针。根据您稍后在代码中所做的事情,您需要的是一个简单的char数组

typedef struct string {
  //char* token[25]; //this create a pointer to array of 25 char
  char token[25]; //this is all you need
} string;

如您将在后面看到的那样,这将大大简化内存分配。

一些基本问题:

\n在分析定界符中包括换行符。<enter>在输入字符串的结尾处命中时,将添加换行符,从而导致的第一个实例this和的第二个实例this\n不相等。

while((buffer = strtok(NULL, " \n")) && buffer != NULL){
                               ^^

这行正在创建未初始化的内存。

string* New = malloc(dim*sizeof(string)); 

关于使用malloc()calloc()的注意事项malloc()会留下未创建的内存,而calloc()会创建全部初始化为的内存块0

使用创建的内存 malloc()

在此处输入图片说明

使用创建的内存calloc()

在此处输入图片说明

这在您的代码中的多个地方变得很重要,但是特别是我在上一节中看到了一个问题:

for(i = 0; New->token[i] != NULL; ++i) {
   printf(" %s", New->token[i]);
}

如果为之创建的内存New未初始化,则当索引i增加到显式写入的内存区域之外并循环尝试test时,会出现运行时错误New->token[i]如果New->token[i]包含0,则它将尝试打印该内存区域。

您还应该通过对free()的相应调用来释放代码中创建的每个内存实例

所有这些以及更多内容都可以在下面的代码重写中得到解决:(针对此字符串进行测试,结果为string。)

typedef struct string {
  //char* token[25]; //this create a pointer to array of 25 char
  char token[25]; //this is all you need
} string;

int main() {
    char* s;
    char* buffer = NULL;
    int i = 0, r = 0;

    string* New = calloc(dim, sizeof(string));//Note: This creates an array of New.
                                              //Example: New[i]
                                              //Not: New->token[i]
    s = calloc(dim , sizeof(char));
    fgets(s, dim, stdin);
    printf("The string is: %s\n", s); 
    buffer = strtok(s, " \n");
    strcpy(New[i].token, buffer); //use strcpy instead of = for strings
    //restuctured the parsing loop to a more conventional construct
    // when using strtok:
    if(buffer)
    {
        ++i;
        while(buffer){
            printf("\nbuffer is: %s", buffer);
            for(r = 0; r < i; ++r) {
                if(strcmp(New[r].token, buffer) != 0 && r == i-1) {
                    strcpy(New[i].token, buffer);
                    ++i;
                }
                else if(strcmp(New[r].token, buffer)==0) {
                    break;
                }
            }
            buffer = strtok(NULL, " \n");
        }
    }
    printf("\n New string: ");
    for(i = 0; i<dim; i++) {
        if(New[i].token) printf(" %s", New[i].token);
    }
    free(New);
    free(s);
    return 0;
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章