从指针数组C中删除重复的元素

时间:2016-11-21 20:01:09

标签: c arrays pointers

我正在尝试接收用户输入并在单独的行上打印出每个单词(没有重复)。到目前为止我所做的是能够接受用户输入并按字母顺序分别打印每一行。我现在需要做的是能够删除数组中的重复项#cam *争论[]

我的输入:

./a.out banana apple apple apple zoo cat fork

我的输出:

apple
apple
apple
banana
cat
fork
zoo

需要做的是打印一个苹果而不是三个。

以下是我到目前为止所做的工作,并且我已经评论了问题所在的代码部分

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

int main(int argc, char* argv[]) {
  int i, j, k, size;
  size = argc -1;
  char *key;
  char* a[argc-1];

  for (i = 2; i < argc; i++) {
    key = argv[i];

    j = i-1;
    while (j >= 1 && strcmp(argv[j], key) > 0) {
      argv[j+1] = argv[j];
      j--;
    }

    argv[j+1] = key;
  }

  //Problem                                                                                                                                                   
  //for(i = 2; i < size; i++){                                                                                                                                
  //    if(argv[i-1] != argv[i])                                                                                                                              
  //      a[i] = argv[i-1];                                                                                                                                   
  //}                                                                                                                                                         

  //for(i=0; i< size; i++)                                                                                                                                    
  //  puts(a[i]);                                                                                                                                             

  for(i=1; i< argc; i++)
    puts(argv[i]);

  return 0;
}

2 个答案:

答案 0 :(得分:1)

首先,您可以使用标题qsort中声明的标准C函数<stdlib.h>

如果要输出不包括重复项的参数,则无需删除参数。您只需输出唯一参数即可。

程序可以按以下方式查看

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

int cmp(const void *left, const void *right)
{
    return strcmp(*(const char **)left, *(const char **)right);
}

int main( int argc, char * argv[] )
{
    if (argc > 1)
    {
        qsort(argv + 1, argc - 1, sizeof(*argv), cmp);

        for (int i = 1; i < argc; )
        {
            puts(argv[i]);
            while (argv[++i] != NULL && 
                   strcmp(argv[i - 1], argv[i] ) == 0);
        }
    }

    return 0;
}

如果要提供这些命令行参数

banana apple apple apple zoo cat fork

然后程序输出将是以下

apple
banana
cat
fork
zoo

如果您确实要“删除”重复的参数,则argc应具有相对于修改的参数列表的正确值,argv[argc]应等于NULL

程序可以按以下方式查看

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

int cmp(const void *left, const void *right)
{
    return strcmp(*(const char **)left, *(const char **)right);
}

int main( int argc, char * argv[] )
{
    if (argc > 1)
    {
        qsort(argv + 1, argc - 1, sizeof(*argv), cmp);

        int n = 1;

        for (int i = 1; i < argc; i++)
        {
            int j = 1;
            while (j < n && strcmp(argv[j], argv[i]) != 0) j++;

            if (j == n)
            {
                if (n != i) argv[n] = argv[i];
                ++n;
            }
        }

        argc = n;
        argv[argc] = NULL;
    }

    for ( int i = 1; i < argc; i++ ) puts(argv[i]);

    return 0;
}

它的输出与上面显示的相同。

答案 1 :(得分:0)

在C中,字符串本身不是数据类型,而是语言引入的约定。牢记这一点很重要。

现在,如果你有两个char指针,那么即使它们指向的字符串是相同的,它们存储的地址也可能不一样。那么,比较

if (argv[i-1] != argv[i])

不会检查字符串是否相同,而只会比较地址。所以:

char * a = "Hello world!\n";
char * b = a;

if (a == b) {
    puts("Always true\n");
}

因为在这里,你实际上没有复制字符串,只需复制存储字符串的地址即可。这也产生了这种效果:

char a[20] = "Hello world!\n";
char * b = a;
a[0] = 'X';
puts(b); // Will print "Xello world!\n";

所以,你需要的是比较两个变量指向的字符串的方法。这是strcmp的用途。如果字符串相同,它将返回0,如果第一个字符串在第二个字符串之前或之后按字母顺序排列,则返回-1+1

所以使用测试

if (!strcmp(argv[i-1], argv[i]))

并且所有都应按预期工作。请注意,您的数组a不包含字符串的副本,而只是指向argv中的字符串。

/ edit:实际上,还有其他一些小错误,但一旦这个问题解决了,我想你也可以解决其余问题。

===推荐在评论中暗示===

在这样的代码中:

for (i = 2; i < size; i++) {
    if (argv[i-1] != argv[i])
        a[i] = argv[i-1];
}

你可以通过添加如下行来轻松搞错:

for (i = 2; i < size; i++) {
    if (argv[i-1] != argv[i])
        printf("argv[%i] and argv[%i] are identical\n", i-1, i);
        a[i] = argv[i-1];
}

因为在那里你可能会忘记添加另一个卷曲制动器。所以,我建议总是添加它,即使是像这样的单行:

for (i = 2; i < size; i++) {
    if (argv[i-1] != argv[i]) {
        a[i] = argv[i-1];
    }
}
即使你在这里也没有必要。