#c #arrays #c #malloc #c-strings
Вопрос:
Как мне получить массив c_str из a std::vector
(внутри a struct
) для использования пользователями C?
Попытка:
#include <vector>
#include <algorithm>
typedef struct { size_t size; const char** arr; } CStrStrArray;
CStrStrArray f() {
const std::vector<const char*> cStrVec {"foo", "bar"};
/* pretend ^this is huge^ with size contents not known ahead of time */
const char **cStrArr = (const char**)malloc(cStrVec.size());
std::copy(cStrVec.begin(), cStrVec.end(), cStrArr);
/* also tried `cStrVec.data();` */
return {cStrVec.size(), cStrArr};
}
/* pretend this is 'main.c' and the above is in an `extern C` elsewhere */
int main(void) {
CStrStrArray c_str_arr = f();
free(c_str_arr.arr);
c_str_arr.size = 0;
return EXIT_SUCCESS;
}
Ошибка:
malloc: Incorrect checksum for freed object 0x7ff996d3d790: probably modified after being freed.
Corrupt value: 0x7ff996d08280
executable(17572,0x11c6d5e00) malloc: *** set a breakpoint in malloc_error_break to debug
Комментарии:
1. Привет @AT — вы не копируете содержимое, вы копируете указатели — и область содержимого завершена, когда метод завершен.. Попробуйте поместить «foo», как, скажем, статическую константу вне метода, и посмотрите, чем она отличается.
2. @MrR Это указатели на строковые литералы, так что можно копировать указатели yhe
Ответ №1:
Ваш код не выделяет достаточно памяти. Вы выделяете память только на 2 байта, но вам нужна память для 2 указателей символов. Так что измените это, как:
malloc(cStrVec.size()) --> malloc(cStrVec.size() * sizeof *cStrArr)
------------/ --------------/
Number of size of a single
char pointers char pointer
in the vector
-------------------------------/
Memory needed
Комментарии:
1. Должно быть
cStrVec.size() * sizeof(char *)
, вы тоже выделяете совпадение2. @Слава
cStrVec.size() * sizeof(char *)
-это то же самое, чтоcStrVec.size() * sizeof *cStrArr
. Однако последнее — «лучший стиль кодирования на языке Си» — по нескольким причинам. Аналогично:int d; assert(sizeof d == sizeof(int));
все в порядке3. Что меня зацепило в этом, так это то, что я могу ссылаться на переменную до того, как она будет «сделана», как будто это не имеет смысла
char c = c 5
; но я думаюsizeof
, что это особенное?4. Да, вы правы, я думал, что
cStrArr
это указатель наCStrStrArray
5. @В Да,
sizeof
это особенное.
Ответ №2:
Если вам нужно преобразовать std::vector<std::string>>
в CStrStrArray
вас, вам не нужен промежуточный шаг и создайте дополнительные std::vector<const char *>
:
CStrStrArray f( const std::vector<std::string> amp;v ) {
CStrStrArray r{ v.size(),
reinterpret_cast<const char **>( malloc( sizeof( char * ) * v.size() ) };
for( size_t i = 0; i < v.size(); i )
r.arr[i] = strdup( v[i].c_str() );
return r;
}
Комментарии:
1. Да, но я не могу сделать это
static
, потому что я не знаю его размер заранее…2. Вам не нужно заранее знать его размер, даже если он статичен, вы имеете в виду, что он будет меняться от звонка к звонку?
3. @Слава — Да, он вызывает HTTPS API на удаленном сервере, а затем я фильтрую ответ в строковый вектор, а затем преобразую этот строковый вектор в массив c_str
4. @В строковом векторе как?
5. Ну, у меня есть большой вектор структур, затем я преобразую его в вектор
std::string
(илиconst char*
), а затем преобразую его в массив c_str (const char**
).