invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 12:10
Оценка: :)
Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.

В общем случае MAPPER это структура котороая имеет следующий вид:


typedef struct
        {
                int colls_num; //number of MAPPING strings
                char **name;  //number of substrings
                char **value;      //substring values array
        }MAPPER;


То есть в заполненном виде вывод структуры может иметь вид:


colls_num: 2

name: name1 value: value1
name: name2 value: value2


Заполнение данной структуры происходит через специальный метод. который так же реализован чрез структуру SPLITTER, но это не суть важно. Метод проверен, отрабатывает верно и чисто. Для ясности приведу пример SPLITTER структуры



typedef struct
        {
                int colls_num;  //number of substrings
                char **substrings;      //substring values array
        }SPLITTER;




Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):





MAPPER MAP_string(SPLITTER *arr)
{
        MAPPER map;

        int i=0;

        int k=0;

        for (i=1;i<=arr->colls_num;i++)
        {
                //int j=0;

                //while (arr->substrings[i-1][j]!='\0') j++;
                int j=strlen(arr->substrings[i-1]);

                if ((i+1)%2 == 0)
                {

                        if (i==1)

                                map.name=(char **)malloc(sizeof(char *)*j+1);

                        else

                                map.name=(char **)realloc(map.name,sizeof(char*)*j+1);

                        printf("i='%u'\n",i);
                        printf("k='%u'\n",k);
                        map.name[k]=arr->substrings[i-1];
                        printf("name %u %s\n",k,map.name[k]);

                }
                else

                {
                        if (i==2)

                                map.value=(char **)malloc(sizeof(char *)*j+1);

                        else

                                map.value=(char **)realloc(map.value,sizeof(char*)*j+1);

                        printf("i='%u'\n",i);
                        printf("k='%u'\n",k);
                        map.value[k]=arr->substrings[i-1];
                        printf("value %u %s\n",k,map.value[k]);


                        k++;

                }
        }

map.colls_num=k++;
printf("%u\n",arr->colls_num);
printf("%u\n",map.colls_num);
printf("%s\n",map.value[0]);


return map;

}


Так вот. Суть в том, что при формировании структуры 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 в отдельный файл и запихнул так же исходник с тестовым примером где проявляется ошибка (только пути к файлам исходников обработчиков поправьте, чтобы собралось). Буду благодарен за наводку.
Re: invalid fastbin entry (free):
От: watchmaker  
Дата: 17.04.14 13:04
Оценка: +1
Здравствуйте, Ovoshlook, Вы писали:


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 :)
Re[5]: invalid fastbin entry (free):
От: watchmaker  
Дата: 17.04.14 19:54
Оценка: +1
Здравствуйте, Ovoshlook, Вы писали:


O>map.name=(char **)malloc(sizeof(char *)*j+1);

O>Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
Хорошо, допустим ты так выделяешь память для конкретной строки. Тогда объясни, почему ты решил умножить j на sizeof(char*)? И почему у тебя тип результата является не указателем на строку, а указателем на массив указателей? И почему ты вообще присваиваешь результат переменной map.name?

O>Ну как же не выделял если я ее тем же самым realloc выделяю для записи этой строки?

Такая ошибка называется buffer overflow. Ну то есть она бы так называлась, если бы в твоей программы был смысл :) На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.
Re: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 12:28
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.


1. Зачем C?
2. Для C есть GLib.
Re[2]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 12:31
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


O>>Всем привет. реализую некое подобие MAP для C. С динамическим выделением памяти под поля name и value.


EP>1. Зачем C?

EP>2. Для C есть GLib.

Хочется поизобретать велосипед это раз и Я не знал что есть GLib это два)
Re[2]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 12:41
Оценка:
Тем не менее ответ на вопрос очень хочется узнать)
Re[2]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 18:16
Оценка:
Здравствуйте, 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 не тяжеловата для таких, в общем то не сильно затратных операций? Может есть аналоги поменьше?
Re[3]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 18:22
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

W>>Вот, например, если смотреть на имена, то почему у тебя j хранит длину строки в одном месте: int j=strlen(arr->substrings[i-1]);, а в другим месте — используется для определения длины массива указателей, которые ссылаются на эти строки: map.name=(char **)malloc(sizeof(char *)*j+1); ?

O>Потому что выделяемая область памяти зависит от размера строки, который в свою очередь хранит переменная j

map.name — это массив массивов, или по-другому — массив строк.
Количество элементов в массиве строк, зависит от количества строк, и не зависит от размера конкретной строки (то есть не зависит от j).
Re[4]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 19:47
Оценка:
Здравствуйте, 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);

Так я выделяю для конкретного элемента массива. То есть не для количества строк в этом массиве, а для уже конкретной строки.
Re[6]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 20:15
Оценка:
Здравствуйте, watchmaker, Вы писали:


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. Ну то есть она бы так называлась, если бы в твоей программы был смысл На самом деле, как уже повторно заметили, в коде безнадёжно перепутаны указатели на строки и массивы указателей.

покажите конкретно пожалуйста- где у меня путаница с указателями. Я действитльно ее не вижу. я как бы не отрицаю вашей правоты и не убеждаю вас в вашей неправоте, мне просто искренне интересно где я накосячил (если накосячил) с выделением памяти и как оно по хорошему должно быть?
Re[7]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 20:20
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)


Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
Re[8]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 21:22
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


O>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)


EP>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?


Строка состоит из символов
Re[9]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 21:27
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>>>j содержит в себе длину сроки, которую я хочу положить в массив. Чтобы ее положить туда, мне нужно в массиве выделить память равную длине этой строки +1 (для символа \0) , где под каждый символ строки выделяется sizeof(char*) байт. Соответственно количество памяти которое должно выделиться под строку = sizeof(char*)*(j+1) (вот кстати похоже 1 ошибку нашел по приоритетам арифметических операций)

EP>>Давай по порядку. Из каких элементов состоит строка? Из указателей или из символов?
O>Строка состоит из символов

char — тип символа
char* — тип указателя на символ
sizeof(T) — возвращает размер типа T
Как посчитать размер строки, состоящей из символов, зная общее количество символов?
Re[10]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 21:34
Оценка:
Здравствуйте, 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)*<количество_символов>
Re[11]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 21:54
Оценка:
Здравствуйте, 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);

Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?
Re[12]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 17.04.14 21:59
Оценка:
Здравствуйте, 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>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?

Чтобы положить в нее свое значение
Re[13]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 17.04.14 22:10
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

EP>>Строка в C, обычно представляется как массив символов. Точнее как указатель на первый символ строки, который имеет тип char*.

EP>>Соответственно выделив буфер, сохраним его в переменной с правильным типом (а раз у нас C, то приведение типов не нужно):
EP>>
EP>>char *string = malloc(X);
EP>>

EP>>Далее вопрос, для чего тебе нужна эта новая строка (на данный момент содержащая мусор)?

O>Чтобы положить в нее свое значение


Откуда? из arr->substrings[i-1]?
То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
Как именно ты собрался это делать?
Re[14]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 18.04.14 04:17
Оценка:
O>>Чтобы положить в нее свое значение

EP>Откуда? из arr->substrings[i-1]?

EP>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
EP>Как именно ты собрался это делать?

map.name[k]=arr->substrings[i-1];
Re: invalid fastbin entry (free):
От: Кодт Россия  
Дата: 18.04.14 10:05
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):


Такое впечатление, что этот код был переписан с паскаля. Индекс от 1 до colls_num включительно, проверка нечётности (!!!), и т.п.
Можно я его просто начисто перепишу?
MAPPER make_mapper(SPLITTER *splitter)
{
    MAPPER mapper;
    int i;

    mapper.colls_num = splitter->colls_num / 2; /* сразу знаем количество */
    mapper.name  = (char**) malloc(mapper.colls_num * sizeof(char*));
    mapper.value = (char**) malloc(mapper.colls_num * sizeof(char*));

    for(i=0; i<mapper.colls_num; ++i)
    {
        mapper.name [i] = strdup(splitter->substrings[i*2  ]); /* не морочим себе голову, берём стандартную функцию аллокации строк */
        mapper.value[i] = strdup(splitter->substrings[i*2+1]);
    }

    return mapper;
}

Это если помещать каждую строку в отдельный блок.
А если хочется разместить все данные в одном блоке, чтобы mapper.name указывал на таблицу индексов, откуда ссылки вели бы на строки в этом же блоке, то НЕЛЬЗЯ делать realloc.
Потому что ты, тем самым, сбиваешь все указатели, которые были внутрь старого блока.

Делаем более чисто:
char* putback(char* /*in-out*/ *pblock, char const* str)
{
    char* block = *pblock;
    int size;
    size = strlen(str) + 1;

    strcpy(block, str); /* копируем строку */
    (*pblock) += size; /* двигаем указатель начала блока */
    return block; /* возвращаем адрес копии */
}

MAPPER make_mapper(SPLITTER *splitter)
{
    MAPPER mapper;
    int n, i;
    int len_names, len_values;
    char* block_names;
    char* block_values;

    n = splitter->colls_num / 2;

    /* считаем потребную память */
    len_names = 0;
    len_values = 0;
    for(i=0; i<n; ++i)
    {
        len_names  += strlen(splitter->substrings[i*2  ]) + 1; /* включая концевые нули */
        len_values += strlen(splitter->substrings[i*2+1]) + 1;
    }

    /* выделяем память */
    block_names  = (char*) malloc(n*sizeof(char*) + len_names *sizeof(char));
    block_values = (char*) malloc(n*sizeof(char*) + len_values*sizeof(char));

    /* настраиваем структуру */
    mapper.colls_num = n;
    mapper.name  = (char**) block_names;  block_names  += n*sizeof(char*);
    mapper.value = (char**) block_values; block_values += n*sizeof(char*);

    /* копируем строки */
    for(i=0; i<n; ++i)
    {
        mapper.name [i] = putback(&block_names,  splitter->substrings[i*2  ]);  
        mapper.value[i] = putback(&block_values, splitter->substrings[i*2+1]);
    }

    return mapper;
}
Перекуём баги на фичи!
Re[15]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 18.04.14 11:21
Оценка:
Здравствуйте, 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++ (или на русском).
Re[2]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 18.04.14 18:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Ovoshlook, Вы писали:


O>>Исходный код формирования структуры MAPPER вот такой (printf для теста. можно не обращать внимание):


К>Такое впечатление, что этот код был переписан с паскаля. Индекс от 1 до colls_num включительно, проверка нечётности (!!!), и т.п.

К>Можно я его просто начисто перепишу?
К>
К>MAPPER make_mapper(SPLITTER *splitter)
К>{
К>    MAPPER mapper;
К>    int i;

К>    mapper.colls_num = splitter->colls_num / 2; /* сразу знаем количество */
К>    mapper.name  = (char**) malloc(mapper.colls_num * sizeof(char*));
К>    mapper.value = (char**) malloc(mapper.colls_num * sizeof(char*));

К>    for(i=0; i<mapper.colls_num; ++i)
К>    {
К>        mapper.name [i] = strdup(splitter->substrings[i*2  ]); /* не морочим себе голову, берём стандартную функцию аллокации строк */
К>        mapper.value[i] = strdup(splitter->substrings[i*2+1]);
К>    }

К>    return mapper;
К>}
К>

К>Это если помещать каждую строку в отдельный блок.
К>А если хочется разместить все данные в одном блоке, чтобы mapper.name указывал на таблицу индексов, откуда ссылки вели бы на строки в этом же блоке, то НЕЛЬЗЯ делать realloc.
К>Потому что ты, тем самым, сбиваешь все указатели, которые были внутрь старого блока.

К>Делаем более чисто:

К>
К>char* putback(char* /*in-out*/ *pblock, char const* str)
К>{
К>    char* block = *pblock;
К>    int size;
К>    size = strlen(str) + 1;

К>    strcpy(block, str); /* копируем строку */
К>    (*pblock) += size; /* двигаем указатель начала блока */
К>    return block; /* возвращаем адрес копии */
К>}

К>MAPPER make_mapper(SPLITTER *splitter)
К>{
К>    MAPPER mapper;
К>    int n, i;
К>    int len_names, len_values;
К>    char* block_names;
К>    char* block_values;

К>    n = splitter->colls_num / 2;

К>    /* считаем потребную память */
К>    len_names = 0;
К>    len_values = 0;
К>    for(i=0; i<n; ++i)
К>    {
К>        len_names  += strlen(splitter->substrings[i*2  ]) + 1; /* включая концевые нули */
К>        len_values += strlen(splitter->substrings[i*2+1]) + 1;
К>    }

К>    /* выделяем память */
К>    block_names  = (char*) malloc(n*sizeof(char*) + len_names *sizeof(char));
К>    block_values = (char*) malloc(n*sizeof(char*) + len_values*sizeof(char));

К>    /* настраиваем структуру */
К>    mapper.colls_num = n;
К>    mapper.name  = (char**) block_names;  block_names  += n*sizeof(char*);
К>    mapper.value = (char**) block_values; block_values += n*sizeof(char*);

К>    /* копируем строки */
К>    for(i=0; i<n; ++i)
К>    {
К>        mapper.name [i] = putback(&block_names,  splitter->substrings[i*2  ]);  
К>        mapper.value[i] = putback(&block_values, splitter->substrings[i*2+1]);
К>    }

К>    return mapper;
К>}
К>


Огромное спасибо, хотя не совсем понятно почему нельзя использовать Realloc при выделении добавлении нового участка памяти к уже созданному массиву в динамике.
Re[16]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 18.04.14 18:42
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Ovoshlook, Вы писали:


O>>>>Чтобы положить в нее свое значение

EP>>>Откуда? из arr->substrings[i-1]?
EP>>>То есть тебе нужно скопировать стоку, первый символ которой находится по адресу arr->substrings[i-1], в строку, первый символ которой находится по адресу string?
EP>>>Как именно ты собрался это делать?
O>>map.name[k]=arr->substrings[i-1];

EP>Тут происходит копирование адреса, а не самой строки. Причём тот адрес который был раньше слева — затирается.


EP>P.S. По всей видимости ты только начинаешь изучение C. Если в дальнейшем планируешь перейти на C++, то нет никакой необходимости сначала учить C — это только привьёт вредные привычки, которые к тому же порождают тормозной код.

EP>Советую начать с книги Страуструпа — Programming -- Principles and Practice Using C++ (или на русском).

Да. Я в курсе что передастся адрес на начало строки. Но собственно это и нужно- чтобы не плодить копии одной и той же строки. Да, с С я недавно познакомился и очень интересует именно работа с памятью, многопоточность, минималистичность и тому подобное. Естественно 1 блин комом, но поэтому сюда и обращаюсь, чтобы как не оставлять пробелов и понять недостающее. С С++ пока что не намерен связываться, хотя раньше писал дипломный проект на нем, точнее на Qt, все таки там очень высокоуровневое все, поэтому база не большая. За ссылку отдельное спасибо тем не менее.
Re[17]: invalid fastbin entry (free):
От: Evgeny.Panasyuk Россия  
Дата: 18.04.14 20:12
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>Да. Я в курсе что передастся адрес на начало строки. Но собственно это и нужно- чтобы не плодить копии одной и той же строки.


Ок, но если не нужны копии — тогда для чего выделять буфер размером со строку?

O>Да, с С я недавно познакомился и очень интересует именно работа с памятью, многопоточность, минималистичность и тому подобное.


Если сравнивать минималистичность самих языков, то тут безусловно лидирует C.
Если же сравнивать минималистичность кода, то C++ превосходит C. То есть сам код получается более лаконичный и быстрый (Это одна из основных фишек C++. Для многих это даже контринтуитивно, т.е. существует стереотип, что быстрый код должен быть dirty/hacky и super low-level, C++ как раз опровергает это).
Вот, например, что говорит Александр Степанов, создатель STL:

What do I mean when I say that an algorithm does not "impose any performance penalty"? In other words, how do you know that a generic algorithm is efficient? An algorithm is called relatively efficient if it's as efficient as a nongeneric version written in the same language, and it's called absolutely efficient if it's as efficient as a nongeneric assembly language version.

For many years, I tried to achieve relative efficiency in more advanced languages (e.g., Ada and Scheme) but failed. My generic versions of even simple algorithms were not able to compete with built-in primitives. But in C++ I was finally able to not only accomplish relative efficiency but come very close to the more ambitious goal of absolute efficiency. To verify this, I spent countless hours looking at the assembly code generated by different compilers on different architectures.

Re[3]: invalid fastbin entry (free):
От: Кодт Россия  
Дата: 18.04.14 22:12
Оценка:
Здравствуйте, Ovoshlook, Вы писали:

O>Огромное спасибо, хотя не совсем понятно почему нельзя использовать Realloc при выделении добавлении нового участка памяти к уже созданному массиву в динамике.


Можно, но с пониманием.
realloc не просто увеличивает память, но и перемещает её, соответственно, все указатели внутрь старого блока становятся невалидными.
Кстати говоря, твой исходный код содержит характерные ошибки, показывающие существенное непонимание работы с памятью и со строками в Си.
После паскаля (или бейсика?) надо обязательно переучиваться, там всё совсем по-другому.

Например,
j = strlen(arr->substrings[i]);
...
map.name = realloc(map.name, sizeof(char*)*j + 1);

По задумке, хотелось добавить к массиву name ещё немножко памяти под очередную строку.
По факту, старый размер забыт, а память выделена только под неё.

Надо было писать
size_t bufsize;
char* buffer;

size_t count;
size_t* offsets;
char** strings; /* неправильно */

.....
size_t len = strlen(s);

buffer = realloc(buffer, (size+len+1)*sizeof(char)); /* изменили буфер */
offsets = realloc(offsets, (count+1)*sizeof(size_t)); /* изменили массивы индексов */
strings = realloc(strings, (count+1)*sizeof(char*));

offsets[count] = size; /* запомнили начало новой строки - её позицию... */
strings[count] = buffer+size; /* и непосредственно указатель на неё */

strcpy(buffer+size, s); /* скопировали строку внутрь буфера - в хвост */

count++;
size += len+1;

.....
/* получаем i-ю строку */
char* t = buffer + offsets[i]; /* правильно */
char* e = strings[i]; /* неправильно */

В чём проблема: после realloc смещения останутся теми же самыми (их надо будет отсчитывать от начала нового буфера), а вот указатели в массиве strings — все, кроме последнего, будут направлены в потолок.

Но в одном посте это всё рассказывать — никаких сил не будет.
Так что — бери старых добрых Кернигана и Ричи, и читай.
Перекуём баги на фичи!
Re[4]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 19.04.14 17:22
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, Ovoshlook, Вы писали:


O>>Огромное спасибо, хотя не совсем понятно почему нельзя использовать Realloc при выделении добавлении нового участка памяти к уже созданному массиву в динамике.


К>Можно, но с пониманием.

К>realloc не просто увеличивает память, но и перемещает её, соответственно, все указатели внутрь старого блока становятся невалидными.
К>Кстати говоря, твой исходный код содержит характерные ошибки, показывающие существенное непонимание работы с памятью и со строками в Си.
К>После паскаля (или бейсика?) надо обязательно переучиваться, там всё совсем по-другому.

К>Например,

К>
К>j = strlen(arr->substrings[i]);
К>...
К>map.name = realloc(map.name, sizeof(char*)*j + 1);
К>

К>По задумке, хотелось добавить к массиву name ещё немножко памяти под очередную строку.
К>По факту, старый размер забыт, а память выделена только под неё.

К>Надо было писать

К>
К>size_t bufsize;
К>char* buffer;

К>size_t count;
К>size_t* offsets;
К>char** strings; /* неправильно */

К>.....
К>size_t len = strlen(s);

К>buffer = realloc(buffer, (size+len+1)*sizeof(char)); /* изменили буфер */
К>offsets = realloc(offsets, (count+1)*sizeof(size_t)); /* изменили массивы индексов */
К>strings = realloc(strings, (count+1)*sizeof(char*));

К>offsets[count] = size; /* запомнили начало новой строки - её позицию... */
К>strings[count] = buffer+size; /* и непосредственно указатель на неё */

К>strcpy(buffer+size, s); /* скопировали строку внутрь буфера - в хвост */

К>count++;
К>size += len+1;

К>.....
К>/* получаем i-ю строку */
К>char* t = buffer + offsets[i]; /* правильно */
К>char* e = strings[i]; /* неправильно */
К>

К>В чём проблема: после realloc смещения останутся теми же самыми (их надо будет отсчитывать от начала нового буфера), а вот указатели в массиве strings — все, кроме последнего, будут направлены в потолок.

К>Но в одном посте это всё рассказывать — никаких сил не будет.

К>Так что — бери старых добрых Кернигана и Ричи, и читай.

Спасибо за разжевывания. Теперь более понятно. Обязательно прочту
Re[18]: invalid fastbin entry (free):
От: Ovoshlook  
Дата: 19.04.14 17:30
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:



EP>Ок, но если не нужны копии — тогда для чего выделять буфер размером со строку?


Наверное просто можно скопировать адрес строки в новый массив и все..ю Действительно...

O>>Да, с С я недавно познакомился и очень интересует именно работа с памятью, многопоточность, минималистичность и тому подобное.


EP>Если сравнивать минималистичность самих языков, то тут безусловно лидирует C.

EP>Если же сравнивать минималистичность кода, то C++ превосходит C. То есть сам код получается более лаконичный и быстрый (Это одна из основных фишек C++. Для многих это даже контринтуитивно, т.е. существует стереотип, что быстрый код должен быть dirty/hacky и super low-level, C++ как раз опровергает это).

Ну помимо прочего, есть некое ПО написанное на С которое мне нужно бы расширить в будущем, поэтому и С. + Идеология классов меня не совсем устраивает, а если в С++ не использовать классы, то зачем использовать С++? (ну это как бы вопрос а не опровержение). Хотя конечно по поводу скорости (самого кода в итоге) — наверное это хороший аргумент в сторону С++, но как мне кажется хорошая программа на С не будет уступать С++ учитывая что С часто используют в программах, которые должны обрабатывать realtime потоки данных и подобные вещи. Но это уже риторика. Спасибо за подсказки и помощь. Буду делать и добиваться результата.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.