Обеспечение безопасности memmove() с помощью realloc()
В моей функции заменить подстроку. Если входная подстрока длиннее исходной, она перемещает часть входной строки, чтобы освободить место для входной подстроки.
Я понимаю, что это приводит к неопределенному поведению. Я думал, что смогу выделить необходимое пространство с помощью realloc(), но не увенчался успехом.
Я попытался добавить это до memmove():
char *newspc = (char*)realloc(in,len+sublen);
in = newspc;
Это разумная стратегия? Как правильно освободить место для этой операции?
Вот программа без использования realloc():
#include <iostream>
#include <string>
#include <string.h>
void replc(char* in, char* subin);
int main()
{
char stmt[] = "replacing this $string ok";
std::cout << stmt << "\n";
replc(stmt, "longerstring"); //<<<4 characters longer breaks the program
std::cout << stmt << "\n";
}
void replc(char* in, char* subin){
uint8_t len = strlen(in);
uint8_t aftok = strchr(strchr(in, '$'), ' ')-in;
uint8_t dollar = strchr(in, '$')-in;
uint8_t tklen = aftok - dollar;
uint8_t sublen = strlen(subin);
if(sublen <= tklen){
//enough room for substring
memmove(in+aftok-(tklen-sublen), in+aftok, (tklen-sublen)+1);
memcpy(in+dollar, subin, sublen);
in[len-(tklen-sublen)] = '\0';
}
else{
//not enough room for substring
// memory allocation should take place here?
memmove(in+aftok+(sublen-tklen), in+aftok, (sublen-tklen)+1);
memcpy(in+dollar, subin, sublen);
in[len+(sublen-tklen)] = '\0';
}
}
1 ответ
Во-первых, если вы хотите использовать realloc, вам не нужно использовать memmove, так как realloc позаботится о копировании данных.
От мужчины:
Функция realloc() изменяет размер блока памяти, на который указывает ptr, на размер в байтах. Содержимое будет неизменным в диапазоне от начала региона до минимума старого и нового размеров.
Кроме того, вы можете использовать realloc только для указателя, ранее возвращенного malloc, realloc или calloc
Если ptr не равен NULL, он должен быть возвращен более ранним вызовом malloc(), calloc() или realloc().
Так что вам нужно использовать malloc в вашем главном
char *stmt = malloc(strlen("replacing this $string ok") + 1);
if (stmt)
stmt = "replacing this $string ok";
Во-вторых, если вы хотите изменить значение указателя в функции вызывающей стороны, вам нужно использовать указатель на этот указатель (стиль C) или ссылку (стиль C++), иначе указатель в вызывающей стороне будет указывать на старый адрес.
Пример в стиле C для прототипа:
void replc(char** in, char* subin);
Распределение (с NewSize в качестве целого числа):
*in = realloc(*in, NewSize);
(Имейте в виду, что malloc и realloc могут возвращать NULL в случае неудачного размещения)