Заполнение данной структуры происходит через специальный метод. который так же реализован чрез структуру SPLITTER, но это не суть важно. Метод проверен, отрабатывает верно и чисто. Для ясности приведу пример SPLITTER структуры
typedef struct
{
int colls_num; //number of substringschar **substrings; //substring values array
}SPLITTER;
Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):
Так вот. Суть в том, что при формировании структуры MAPPER на этапе формирования последнего value (то есть если всего у нас 4 элемента ИМЯ/ЗНАЧЕНИЕ ) возникает ошибка invalid fastbin entry (free): 0x0000000000c350f0 ***
То есть имя для 4 элемента формируется а значение нет.
Косяк где то вот тут:
else
{
if (i==2)
map.value=(char **)malloc(sizeof(char *)*j+1);
else
map.value=(char **)realloc(map.value,sizeof(char*)*j+1);
Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.
На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка (только пути к файлам исходников обработчиков поправьте, чтобы собралось). Буду благодарен за наводку.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.
EP>1. Зачем C? EP>2. Для C есть GLib.
Хочется поизобретать велосипед это раз и Я не знал что есть GLib это два)
O>Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.
Проблема в том, что ты записываешь свои данные в область памяти, которую ты не выделял. Ну а вскрывается это не сразу, а собственно при других операциях с памятью, вроде того же вызова realloc.
Вообще, код ужасен.
Попробуй для начала его разбить на функции, убрать копипасту, дать переменным нормальные имена, а не безликие i/j/k.
Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?
O>На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка
Молодец. Пусть там и лежат. Больше их не трогай, а возьми GLib :)
Здравствуйте, watchmaker, Вы писали:
O>Хотел думать что проблема с выделением нового блока памяти, но в таких случаях обычно выдается segfault. В чем именно проблема может быть еще -я пока что понять не могу.
Проблема в том, что ты записываешь свои данные в область памяти, которую ты не выделял. Ну а вскрывается это не сразу, а собственно при других операциях с памятью, вроде того же вызова realloc.
Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки? Если не сложно- можно более подробно? пока что не понятно где я с выделением памяти просчитался?
Вот здесь:
else
{
if (i==2)
map.value=(char **)malloc(sizeof(char *)*j+1);
else
map.value=(char **)realloc(map.value,sizeof(char*)*j+1);
Если я встречаю первое значение для value я выделяю память через valloc для элемента массива, если же у меня знчение отличное от первого, значит я могу утверждать что память уже выделена и остается только ее расширить на необходимое количество байт.
Не понимаю пока что что не так в этом куске?
W>Попробуй для начала его разбить на функции, убрать копипасту, дать переменным нормальные имена, а не безликие i/j/k.
Ок. Принято
W>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?
Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j
O>>На всякий случай положил исходники самих обработчиков MAPPER и SPLITTER в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка W>Молодец. Пусть там и лежат. Больше их не трогай, а возьми GLib
GLib не тяжеловата для таких, в общем то не сильно затратных операций? Может есть аналоги поменьше?
Здравствуйте, Ovoshlook, Вы писали:
W>>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ? O>Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j
map.name — это массив массивов, или по-другому — массив строк.
Количество элементов в массиве строк, зависит от количества строк, и не зависит от размера конкретной строки (то есть не зависит от j).
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
W>>>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ? O>>Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j
EP>map.name — это массив массивов, или по-другому — массив строк. EP>Количество элементов в массиве строк, зависит от количества строк, и не зависит от размера конкретной строки (то есть не зависит от j).
map.name=(char **)malloc(sizeof(char *)*j+1);
Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
O>Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
Хорошо, допустим ты так выделяешь память для конкретной строки. Тогда объясни, почему ты решил умножить j на sizeof(char*)? И почему у тебя тип результата является не указателем на строку, а указателем на массив указателей? И почему ты вообще присваиваешь результат переменной map.name?
O>Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки?
Такая ошибка называется buffer overflow. Ну то есть она бы так называлась, если бы в твоей программы был смысл :) На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.
O>>Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки. W>Хорошо, допустим ты так выделяешь память для конкретной строки. Тогда объясни, почему ты решил умножить j на sizeof(char*)? И почему у тебя тип результата является не указателем на строку, а указателем на массив указателей? И почему ты вообще присваиваешь результат переменной map.name?
j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
Так как переменная map.name массив массивов, то получается что делая realloc я добавляю память к массиву массивов, выделяя для элемента массива — строки, необходимое количество байт.
O>>Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки? W>Такая ошибка называется buffer overflow. Ну то есть она бы так называлась, если бы в твоей программы был смысл На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.
покажите конкретно пожалуйста- где у меня путаница с указателями. Я действитльно ее не вижу. я как бы не отрицаю вашей правоты и не убеждаю вас в вашей неправоте, мне просто искренне интересно где я накосячил (если накосячил) с выделением памяти и как оно по хорошему должно быть?
Здравствуйте, Ovoshlook, Вы писали:
O>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
EP>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
Здравствуйте, Ovoshlook, Вы писали:
O>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций) EP>>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов? O>Строка состоит из символов
char — тип символа char* — тип указателя на символ sizeof(T) — возвращает размер типа T
Как посчитать размер строки, состоящей из символов, зная общее количество символов?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций) EP>>>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов? O>>Строка состоит из символов
EP>char — тип символа EP>char* — тип указателя на символ EP>sizeof(T) — возвращает размер типа T EP>Как посчитать размер строки, состоящей из символов, зная общее количество символов?
умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов>
Здравствуйте, Ovoshlook, Вы писали:
O>>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)
[...] O>умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов>
Правильно, сравни с тем что было ранее, это одна из ошибок, на которую указал watchmaker.
Итак, зная размер строки X, мы можем выделить под неё буфер: malloc(X) — возвращает указатель на выделенный буфер размера X, либо нулевой указатель в случае fail.
Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*.
Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно):
char *string = malloc(X);
Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Ovoshlook, Вы писали:
O>>>>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций) EP>[...] O>>умножить размер одного символа на общее количество символов в строке. sizeof(char)*<количество_символов> EP> EP>Правильно, сравни с тем что было ранее, это одна из ошибок, на которую указал watchmaker.
EP>Итак, зная размер строки X, мы можем выделить под неё буфер: EP>malloc(X) — возвращает указатель на выделенный буфер размера X, либо нулевой указатель в случае fail.
EP>Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*. EP>Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно): EP>
EP>char *string = malloc(X);
EP>
EP>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
Здравствуйте, Ovoshlook, Вы писали:
EP>>Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*. EP>>Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно): EP>>
EP>>char *string = malloc(X);
EP>>
EP>>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
O>Чтобы положить в нее свое значение
Откуда? из arr->substrings[i-1]?
То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
Как именно ты собрался это делать?
O>>Чтобы положить в нее свое значение
EP>Откуда? из arr->substrings[i-1]? EP>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string? EP>Как именно ты собрался это делать?
Здравствуйте, Ovoshlook, Вы писали:
O>Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):
Такое впечатление, что этот код был переписан с паскаля. Индекс от 1 до colls_num включительно, проверка нечётности (!!!), и т.п.
Можно я его просто начисто перепишу?
Это если помещать каждую строку в отдельный блок.
А если хочется разместить все данные в одном блоке, чтобы mapper.name указывал на таблицу индексов, откуда ссылки вели бы на строки в этом же блоке, то НЕЛЬЗЯ делать realloc.
Потому что ты, тем самым, сбиваешь все указатели, которые были внутрь старого блока.
Здравствуйте, Ovoshlook, Вы писали:
O>>>Чтобы положить в нее свое значение EP>>Откуда? из arr->substrings[i-1]? EP>>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string? EP>>Как именно ты собрался это делать? O>map.name[k]=arr->substrings[i-1];
Тут происходит копирование адреса, а не самой строки. Причём тот адрес который был раньше слева — затирается.
P.S. По всей видимости ты только начинаешь изучение C. Если в дальнейшем планируешь перейти на C++, то нет никакой необходимости сначала учить C — это только привьёт вредные привычки, которые к тому же порождают тормозной код.
Советую начать с книги Страуструпа — Programming -- Principles and Practice Using C++ (или на русском).