LINUX.ORG.RU

Помогите разобраться с malloc СИ

 ,


0

3

Здравствуйте.

Есть функция в которой есть две переменные для массивов - buff и trans_rate:

void rate_coin(char *coin)
 {
    FILE *rat_coi;
    char *buff = (char*) malloc(128 * sizeof(char));
    snprintf(buff, (int)strlen(coin) + 59, "%s%s%s", "curl https://api.coinmarketcap.com/v1/ticker/", coin, "/ 2>/dev/null"); 
    printf("Coinmarketcap: %s\n", buff);
    rat_coi = popen(buff, "r"); 
    if(rat_coi == NULL) error_log("rat_coi!");

    char trans_rate[128] = {0,};
    //char *trans_rate = (char*) malloc(128 * sizeof(char));
    int count = 0;
    strcat(trans_rate, "RATE COIN\n");
    memset(buff, 0, 128);
    while(fgets(buff, 126, rat_coi) != NULL)
     {
       count++;
       if(count > 8) break;
       if(count == 4 || count == 7 || count == 8)
        {
          char *pch = strtok(buff, " ,\"");
          while(pch != NULL)
           {
             char *ptr = strchr(pch, ':');
             if(ptr!=NULL) *ptr = ' ';
             strcat(trans_rate, pch);
             pch = strtok(NULL, " ,\"");
           }
        }
     }

    trans_rate[strlen(trans_rate) - 1] = 0;
    SendMessage(glob_chat_id, trans_rate);
    free(buff);
    printf("%s\n\n", trans_rate);
    //free(trans_rate);
 }

Для переменной buff делаю malloc, использую её в функции snprintf(buff, ...). После этого очищаю buff с помощью memset(buff,...), использую её же в функции while(fgets(buff,...) и в конце освобождаю память - free(buff);.

Для переменной trans_rate выделяю нужное кол-во байт и использую её.

Всё работает хорошо.

Если же для переменной trans_rate тоже делать malloc (строчка закомментирована) вместо char trans_rate[128] = {0,};, то прога начинает вести себя непредсказуемо, как будто перекрываются массивы (в printf попадают непонятные символы):

h�"�WRATE COIN

Объясните пожалуйста, почему в данном случае для buff malloc работает, а для trans_rate нет?


Ответ на: комментарий от vodz

Ну это ж не панацея. Выделили миллион по 16 байт, всё освободили, а потом запросили 64 байта... И обломаетесь.

Если выделили, а потом всё освободили, то никакой фрагментации и не будет. Будет свободная область на 1 000 000 * (16 + оверхед) байт.

Deleted
()
Ответ на: комментарий от Deleted

Если выделили, а потом всё освободили, то никакой фрагментации и не будет.

Не не. Это только если освобождать ровно в обратной последовательности к запросам на выделение. Если ровно с начала (а так ведь всегда легче), то будет ровно как сказал, будут блоки по 48 байт.

vodz ★★★★★
()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Выделено:

1 2 3 4 5 6 7 8 9
A A A A A A A A A

Освобождаем:

1 2 3 4 5 6 7 8 9
F A A A A A A A A
^
+-- 1 свободный  блок 


1 2 3 4 5 6 7 8 9
F F A A A A A A A
  ^
  +-- сливаем с предыдущим, снова получился 1 свободный блок

1 2 3 4 5 6 7 8 9
F F F A A A A A A
    ^
    +-- сливаем с предыдущим, снова получился 1 свободный блок

.
.
.

1 2 3 4 5 6 7 8 9
F F F F F F F F F

1 большой свободный блок

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от vodz

Ну да, Земля плоская, malloc - сискол. Уж не с последнего у вас тут подгорело? А?

Совсем балаболка сломалась? Ну дак сломанным место на помойке. Что тут тут делаешь?

Так закройте зеркало тряпочкой, выпейти успокоину и поспите. Делов то.

Вот ты мне ответь нормально. Почему тебе так сложно не нести ахению? Ведь это не сложно.

Хотя ладно, может я зря к тебе придираюсь - ты ведь рядовой и что с тебя взять. В любом случае у меня нет никаких претензий к тебе. У меня претензия одна, особенно после того случая. Ты не только сам нулёвый, дак ещё и отупляешь людей своими топ-ответами, которые тебе верят. Фу таким быть.

Хотя кто знает - может по вашим меркам ты и не нулёвый. Хрен его знает. В любом случае, не обижайся на меня.

rustonelove
()
Ответ на: комментарий от vodz

Будет выделена страница, которая и будет проинициализирована нулями, так как это BSS.Будет выделена страница, которая и будет проинициализирована нулями, так как это BSS.

Ну и что же произойдёт при первой записи в эту страницу, как в примере 3?

Sorcerer ★★★★★
()
Ответ на: комментарий от Deleted

А, я вспомнил, почему у меня так не получалось. Адрес «вперед» получить просто, размер блока то так и так известен, а назад уже сложнее.

vodz ★★★★★
()
Ответ на: комментарий от MKuznetsov

Обычное бла, бла, бла. До вызова free malloc будет выделять память через сисколы. Если ты сможешь сделать так, чтобы это как-то по-другому в защищенном режиме на ring-3, то я соглашусь с тобой что это обычная библиотечная функция, которая не является оберткой над сисколами.

xpahos ★★★★★
()
Ответ на: комментарий от Sorcerer

Ну и что же произойдёт при первой записи в эту страницу, как в примере 3?

С большой вероятностью ничего. При запуске startup код пропишет в эту страницу (скажем инициализирование stdio), система выделит её, в странице будет ваши 128 байт с большой вероятностью, потому когда дойдёт до main() то вы смело сможете туда писать без тормозов. Вы думаете для чего bss вообще придуман?

vodz ★★★★★
()
Ответ на: комментарий от xpahos

До вызова free malloc будет выделять память через сисколы

а вот и нет :-) malloc(), free() это библиотечные функции, и (например в libc) как и откуда они предоставляют память - целиком и полностью определяет программист.

MKuznetsov ★★★★★
()
Ответ на: комментарий от rustonelove

Совсем балаболка сломалась?

Что, умишка не хватает понять, что «мутекс - сискол» равносильно «malloc - сискол»? Причём даже круче, ибо malloc в конце-концов таки позовёт сискол, а вот работа с мутексами в однопоточнике — никогда? Я уж пытался не травмировать вашу психику, напоминая, что найти кучу функций без сисколов — как нефиг делать.

vodz ★★★★★
()
Ответ на: комментарий от xpahos

Обычное бла, бла, бла. До вызова free malloc будет выделять память через сисколы.

Так было до изобретения mmap anonymous. По историческим меркам это недавно, Линукс уже тогда существовал в виде 1.0 ядер. Но по меркам местных анонимуосов такого не бывает. Так что вот...

vodz ★★★★★
()
Ответ на: комментарий от vodz

Что, умишка не хватает понять, что «мутекс - сискол» равносильно «malloc - сискол»?

Вот смотри, убогий. Зачем ты пытаешься кудахтать мне что-то? Зачем несоизмеримо более примитивная форма жизни пытается поймать меня?

Давай я в очередной раз укажу тебе на твоё место. Было определенно то, что функция в конечном итоге так или иначе позовёт сискол. Ты высрал ferror() как пример функции, которая не позовёт. И обосрался.

Эта функция в конечном итоге, так или иначе его(сискол) позовёт. Ты обделался. Как всегда.

Я уж пытался не травмировать вашу психику, напоминая, что найти кучу функций без сисколов — как нефиг делать.

Ещё раз, балаболка. Тебе 25раз уже повторили. В данной ветке мы обсуждает то, как ты обделался. Никакие другие функции, никакие другие сисколы - тут не обсуждаются. И тебе это говорили. Хочешь побсуждать - выкатывай новую ветку.

Хотя там тебя ждёт тот же исход.

rustonelove
()
Ответ на: комментарий от MKuznetsov

(например в libc) как и откуда они предоставляют память - целиком и полностью определяет программист.

В glibc что-то не очень определяет, по-моему. Потребовалось мне однажды, чтобы оно только с помощью mmap память брало, в sbrk не лезло, так что-то не удалось настроить. Пришлось jemalloc использовать.

Sorcerer ★★★★★
()
Ответ на: комментарий от Sorcerer

man mallopt

man malloc_hook

легальный способ оперирование malloc, чтобы и своё что нужно вписать и предоставляемые libc фичи непохерить

то есть в самом прикладе нет необходимости переписывать что-то с malloc() на xxxMalloc() - только в одном месте (в каком-нить ините) настроить аллокатор под себя.

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Всё равно уже никто не помнит с чего всё началось, спрошу.

Скажите, как работает функция snprintf(buff, 25...) . Если буфер выделен 40, сама строка 10, а во втором аргументе написать 25.

Как в итоге поведёт себя функция - запишет 10 байт и занулит, после чего закончит работу, или следующие 15 байт (в аргументе ведь 25) тоже занулит?

stD
() автор топика
Ответ на: комментарий от stD

Я помню, как всё начиналось...

Я не читал весь этот флейм, поэтому первый вопрос.

char trans_rate[128] = {0,}; //Здесь ты обнуляешь первый байт, строка пустая.

char *trans_rate = (char*) malloc(128 * sizeof(char)); //Здесь ты не обнуляешь первый байт,
                                                       //в строке мусор, ноля в пределах буфера может не оказаться
                                                       //поэтому strcat пишет в случайную область памяти, а не туда, куда ты ожидаешь
//Надо добавить
*trans_rate = 0;
//или
trans_rate[0] = 0;
//или использовать calloc, которая заполняет выделенную память нулями

Второй вопрос. snprintf запишет столько байт, сколько ты указал в параметре функции, включая завершающий 0, но не более чем длина строки + этот 0. Если строка короче, всё что за ней не изменится, но это не важно. То есть, функции имеет смысл указывать длину буфера - 1, а в последний байт буфера записать 0, чтобы быть уверенным, что результирующая строка всегда закончится нулём.

И читай маны, там всё написано.

alexku
()
Ответ на: комментарий от MKuznetsov

malloc_hook - это про другое, а через mallopt это нормально не настроить.

Sorcerer ★★★★★
()
Ответ на: комментарий от stD

Как в итоге поведёт себя функция - запишет 10 байт и занулит, после чего закончит работу, или следующие 15 байт (в аргументе ведь 25) тоже занулит?

Не, ну хотя бы маны читать надо самостоятельно. man snprintf:

The functions snprintf() and  vsnprintf()  write  at  most  size  bytes
(including the terminating null byte ('\0')) to str.
Sorcerer ★★★★★
()
Ответ на: комментарий от alexku

char trans_rate[128] = {0,}; //Здесь ты обнуляешь первый байт

Опять эксперты в тред заехали со своими охренительными познаниями? Ну зато про маны потрепался и тут же обосрался - это прям сильно.

rustonelove
()
Ответ на: комментарий от Sorcerer

Ну так и в случае со стеком - ничего. С большой вероятностью.

Не совсем. Мы же сравниваем варианты и до мелочёвки докапываемся. Со стеком вам придётся обнулять, хорошо если только первый байт, а потом ещё и работать с этим указателем как смещение от указателя кадра стека или тратить регистр.

vodz ★★★★★
()
Ответ на: комментарий от Sorcerer

Не, ну хотя бы маны читать надо самостоятельно. man snprintf:

Между прочим с (v)snprintf бяда, если хотите портируемость с большими юниксами. Вот этот дурацкий код, когда даём snprintf некий «большой» буфер и фиг с ним, что результат обрежется пошло от того, что первоначально и в старых юниксах так и осталось snprintf возвращает не нужный объём для помещения всей строки, а -1. :(

vodz ★★★★★
()

Зачем кастовать результат malloc'а? Зачем говорить о calloc, не читая код glibc и не понимая, как он работает? Зачем полагаться на memset, который ничего не гарантирует? Зачем?..

Тред весь не читал, здоровья жалко.

post-factum ★★★★★
()
Ответ на: комментарий от alexku

char trans_rate[128] = {0,}; //Здесь ты обнуляешь первый байт, строка пустая.

Мне казалось, что запятая после нуля говорит компилятору занулить всё остальное?

snprintf запишет столько байт, сколько ты указал в параметре функции, включая завершающий 0, но не более чем длина строки + этот 0.

Вот про это я спрашивал, так как в мане (если я правильно перевёл) про это не сказано.

stD
() автор топика
Ответ на: комментарий от stD

Нет, конструкция char trans_rate[128] = {0}; сделает то же самое — массив из 128 нулей.

В мане все сказано, читай внимательней. Поэтому нет смысла писать

char buf[129];
snprintf(buf, 128, "...");

anonymous
()
Ответ на: комментарий от rustonelove

char trans_rate[128] = {0,}; //Здесь ты обнуляешь первый байт

Опять эксперты в тред заехали со своими охренительными познаниями? Ну зато про маны потрепался и тут же обосрался - это прям сильно.

Обосрался ты, тупое чучело.

#include <stdio.h>
 
int main(int argc, char *argv[])
{
        char arr[10] = {1,};
        int i;
        for(i = 0; i < 10; i++)
                printf("%d ", arr[i]);
        printf("\n");
}

gcc -o array_init array_init.c

./array_init
1 0 0 0 0 0 0 0 0 0 


alexku
()
Ответ на: комментарий от alexku

Обосрался ты, тупое чучело.

Раскукарекалась? И что ты мне показал?

Специально для клоунов поясню, раз ты даже не осилил понять того, в чём именно ты обосрался.

сhar trans_rate[128] = {0,}; //Здесь ты обнуляешь первый байт

Здесь он обнуляет ВСЕ байты. Инициализатор инициализирует всегда любой объект полностью. Инициализатор и есть идентичный объект.

1 0 0 0 0 0 0 0 0 0

Тебе, ламерку, даже это показали.

rustonelove
()
Ответ на: комментарий от stD

Мне казалось, что запятая после нуля говорит компилятору занулить всё остальное?

char trans_rate[128] = {0,} эквивалентно: char trans_rate[128] = (char[128]){0,};

Т.е. {} описывает полный «объект».

Поэтому да, ты прав, только это говорит не запятая. Это логика инициализации - любая инициализация полная.

rustonelove
()
17 января 2018 г.
Ответ на: комментарий от post-factum

Зачем полагаться на memset, который ничего не гарантирует?

А почему memset ничего не гарантирует? И на что полагаться?

stD
() автор топика
Ответ на: комментарий от post-factum

Спасибо, мира Вам и добра.

stD
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.