Ошибка повреждения памяти Malloc () после объединения строки

#c #string #memory-management #strcat

#c #строка #управление памятью #strcat

Вопрос:

Ребята, я генерирую строку, которая отображает путь к файлу, объединяя макрос и строку. Функция заключается в следующем:

 char *userPath(char *username)
{
   char *path = (char*)malloc(sizeof(char) * (strlen(MAILBOXES)   strlen(username)   1));
   path[0] = '';
   strcat(path, MAILBOXES);
   strcat(path, "/");
   strcat(path, username);
   return path;
}
  

Возвращенный указатель ссылается на правильную строку, но после некоторого вызова этой функции процесс выдает очень, очень плохое сообщение * обнаружен glibc ./mmboxd: malloc(): повреждение памяти: 0x085310a8 ** с относительной обратной трассировкой. Я знаю, что проблема здесь, поскольку у меня возникла эта ошибка после ее реализации, а также потому, что единственный malloc, который я использую, находится здесь. Что не так с этим фрагментом кода?

Комментарии:

1. Приведение malloc не требуется и sizeof(char) равно 1 по определению, поэтому вы можете упростить malloc вызов char *path = malloc(STRLEN(MAILBOXES) strlen(username) 2);

2. @John Bode — Некоторые люди (не обязательно я) говорят, что вам следует использовать char *path = malloc(sizeof *path * whatever); , чтобы при изменении типа path (скажем, на wchar_t * ) malloc соответствующим образом скорректировать размер.

3. Запись, sizeof *path возможно, разумна, но sizeof(char) определенно нет.

4. @Chris Lutz: на самом деле, это моя обычная парадигма, но я решил, что сделаю это как можно проще.

Ответ №1:

1 должно быть 2, чтобы учесть добавляемый вами разделитель и нулевой ограничитель. И вы можете опустить sizeof(char), который всегда будет равен 1.

Ответ №2:

Вот в чем проблема:

    char *path = (char*)malloc(sizeof(char) * (strlen(MAILBOXES)   strlen(username)   1));
  

Вы выделяете достаточно памяти для a) всех символов в MAILBOXES , b) всех символов в username и c) '/' символа, но вы забываете d) завершающий '' символ! Так 1 должно быть 2

В вашем коде есть несколько других странностей, но они не являются неправильными, просто то, что могло бы быть лучше:

  1. Вам не нужно приводить возвращаемое значение malloc в C, и некоторые (например, я) считают это плохим стилем по разным причинам, которые вы более чем способны найти в Google.
  2. sizeof(char) всегда равно 1 (это определено в стандарте). Некоторые люди говорят, что нужно сохранить это для симметрии. Некоторые говорят, что удалите ее, поскольку она одна. Некоторые говорят, измените это на sizeof *path , так что, если вы измените path на wchar_t * , malloc будет корректно скорректировано, чтобы сохранить выделение нужного размера.
  3. Использование strcat для записи первого бита данных в строку потенциально неэффективно. Почему бы не удалить path[0] = ''; строку и просто использовать strcpy для первого бита данных?
  4. Вы вычисляете длины всех строк, но затем отбрасываете их и используете strcat , который повторно пересекает (ранее вычисленные) длины, чтобы найти нужное место. Если бы вы сохранили результаты ваших двух strlen вызовов, вам не нужно было бы использовать strcat и без необходимости продолжать пересчитывать, где находится конец строки.
  5. Использование strcat для добавления одного символа неэффективно.
  6. Вы не проверяете возвращаемое значение malloc на предмет успеха или неудачи перед его использованием.

Комментарии:

1. Спасибо! Я гуглю, чтобы лучше определить, какая божественная практика не приводить malloc, и я буду использовать strcpy для первого байта

2. Лучше вообще не использовать strcpy и strcat . Вместо этого используйте, snprintf(path, len, MAILBOXES "/%s", username); где len совпадает с аргументом, который вы передали malloc . Таким образом, нет опасности переполнения.

3. @R .. — Если malloc не произошел сбой (о чем я еще забыл упомянуть), в любом случае нет опасности переполнения, как только OP исправит ошибку «один за другим».

4. Я имею в виду, что если бы OP сделал это с snprintf , то вопрос был бы «почему усекается последний символ?» вместо «почему у меня повреждение памяти?» и OP, вероятно, выяснил бы это, даже не спрашивая.

Ответ №3:

Похоже, вы не оставили места для нулевого разделителя. Вы должны выделить дополнительный char для этого.

Я предполагаю, что 1 в malloc() используется разделитель путей. Сделайте это 2 , и у вас останется место для завершающего нулевого символа.

Ответ №4:

Когда вы выделяете строку «path», вы забыли добавить длину символа «/», который вы добавляете между ПОЧТОВЫМИ ЯЩИКАМИ и именем пользователя.

Ответ №5:

Похоже, вам потребуется ввести в malloc еще один байт для нулевого завершения.

Ответ №6:

Вам необходимо выделить один дополнительный байт для нулевого символа » x00″ в качестве ограничителя строки в строках C.

В настоящее время вы выделяете только один дополнительный байт для символа / .

Поэтому попробуйте 2 вместо 1

Ответ №7:

Вы не вводите бюджет в символ для завершающего значения null. Ваша длина malloc должна быть 2, а не 1.

Ответ №8:

Ваш 1 в конце malloc() учитывает / . Но вам нужно место для нулевого символа в конце, который добавляется с помощью strcat() . Итак, это 2 .

 char *path = (char*)malloc(sizeof(char) * (strlen(MAILBOXES)   strlen(username)   2));
  

Комментарии:

1. Обязательно отформатируйте свой код как code (я это исправил), иначе * символы исчезнут и будут выделены курсивом. Также вы можете отказаться от приведения.