glibc виявлено: подвійний вільний або корупційний

Я поясню коротких кроків кодування, які я зробив, і області, де я стикаюся з проблемою

main.cpp

int main()
{
    int cnt_map,i=1,value;

   /* My question is about this char pointer "key" */ 
    char *key =(char*)malloc(sizeof(char) * 25);

   if(key!=NULL)
   {
     printf("Key value is not NULL,its value is:%x\n",key) ;
     cout<< "Enter the number of elements required in container map"<> cnt_map;
     for (i=1;i<=cnt_map;i++)
     {
       cout << "Enter the key : ";
       cin >>key;
       cout << "Enter the key value:" ;
       cin >>value;
       printf("value pointed by ptr key: %s, value in ptr: %x\n", key,key);
       c -> add_map1(key,value); //Function inserts value to map container
       key+=sizeof(key);
     }
     c -> size_map1();           //Function displays size of map container
     c -> display_map1();        //Function displays contents of map container
  if(key)
  {
    printf("FINALLY:value pointed by ptr key: %s, value in ptr: %x,size:%d\n",key, key, sizeof(key));
    free(key);
  } 
 }
return 0;
}

при спробі компіляції і запуску вищевказаного коду, я в змозі успішно компілювати код, але отримав "glibc виявлено: подвійний вільний або корупції" при спробі запуску програми.

Тепер моє питання полягає в тому, що я створив індикатор char ( char * key = (char *) malloc (sizeof (char) * 25); ) і успішно присвоєно їй пам'ять за допомогою malloc. Після завершення мого процесу, коли я спробував звільнити цей char покажчик я отримую двічі вільні або корупційні помилки. Я дізнався, що будь-яка змінена пам'ять з malloc/calloc повинна бути остаточно звільнена. Будь ласка, скажіть, чому я отримую помилку, чому я не повинен це робити? Будь ласка, скажіть мені, як операції з пам'яттю виконуються на char * key (якщо можливо, зображено).

Note: The code presented above is not the complete code, I just explained where I am getting the problem and if I am not freeing the pointer variable, my application is running successfully.

Будь-яка допомога дуже вдячна. Велике спасибі заздалегідь.

4
@ H2CO3 Чи не вимагає C + + відправлення? Звичайно, код C ++ повинен використовувати new , а не malloc .
додано Автор Barmar, джерело
@ H2CO3 Чи не вимагає C + + відправлення? Звичайно, код C ++ повинен використовувати new , а не malloc .
додано Автор Barmar, джерело
@ H2CO3 Чи не вимагає C + + відправлення? Звичайно, код C ++ повинен використовувати new , а не malloc .
додано Автор Barmar, джерело
@JimBalter Тег говорить c ++ .
додано Автор Barmar, джерело
@JimBalter Тег говорить c ++ .
додано Автор Barmar, джерело
Ваш код говорить key1 , а не ключ - це лише помилка?
додано Автор RichieHindle, джерело
@JimBalter: Так, він просто має пару рядків C ++, що посипаються в нього. :-)
додано Автор RichieHindle, джерело
@JimBalter: Так, він просто має пару рядків C ++, що посипаються в нього. :-)
додано Автор RichieHindle, джерело
Це не C код.
додано Автор Jim Balter, джерело
Це не C код.
додано Автор Jim Balter, джерело
@BarMar Змінено на C; Я повернув його назад.
додано Автор Jim Balter, джерело
@BarMar Змінено на C; Я повернув його назад.
додано Автор Jim Balter, джерело
@BarMar Змінено на C; Я повернув його назад.
додано Автор Jim Balter, джерело
Ви завжди можете використовувати valgrind для налагодження всіх цих помилок пам'яті. Вона втрачає дуже мало і висновок читається.
додано Автор cgledezma, джерело
Ви завжди можете використовувати valgrind для налагодження всіх цих помилок пам'яті. Вона втрачає дуже мало і висновок читається.
додано Автор cgledezma, джерело
Ви завжди можете використовувати valgrind для налагодження всіх цих помилок пам'яті. Вона втрачає дуже мало і висновок читається.
додано Автор cgledezma, джерело
char * key = (char *) malloc (sizeof (char) * 25); -> char * key = malloc (25);
додано Автор user529758, джерело
char * key = (char *) malloc (sizeof (char) * 25); -> char * key = malloc (25);
додано Автор user529758, джерело
@Barmar C ++ вимагає цього, звичайно (на жаль).
додано Автор user529758, джерело
@Barmar C ++ вимагає цього, звичайно (на жаль).
додано Автор user529758, джерело
@Barmar C ++ вимагає цього, звичайно (на жаль).
додано Автор user529758, джерело

7 Відповіді

Роблячи це:

key+=sizeof(key);

змінна key більше не вказує на початок виділеної пам'яті. Потрібно передати оригінальний вказівник на free() . Потрібно зберегти оригінальний вказівник в іншій змінній так, щоб ви могли правильно free() в кінці.

(Ви можете просто вилучити цей рядок - я не впевнений, що він робить, враховуючи, що sizeof (ключ) є або 4, або 8.

7
додано
Здається, не існує жодних причин для того, щоб збільшити key в першу чергу.
додано Автор Barmar, джерело
Якщо add_map1 не створює копію ключа, вам потрібно викликати malloc() кожен раз через цикл, і ви не повинні викликати free() , оскільки карта все ще посилається на рядок. Але це дійсно повинно зробити копію, саме щоб уникнути цієї проблеми, а також так, щоб автоматичні рядки могли бути використані як ключі.
додано Автор Barmar, джерело
@ybc: Я не можу придумати випадок, коли неможливість викликати free призведе до помилки коду, окрім втрати пам'яті. Але це дуже погана практика, і ніхто не рекомендував би це. (У вашому прикладі можна просто скористатися звичайним старим масивом, char ключем [25]; , у цьому випадку не потрібно взагалі викликати free , просто як ви не називаєте free для cnt_map або i .
додано Автор RichieHindle, джерело
@ybc: При кожному виклику до malloc ви виділите один блок пам'яті. Незалежно від того, як ви використовуєте цю пам'ять, вам знадобиться лише один відповідний виклик для free . Ваша програма працює, тому що немає абсолютної необхідності для звільнення пам'яті - у вашому випадку, пам'ять повертається в операційну систему, коли процес помирає. Але якщо ви запускали цей код у циклі, мільйони разів, ваш процес зрештою закінчиться пам'яттю.
додано Автор RichieHindle, джерело
@ybc: Напевно add_map1 бере копію вмісту ключа ? Якщо це не так, то треба! (До речі, я вважаю, що ми тут відхиляємося, StackOverflow не є дискусійним форумом.)
додано Автор RichieHindle, джерело
Тоді як щодо всіх виділених місць пам'яті з цією клавішею + = sizeof (ключ); . Як звільнити всі локації? що станеться, якщо ми не звільнимо ці місця? чому моя програма успішно виконується, коли я не користуюся безкоштовним ()?
додано Автор ybc, джерело
Дякую всім!!
додано Автор ybc, джерело
Це те, що відбувається .. коли я повторно запустити додаток, я знайшов пам'ять почала виділяти в тому ж попередньому locations.Thanks для великого analysis.Anyway я вимагаю дуже менше ітерацій в моєму випадку, але, ще одне питання У якій саме ситуації нам потрібно звільнити присвоєну пам'ять ... думаю, протилежність наданому вами поясненню (якщо це можливо, випадок використання).
додано Автор ybc, джерело
якщо я роблю це кожен раз, коли я роблю cin >> ключ , розташування пам'яті масиву char перекривається новим входом і не вставляється правильно в карту контейнера ... і це причина Я розглядав збільшення місць покажчика себе.
додано Автор ybc, джерело

Роблячи це:

key+=sizeof(key);

змінна key більше не вказує на початок виділеної пам'яті. Потрібно передати оригінальний вказівник на free() . Потрібно зберегти оригінальний вказівник в іншій змінній так, щоб ви могли правильно free() в кінці.

(Ви можете просто вилучити цей рядок - я не впевнений, що він робить, враховуючи, що sizeof (ключ) є або 4, або 8.

7
додано
Якщо add_map1 не створює копію ключа, вам потрібно викликати malloc() кожен раз через цикл, і ви не повинні викликати free() , оскільки карта все ще посилається на рядок. Але це дійсно повинно зробити копію, саме щоб уникнути цієї проблеми, а також так, щоб автоматичні рядки могли бути використані як ключі.
додано Автор Barmar, джерело
Здається, не існує жодних причин для того, щоб збільшити key в першу чергу.
додано Автор Barmar, джерело
@ybc: При кожному виклику до malloc ви виділите один блок пам'яті. Незалежно від того, як ви використовуєте цю пам'ять, вам знадобиться лише один відповідний виклик для free . Ваша програма працює, тому що немає абсолютної необхідності для звільнення пам'яті - у вашому випадку, пам'ять повертається в операційну систему, коли процес помирає. Але якщо ви запускали цей код у циклі, мільйони разів, ваш процес зрештою закінчиться пам'яттю.
додано Автор RichieHindle, джерело
@ybc: Я не можу придумати випадок, коли неможливість викликати free призведе до помилки коду, окрім втрати пам'яті. Але це дуже погана практика, і ніхто не рекомендував би це. (У вашому прикладі можна просто скористатися звичайним старим масивом, char ключем [25]; , у цьому випадку не потрібно взагалі викликати free , просто як ви не називаєте free для cnt_map або i .
додано Автор RichieHindle, джерело
@ybc: Напевно add_map1 бере копію вмісту ключа ? Якщо це не так, то треба! (До речі, я вважаю, що ми тут відхиляємося, StackOverflow не є дискусійним форумом.)
додано Автор RichieHindle, джерело
Тоді як щодо всіх виділених місць пам'яті з цією клавішею + = sizeof (ключ); . Як звільнити всі локації? що станеться, якщо ми не звільнимо ці місця? чому моя програма успішно виконується, коли я не користуюся безкоштовним ()?
додано Автор ybc, джерело
Дякую всім!!
додано Автор ybc, джерело
Це те, що відбувається .. коли я повторно запустити додаток, я знайшов пам'ять почала виділяти в тому ж попередньому locations.Thanks для великого analysis.Anyway я вимагаю дуже менше ітерацій в моєму випадку, але, ще одне питання У якій саме ситуації нам потрібно звільнити присвоєну пам'ять ... думаю, протилежність наданому вами поясненню (якщо це можливо, випадок використання).
додано Автор ybc, джерело
якщо я роблю це кожен раз, коли я роблю cin >> ключ , розташування пам'яті масиву char перекривається новим входом і не вставляється правильно в карту контейнера ... і це причина Я розглядав збільшення місць покажчика себе.
додано Автор ybc, джерело

Роблячи це:

key+=sizeof(key);

змінна key більше не вказує на початок виділеної пам'яті. Потрібно передати оригінальний вказівник на free() . Потрібно зберегти оригінальний вказівник в іншій змінній так, щоб ви могли правильно free() в кінці.

(Ви можете просто вилучити цей рядок - я не впевнений, що він робить, враховуючи, що sizeof (ключ) є або 4, або 8.

7
додано
Здається, не існує жодних причин для того, щоб збільшити key в першу чергу.
додано Автор Barmar, джерело
Якщо add_map1 не створює копію ключа, вам потрібно викликати malloc() кожен раз через цикл, і ви не повинні викликати free() , оскільки карта все ще посилається на рядок. Але це дійсно повинно зробити копію, саме щоб уникнути цієї проблеми, а також так, щоб автоматичні рядки могли бути використані як ключі.
додано Автор Barmar, джерело
@ybc: Напевно add_map1 бере копію вмісту ключа ? Якщо це не так, то треба! (До речі, я вважаю, що ми тут відхиляємося, StackOverflow не є дискусійним форумом.)
додано Автор RichieHindle, джерело
@ybc: При кожному виклику до malloc ви виділите один блок пам'яті. Незалежно від того, як ви використовуєте цю пам'ять, вам знадобиться лише один відповідний виклик для free . Ваша програма працює, тому що немає абсолютної необхідності для звільнення пам'яті - у вашому випадку, пам'ять повертається в операційну систему, коли процес помирає. Але якщо ви запускали цей код у циклі, мільйони разів, ваш процес зрештою закінчиться пам'яттю.
додано Автор RichieHindle, джерело
@ybc: Я не можу придумати випадок, коли неможливість викликати free призведе до помилки коду, окрім втрати пам'яті. Але це дуже погана практика, і ніхто не рекомендував би це. (У вашому прикладі можна просто скористатися звичайним старим масивом, char ключем [25]; , у цьому випадку не потрібно взагалі викликати free , просто як ви не називаєте free для cnt_map або i .
додано Автор RichieHindle, джерело
якщо я роблю це кожен раз, коли я роблю cin >> ключ , розташування пам'яті масиву char перекривається новим входом і не вставляється правильно в карту контейнера ... і це причина Я розглядав збільшення місць покажчика себе.
додано Автор ybc, джерело
Дякую всім!!
додано Автор ybc, джерело
Тоді як щодо всіх виділених місць пам'яті з цією клавішею + = sizeof (ключ); . Як звільнити всі локації? що станеться, якщо ми не звільнимо ці місця? чому моя програма успішно виконується, коли я не користуюся безкоштовним ()?
додано Автор ybc, джерело
Це те, що відбувається .. коли я повторно запустити додаток, я знайшов пам'ять почала виділяти в тому ж попередньому locations.Thanks для великого analysis.Anyway я вимагаю дуже менше ітерацій в моєму випадку, але, ще одне питання У якій саме ситуації нам потрібно звільнити присвоєну пам'ять ... думаю, протилежність наданому вами поясненню (якщо це можливо, випадок використання).
додано Автор ybc, джерело

Це пов'язано з цим рядком: key + = sizeof (key); . key не містить ту саму адресу, що й адреса malloc .

Наприклад:

char * key = (char *) malloc (sizeof (char) * 25);

Припустимо, що malloc повертає адресу 20000 (повністю безглуздий адреса, це тільки для прикладу).

Тепер ви робите ключ + = sizeof (ключ); , тому ключ = 20000 + 4 = 20004. Проблема полягає в тому, що ви намагаєтеся звільнити ключ , який вказує на адреса 20004 замість 20000.

Щоб виправити це, спробуйте:

int main()
{
    int cnt_map,i=1,value;
    char *key_save;

   /* My question is about this char pointer "key" */ 
    char *key =(char*)malloc(sizeof(char) * 25);

    key_save = key;
   if(key!=NULL)
   {
     printf("Key value is not NULL,its value is:%x\n",key) ;
     cout<< "Enter the number of elements required in container map"<> cnt_map;
     for (i=1;i<=cnt_map;i++)
     {
       cout << "Enter the key : ";
       cin >>key;
       cout << "Enter the key value:" ;
       cin >>value;
       printf("value pointed by ptr key: %s, value in ptr: %x\n", key,key);
       c -> add_map1(key,value); //Function inserts value to map container
       key+=sizeof(key);
     }
     c -> size_map1();           //Function displays size of map container
     c -> display_map1();        //Function displays contents of map container
  if(key)
  {
    printf("FINALLY:value pointed by ptr key: %s, value in ptr: %x,size:%d\n",key, key, sizeof(key));
    free(key_save);
  } 
 }
return 0;
}
5
додано
"Виправити" неправильно, тому що приріст ключа неправильний ... див. Іншу відповідь і коментарі тут.
додано Автор Jim Balter, джерело
Якщо ви вільний (ключ) (з хорошою адресою), весь простір пам'яті, виділений key , буде звільнено (включаючи байти на адресу "20004", так)
додано Автор nouney, джерело
@JimBalter Це не моя проблема. Питання: Чому існує пошкодження пам'яті? , я просто відповідаю на це питання, я не тут, щоб переглянути весь код.
додано Автор nouney, джерело
Тоді що буде з ключовою адресою (вашою справою 20004) і її вмістом, який також створений з тієї ж програми? ми дійсно потребуємо звільнити їх теж? Будь ласка, допоможіть мені зрозуміти!
додано Автор ybc, джерело
Чудово! Велике вам спасибі за пояснення, і ви маєте рацію, я також стурбований чому існує пошкодження пам'яті? @Jim Тісто * "Виправити" неправильно, тому що збільшення ключа неправильно ... іншу відповідь і коментарі тут. * Що ви мали на увазі, нарешті? Дякую
додано Автор ybc, джерело

Це пов'язано з цим рядком: key + = sizeof (key); . key не містить ту саму адресу, що й адреса malloc .

Наприклад:

char * key = (char *) malloc (sizeof (char) * 25);

Припустимо, що malloc повертає адресу 20000 (повністю безглуздий адреса, це тільки для прикладу).

Тепер ви робите ключ + = sizeof (ключ); , тому ключ = 20000 + 4 = 20004. Проблема полягає в тому, що ви намагаєтеся звільнити ключ , який вказує на адреса 20004 замість 20000.

Щоб виправити це, спробуйте:

int main()
{
    int cnt_map,i=1,value;
    char *key_save;

   /* My question is about this char pointer "key" */ 
    char *key =(char*)malloc(sizeof(char) * 25);

    key_save = key;
   if(key!=NULL)
   {
     printf("Key value is not NULL,its value is:%x\n",key) ;
     cout<< "Enter the number of elements required in container map"<> cnt_map;
     for (i=1;i<=cnt_map;i++)
     {
       cout << "Enter the key : ";
       cin >>key;
       cout << "Enter the key value:" ;
       cin >>value;
       printf("value pointed by ptr key: %s, value in ptr: %x\n", key,key);
       c -> add_map1(key,value); //Function inserts value to map container
       key+=sizeof(key);
     }
     c -> size_map1();           //Function displays size of map container
     c -> display_map1();        //Function displays contents of map container
  if(key)
  {
    printf("FINALLY:value pointed by ptr key: %s, value in ptr: %x,size:%d\n",key, key, sizeof(key));
    free(key_save);
  } 
 }
return 0;
}
5
додано
"Виправити" неправильно, тому що приріст ключа неправильний ... див. Іншу відповідь і коментарі тут.
додано Автор Jim Balter, джерело
Якщо ви вільний (ключ) (з хорошою адресою), весь простір пам'яті, виділений key , буде звільнено (включаючи байти на адресу "20004", так)
додано Автор nouney, джерело
@JimBalter Це не моя проблема. Питання: Чому існує пошкодження пам'яті? , я просто відповідаю на це питання, я не тут, щоб переглянути весь код.
додано Автор nouney, джерело
Чудово! Велике вам спасибі за пояснення, і ви маєте рацію, я також стурбований чому існує пошкодження пам'яті? @Jim Тісто * "Виправити" неправильно, тому що збільшення ключа неправильно ... іншу відповідь і коментарі тут. * Що ви мали на увазі, нарешті? Дякую
додано Автор ybc, джерело
Тоді що буде з ключовою адресою (вашою справою 20004) і її вмістом, який також створений з тієї ж програми? ми дійсно потребуємо звільнити їх теж? Будь ласка, допоможіть мені зрозуміти!
додано Автор ybc, джерело

Просто видаліть рядок:

key+=sizeof(key);

key is not a pointer to an array of strings, it's a pointer to a single string. Every time you increment this, you're reducing the available space in the string. The first time you read a key, there's 25 bytes available. The next time, you've incremented key by 4 or 8 bytes, but the end of the allocated space hasn't changed, so now there's only 21 or 17 bytes available. The third time it's only 17 or 9 bytes, and so on. After a few iterations, you'll increment key past the end of the memory block that you allocated, and it will start writing into unallocated memory (or memory that's assigned to other data structures). This is undefined behavior, and will most likely cause unpredictable failures in your program.

Оскільки ви використовуєте C ++, ви повинні використовувати std :: string замість char [] для рядків, а std :: vector замість звичайні масиви. Ці структури даних автоматично розширюються в міру необхідності, так що ви уникнете переповнення буфера, як це.

1
додано
Велике пояснення ...
додано Автор ybc, джерело

це не враховує ваш код, але у мене виникла одна й та ж проблема в проблемі письменника Reader (операційні системи) "nofollow"> http://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem .

Це було пов'язано з тим, що покажчик файлу був глобальним, так що всякий читач намагався читати, а в b/w інший читав читає і закриває покажчик файлу, коли інший читач, який ще не прочитав, спробував закрити файл покажчика після читання. так що те, що сталося, вже був закритий файловим покажчиком, це не вказувало на будь-який файл. Використовується розчин i. Замість того, щоб оголошувати файл покажчиком global, я оголосив його локальною функцією reader, що він або ж ви можете перевірити покажчик файлу на NULL і якщо NULL тоді не закриєте файл покажчика.

#include
#include
#include
#include
#include
sem_t x,wsem;
int rc=0;
char ch;
char str[20];
void *reader(void *);
void *writer(void *);


int main()
{
 int nw,nr,i=0,j=0;
 pthread_t w[10],r[10];
 sem_init(&x,0,1);
 sem_init(&wsem,0,1);
 rc=0;
 printf("Enter the no of readers:");
 scanf("%d",&nr);
 printf("Enter the no of writers");
 scanf("%d",&nw);
 while(i
0
додано
IT KPI C/С++ новым годом
IT KPI C/С++ новым годом
747 учасників

Чат обсуждения С/С++. - Вопросы "напишите за меня лабу" - это оффтоп. - Оффтоп, флуд, оскорбления и вбросы здесь не приняты. - За нарушение - предупреждение или mute на неделю. - За спам и рекламу - ban. Все чаты IT KPI: https://t.me/itkpi/1147