#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
В вашем коде есть несколько других странностей, но они не являются неправильными, просто то, что могло бы быть лучше:
- Вам не нужно приводить возвращаемое значение
malloc
в C, и некоторые (например, я) считают это плохим стилем по разным причинам, которые вы более чем способны найти в Google. sizeof(char)
всегда равно 1 (это определено в стандарте). Некоторые люди говорят, что нужно сохранить это для симметрии. Некоторые говорят, что удалите ее, поскольку она одна. Некоторые говорят, измените это наsizeof *path
, так что, если вы изменитеpath
наwchar_t *
,malloc
будет корректно скорректировано, чтобы сохранить выделение нужного размера.- Использование
strcat
для записи первого бита данных в строку потенциально неэффективно. Почему бы не удалитьpath[0] = '';
строку и просто использоватьstrcpy
для первого бита данных? - Вы вычисляете длины всех строк, но затем отбрасываете их и используете
strcat
, который повторно пересекает (ранее вычисленные) длины, чтобы найти нужное место. Если бы вы сохранили результаты ваших двухstrlen
вызовов, вам не нужно было бы использоватьstrcat
и без необходимости продолжать пересчитывать, где находится конец строки. - Использование
strcat
для добавления одного символа неэффективно. - Вы не проверяете возвращаемое значение
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 (я это исправил), иначе
*
символы исчезнут и будут выделены курсивом. Также вы можете отказаться от приведения.