В C, как удалить идентичные и последовательные строки в массиве символов? - PullRequest
0 голосов
/ 26 апреля 2018

Мне нужна помощь в создании функции.

Функция deleteIdents () удалит идентичные строки в массиве char, если они являются последовательными.Он сохранит одну из идентичных строк.

Мне не нужно проверять, идентична ли вся строка.Только первые 79 символов, MAXCHARS, подойдут для этого сценария.

Так, например, если мой массив содержит

Hello World
Hi World
Hello World
Hello World
Hello World
Hi there

, он будет изменен на

Hello World
Hi World
Hello World
Hi there

В моей голове эта функция будет выглядеть примерно так:

int deleteIdents(char *a)
{
    int i;
    for (i=0; i<=MAXCHARS; i++) {
        if (a[i] != '\n')
            /* copy into new array */
        }
    }
}

, но я не уверен.Если у вас есть решение, я был бы рад и благодарен услышать его:)

Ответы [ 4 ]

0 голосов
/ 28 апреля 2018

Еще один пример того, как этого можно достичь.Идея состоит в том, чтобы сохранить 2 указателя и увеличивать первый только если записи разные.Также выделяется некоторое дополнительное хранилище, чтобы избежать утечек памяти для записей, которые были переопределены.

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

int unique(char **strings, int size) {
    if (!strings) {
        return -1;
    }
    int head = 0, newHead = 0, duplicatedElementsHead = 0;
    //Save duplicates to avoid memory leaks
    char** duplicatedEntries = malloc(size*sizeof(char*));

    while (head < size) {
        //String are the same
        if (!strcmp(strings[head], strings[newHead])) {
            if (head != newHead) {
                duplicatedEntries[duplicatedElementsHead++] = strings[newHead];
            }
            ++head;
        } else {
            strings[++newHead] = strings[head++];
        }
    }

    //Put duplicated entries after new end
    int idx = 0, tmpHead = newHead + 1;
    for (; idx < duplicatedElementsHead; ++idx) {
        strings[tmpHead++] = duplicatedEntries[idx];
    }

    free(duplicatedEntries);
    return newHead;
}

int main() {
    char **strings = malloc(8*sizeof(char*));
    strings[0] = "Hello World";
    strings[1] = "Hi World";
    strings[2] = "Hi World";
    strings[3] = "Hello World";
    strings[4] = "Hello World";
    strings[5] = "Hi there";
    strings[6] = "Hia";
    strings[7] = "Hi";
    int newEnd = unique(strings, 8);
    for (int i=0; i < newEnd; ++i) {
        printf("%s\n", strings[i]);
    }
    free(strings);
}
0 голосов
/ 26 апреля 2018

Вы, по сути, пишете основные функции утилиты unix / linux 'uniq'.

cat filename | sort | uniq > newfile
#or skip sort, since you didn't mention
cat filename | uniq > newfile

Вы можете просто использовать popen и uniq (что-то вроде этого ...)

FILE *uniqfh;
uniqfh = popen("cat file1 | uniq" , "r");
if (uniqfh == NULL) { //handle error
}
while( fgets(uniqfh, buffer, buffersize) ) printf("%s\n",buffer);

А если серьезно, вы могли бы написать ядро ​​uniq (),

static long MAXUNIQ=79; //or whatever you want
char*
isdup(char* prev, char* next, long len)
{
    //if( !prev || !next) error
    long n = len<=0 ? MAXUNIQ : len;
    for(  ; *prev==*next && n --> 0; ) { //down-to operator (sic)
        ; //clearly nothing happening here!
    }
    return( (n<1) || !(*p+*n) );
}
/yeah, this is actually strncmp, but hey

Вам нужен массив 'строк' (char * или char []), давайте прочитаем их,

char* ray[ARRAYMAX]; //define how many elements of your arRay
//could use, char** ray; and malloc(ARRAYMAX*sizeof(char*))

long
read_array(FILE* fh, char* ray[])
{
    char buffer[MAXLINE+1];
    long count=0;
    while( fgets(buffer,sizeof(buffer),fh) ) {
        //you could eat dups here, or in separate function below
        //if( (count<1) && !isdup(ray[count-1],buffer,MAXUNIQ) )
        ray[count++] = strdup(buffer);
    }
    //ray[0] through ray[count-1] contain char*
    //count contains number of strings read
    return count;
}
long
deleteIdents(long raysize, char* ray[]) //de-duplicate
{
    long kept, ndx;
    for( ndx=1, kept=0; ndx<raysize; ++ndx ) {
        if( !isdup(ray[kept],ray[ndx]) ) {
            ray[kept++] = ray[ndx];
        }
        else {
            free(ray[ndx]);
            ray[ndx] = NULL; //not entirely necessary, 
        }
    }
    return kept; //new ray size
}

И вам нужно будет это назвать ...

...
long raysize;
char* ray[ARRAYMAX] = {0}; //init to null pointers
raysize = read_array(fopen(filename,"r"),ray);
raysize = deleteIndents(raysize,ray);
...

Позже вам нужно будет освободить строки malloc,

for( ; 0 <-- raysize; ) { free(ray[raysize]);  ray[raysize] = NULL; }
0 голосов
/ 26 апреля 2018

Следующая программа делает то, что вам нужно для массива строковых элементов.Мы перемещаемся по массиву с двумя указателями, инициализированными для первого и второго элементов.Мы запускаем цикл array_n - 1 сравнений одного элемента со следующим, сравнивая обе строки ... если они разные, мы копируем указатель строки *source_ptr в место *target_ptr.Если они отличаются, мы только увеличиваем source_ptr, поэтому он указывает на следующую строку массива, но , не копируя ее (это заставляет нас эффективно удалить указатель). Мы также управляем новым массивом (мыиспользовали один и тот же массив как источник и пункт назначения, так как мы можем удалять только элементы массива, поэтому каждый раз, когда между обоими указателями появляется большая дыра)

pru.c

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

/* array of strings */    
char *array[] = {
    "Hello World",
    "Hi World",
    "Hello World",
    "Hello World",
    "Hello World",
    "Hi there",
};

size_t array_n = sizeof array / sizeof *array;

int main()
{
    int i;

    char **target_ptr = array, **source_ptr = array + 1;
    size_t new_length = 1;

    for (i = 1; i < array_n; i++) {
        /* if strings pointed to by pointers are equal */
        if (strcmp(*target_ptr, *source_ptr) == 0) {
            /* go to the next, effectively discarding the second pointer */
            source_ptr++;
        } else {
            /* copy both pointers in place, to the destination array */
            *target_ptr++ = *source_ptr++;
            new_length++; /* increment array length */
        }
    }
    /* finally, we have in the array only the good pointers */

    /* print'em */
    for (i = 0; i < new_length; i++)
        printf("%s\n", array[i]);

    exit(0);
}

, и этовсе.

образец прогона:

$ pru
Hi World
Hello World
Hi there
Hello World
$ _
0 голосов
/ 26 апреля 2018

Хорошо прочитайте первую строку, а не вторую, сравните их, если они равны, войдите в цикл, пока они не будут равны.Итак, вот код:

char *first_line = malloc(MAXLINE);
char *second_line = malloc(MAXLINE);

getline(first_line);

do {
   getline(second_line);
} while (strcmp (first_line, second_line));

Для поиска getline() реализации, так что существует множество примеров.Или здесь у вас есть мой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...