Удаление строки из массива строк в C (т.е. удаление элемента из элемента из 2D-массива) - PullRequest
0 голосов
/ 07 августа 2020

Итак, у меня есть массив строк, содержащий дубликаты. Моя общая цель - удалить дубликаты и соответственно изменить размер массива. Наилучшим способом решения этой проблемы до сих пор было использование функции memmove ().

Мой текущий подход к тестированию - это l oop через массив и сканирование каждого элемента. Если строка встречается более одного раза, я бы перезаписал дубликат следующим элементом в списке, используя memmove (). Каждый элемент в списке также будет перемещен на одну позицию вверх в массиве с помощью memmove (). Затем я бы изменил размер всего массива, чтобы удалить пустые ячейки памяти в конце массива.

Я объявил массив следующим образом:

char source[43][20];

Массив представляет собой просто список городов (я включил только первые 6 для демонстрации):

York
Leeds
Liverpool
Manchester
Reading
Oxford

Мне удалось перезаписать первый элемент вторым элементом со следующим кодом:

memmove(&(source[0][0]), &(source[1][0]), strlen(source[1]) * sizeof(char));

Давая это вывод:

Leeds
Leeds
Liverpool
Manchester
Reading
Oxford

, но когда я пытаюсь перезаписать третий элемент поверх второго с помощью этого кода:

memmove(&(source[1][0]), &(source[2][0]), strlen(source[2]) * sizeof(char));

, я получаю следующий результат:

Leeds
Liverpooφu
Liverpool
Manchester
Reading
Oxford

Как видите, «Ливерпуль» работает не так, как задумано. В настоящее время я не знаю, как изменить размер массива, поэтому буду благодарен за любые идеи по этому поводу. Благодарю за любую помощь, ребята :).

Ответы [ 3 ]

3 голосов
/ 07 августа 2020

Когда вы делаете копию, вы не копируете завершающий нулевой байт. Это означает, что любой мусор, который окажется после того, что было скопировано, будет прочитан как часть строки.

Поскольку у вас есть элементы массива фиксированного размера, просто скопируйте весь подмассив:

memcpy(source[0], source[1], sizeof(source[0]));

И если вы хотите переместить несколько элементов:

memmove(source[0], source[1], sizeof(source[0]) * num_to_move);
0 голосов
/ 07 августа 2020

Обратите внимание, что вы не можете изменять размер массивов. Чтобы иметь возможность использовать realloc, вы можете сделать что-то вроде этого:

char (*source)[20] = malloc(sizeof *source * 43);

Это даст вам указатель на массив из 20 символов, а затем вы выделите память для 43 таких массивов. Позже его можно будет перераспределить. Вот так:

char (*source)[20] tmp = realloc(source, sizeof *source * size);
if(tmp)
    source = tmp;
else
    // Handle error

Обратите внимание, что char (*source)[20] полностью отличается от char *source[20]. Последний представляет собой массив из 20 указателей.

Также обратите внимание, что sizeof может быть немного сложным. Вышеупомянутое работает, но его нужно будет изменить, если вы использовали char **source вместо char (*source)[20].

Для полноты, даже если другие упомянули об этом, ваша проблема в том, что вы не копируете \0 персонаж. Самое простое решение - использовать strcpy, но strncpy безопаснее.

strncpy(source[0], source[1], 20);
0 голосов
/ 07 августа 2020

Вы забыли про нулевой символ завершения при копировании строк. Вам нужно strlen(...) + 1, чтобы скопировать строку, содержащую нулевой символ завершения.

sizeof(char) можно опустить - char всегда 1 байт, sizeof(char) всегда 1.

Нет необходимости чтобы использовать здесь memmove, предполагая, что strlen(source[2]) + 1 < 20, тогда source[1], source[1] + strlen(source[2]) и source[2], source[2] + strlen(source[2])] - отдельные области памяти. Тогда просто memcpy. Но если на то пошло, просто strcpy строк.

strcpy(source[0], stource[1]);
strcpy(source[1], stource[2]);
// etc...

Если вас не волнует копирование лишних байтов, вы можете переместить все строки вверх за один go, например:

memmove(&source[0], &source[1], sizeof(source) - 1 * sizeof(*source));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...