2016-11-21 2 views
1

Я пытаюсь взять пользовательский ввод и распечатать каждое слово на отдельной строке (без дубликатов). То, что я сделал до сих пор, может принимать пользовательский ввод и печатать каждую строку отдельно в алфавитном порядке. Что мне нужно сделать прямо сейчас быть в состоянии удалить дубликаты в пределах массива, что это символ * утверждают, []Удалить повторяющиеся элементы из массива указателей C

Мой вход:

./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; 
} 
+1

Сравнение указателей - это не то же самое, что сравнение строк. – jxh

ответ

0

В C строки не являются самим типом данных, а конвенцией, введенной языком. Важно помнить об этом.

Теперь, если у вас есть два указателя на символы, то даже если строки, на которые они указывают, идентичны, адреса, в которых они хранятся, могут быть не одинаковыми. Таким образом, сравнение

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]; 
    } 
} 

даже ты не действительно нужны здесь.

+0

Я сделал 'for (i = 2; i

+0

Да, проверьте начальные и конечные значения i в цикле и индексы массива, к которым вы обращаетесь. (т. е. положить некоторый 'printf (" строка% i: i =% i \ n ", __LINE__, i);' в коде и проанализировать, что происходит;) –

+0

О, и одна рекомендация об однострочных в 'if 'statements - я отвечу на мой вопрос, поскольку он включает форматирование кода ... –

1

Прежде всего, вы можете использовать стандартную функцию C qsort заявленной в заголовке <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; 
} 

Его выход будет таким же, как показано выше.

+0

адресуется, но он не поможет OP, он, очевидно, учится C и должен понимать концепцию струн и указателей. Этот ответ ему не поможет. –

+0

удалить из char * или просто использовать другой массив на самом деле не имеет значения. до тех пор, пока дубликаты исчезли @Arkadiy –

+0

это опрятное решение – artm