вопрос по указателям c - PullRequest
       3

вопрос по указателям c

2 голосов
/ 21 января 2011

Это просто сомнение, которое пришло мне в голову

вот код, показанный ниже

          main()
          {
                  int *p,*q;
                  int a =20;
                  p = q;
                  p = &a;
                  free(p);
                  printf("The values of p and q are %d and %d\n",*p,*q);
           }

Я сомневаюсь, что если мы освободим указатель p, память, выделенная для этого указателя, будет освобождена и возвращена в свободный пул памяти, и поэтому в этом случае, поскольку q также указывает на p, разыменование q должно давать ошибку согласно мое понимание. Правильно ли я говорю об этом ?? Я запустил эту программу в компиляторе dev C ++, и, к моему удивлению, он показывает значения для обоих указателей. Мы называем указатель q как висячий указатель в этом случае?

большое спасибо заранее Мэдди

Ответы [ 7 ]

4 голосов
/ 21 января 2011

Попытка освободить p здесь вызывает неопределенное поведение - вам разрешено освобождать только то, что вы используете malloc (или calloc, или realloc, или strdup).В этом случае вы освобождаете указатель на переменную стека a, что недопустимо.

То же самое относится к разыменованию *q - значение в q неинициализировано,поэтому разыменование вызывает и неопределенное поведение.Строго говоря, p = q также не определено *, но на практике простое копирование значения неинициализированной переменной имеет тенденцию не вызывать слишком много проблем само по себе (просто не ожидайте, что значение будет значимым).

Когда вы вызываете неопределенное поведение, может произойти все, что угодно - это включает, но не ограничивается:

  • Сбой сразу
  • Сбой позжев некотором несвязанном коде
  • Повреждение некоторых данных без сбоев
  • Повреждение некоторых данных на диске, которые вы считаете безопасными
  • Обращение к серверу резервного копирования и повреждение также резервных копий
  • Разрешение хакеру, который активировал контроль за ошибками на вашем компьютере
  • Вызов демонов через носовые ходы
  • Любая комбинация вышеперечисленных
  • Иногда, вообще ничего.

Компилятор не требуется, чтобы выдавать какое-либо полезное сообщение об ошибке, хотя в некоторых случаях это может случаи.

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

* - для C99 6.2.6.1, если реализация C имеет представления ловушек для типов указателей, возможно, что неопределенное начальное значение для переменной является представлением ловушки, и в этот момент чтение его через q lvalue вызывает неопределенное поведение.

1 голос
/ 21 января 2011

Вы должны прочитать о указателях и понять их лучше. Совет

p = q

q - неинициализированный указатель, вы назначаете p для указания на ту же неопределенную зону памяти.

p = &a;

ЭтоХорошо, теперь p содержит адрес a, но q остается не инициализированным

free(p);

a хранится в стеке, а не в куче.Могли бы сделать это с:

int *a = malloc(sizeof(int)); // allocates memory and stores location
*a = 20;                      // modifies allocated memory
p = a;                        // have a second pointer to the same zone
free(p);                      // frees the allocated memory: now dereferencing either p or a is a sin.
1 голос
/ 21 января 2011

Как вы можете освободить память из стека?

Не вычисляет!

0 голосов
/ 21 января 2011

Это дает мне точное поведение, которое я ожидал при запуске через Valgrind:

==8839== Invalid free() / delete / delete[]
==8839==    at 0x4024836: free (vg_replace_malloc.c:325)
==8839==    by 0x8048440: main (boom.c:10)
==8839==  Address 0xbe9a5164 is on thread 1's stack

Я сделал это, потому что мне было любопытно, так как некоторые сообщали о том же поведении.

Адресp (как разыменовано free()) - это то, что известно как висячий указатель, поэтому любая операция над ним не определена.Я скомпилировал без оптимизации (-O0) и с отладочными символами (-g), чтобы получить лучшую иллюстрацию, но она взорвалась, несмотря ни на что.

При нормальной работе программы, как и ожидалось, просто возникает ошибка сегментации.Программа фактически завершается при профилировании в valgrind (дополнительные жалобы, когда printf() также разыменовывает взрывной указатель):

==8839== Use of uninitialised value of size 4
==8839==    at 0x8048445: main (boom.c:11)
==8839==
The values of p and q are 20 and 459916161
==8839==
==8839== HEAP SUMMARY:
==8839==     in use at exit: 0 bytes in 0 blocks
==8839==   total heap usage: 0 allocs, 1 frees, 0 bytes allocated

Но только потому, что Valgrind перехватывает SEGV.

Неопределенное поведение простоэто, неопределенное.Это одна из главных причин страшного «вау, работает на моей машине!»ошибка:)

0 голосов
/ 21 января 2011

Попытка free памяти, которая не была получена с malloc, calloc или realloc, приводит к НЕОПРЕДЕЛЕННЫМ РЕЗУЛЬТАТАМ. Иногда это делает что-то глупое, например, продолжать бежать и давать вам глупые результаты. Иногда он делает что-то более полезное:

$ ./a.out
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff8393bd5c ***
======= Backtrace: =========
/lib/libc.so.6(+0x774b6)[0x7f7a30bc04b6]
./a.out[0x400526]
/lib/libc.so.6(__libc_start_main+0xfe)[0x7f7a30b67d8e]
./a.out[0x400439]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:03 675233                             /tmp/a.out
00600000-00601000 r--p 00000000 08:03 675233                             /tmp/a.out
00601000-00602000 rw-p 00001000 08:03 675233                             /tmp/a.out
00f04000-00f25000 rw-p 00000000 00:00 0                                  [heap]
7f7a30933000-7f7a30948000 r-xp 00000000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30948000-7f7a30b47000 ---p 00015000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30b47000-7f7a30b48000 r--p 00014000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30b48000-7f7a30b49000 rw-p 00015000 08:03 228559                     /lib/libgcc_s.so.1
7f7a30b49000-7f7a30cc3000 r-xp 00000000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30cc3000-7f7a30ec2000 ---p 0017a000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30ec2000-7f7a30ec6000 r--p 00179000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30ec6000-7f7a30ec7000 rw-p 0017d000 08:03 228962                     /lib/libc-2.12.1.so
7f7a30ec7000-7f7a30ecc000 rw-p 00000000 00:00 0                      
7f7a30ecc000-7f7a30eec000 r-xp 00000000 08:03 228501                     /lib/ld-2.12.1.so
7f7a310cc000-7f7a310cf000 rw-p 00000000 00:00 0
7f7a310ea000-7f7a310ec000 rw-p 00000000 00:00 0                      
7f7a310ec000-7f7a310ed000 r--p 00020000 08:03 228501                     /lib/ld-2.12.1.so
7f7a310ed000-7f7a310ee000 rw-p 00021000 08:03 228501                     /lib/ld-2.12.1.so
7f7a310ee000-7f7a310ef000 rw-p 00000000 00:00 0                      
7fff8391d000-7fff8393e000 rw-p 00000000 00:00 0                          [stack]
7fff839df000-7fff839e0000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted

Моя библиотека C помогает мне получить адрес, который не удался, и очень помогает сбросить карту памяти (что является новым для меня!

0 голосов
/ 21 января 2011

a - это автоматическая переменная, и applyinf free (p), где p = & a - ошибка, с которой вы, вероятно, столкнетесь, как только вы выделите другую память, поскольку вы помечаете ее как свободную блочную память, которую нельзя использовать.

0 голосов
/ 21 января 2011

Вы пытаетесь вызвать free() для указателя на выделенную в стеке память, и это неопределенное поведение, никогда не делайте этого.Звоните free() только по указателям, полученным из malloc().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...