указателей действительно сложная вещь в С. Для многих людей трудно понять, так что для хорошего понимания я написал следующий код:Понимания указателей с таНос и свободными
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int *p; // pointer -> will be dynamic allocated
int *a; // array -> will be dynamic allocated
// print before allocate memory (1)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: %d\n", &a, a, *a);
printf("\n");
// allocate memory (2)
p = (int *)malloc(sizeof(int));
a = (int *)malloc(sizeof(int) * 10);
// print after allocate, but before give a value to poinetrs (3)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: %d\n", &a, a, *a);
printf("\n");
// give a value to poinetrs (4)
*p = 1;
for (int i = 0; i < 10; i++) { a[i] = i; }
// print after we gave a value to pointers (5)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: ", &a, a);
// because a is an array we must use a loop for print
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
printf("\n");
printf("\n");
// free pointers (6)
free(p);
free(a);
// print pointers after free (7)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: ", &a, a);
// because a is an array we must use a loop for print
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
printf("\n");
printf("\n");
// try to change values after free (8)
*p = 12;
for (int i = 0; i < 10; i++) { a[i] = 3; }
// print after (8)
printf("&p: %p\tp: %p\t*p: %d\n", &p, p, *p);
printf("&a: %p\ta: %p\t*a: ", &a, a);
// because a is an array we must use a loop for print
for (int i = 0; i < 10; i++) { printf("%d ", a[i]); }
printf("\n");
printf("\n");
return 0;
}
Выход:
&p: 0xbfe5db64 p: 0xbfe5dc24 *p: -1075452506
&a: 0xbfe5db68 a: 0xbfe5dc2c *a: -1075452502
&p: 0xbfe5db64 p: 0x8716008 *p: 0
&a: 0xbfe5db68 a: 0x8716018 *a: 0
&p: 0xbfe5db64 p: 0x8716008 *p: 1
&a: 0xbfe5db68 a: 0x8716018 *a: 0 1 2 3 4 5 6 7 8 9
&p: 0xbfe5db64 p: 0x8716008 *p: 0
&a: 0xbfe5db68 a: 0x8716018 *a: 0 1 2 3 4 5 6 7 8 9
&p: 0xbfe5db64 p: 0x8716008 *p: 12
&a: 0xbfe5db68 a: 0x8716018 *a: 3 3 3 3 3 3 3 3 3 3
Теперь, вопросы и замечания:
При печати указателей, прежде чем дать для него память, почему указатель имеет случайное значение и случайный адрес, чтобы указать на него и почему он не является NULL?
После использования malloc мы можем видеть адрес, в котором указатель указывает на изменение, и его значение равно NULL, так что же делает malloc?
После того, как мы придаем ему значение и печатаем его, мы освобождаем его и печатаем его снова, но значения и адрес такие же, как и для массива, но не для целого числа, почему? Так что же на самом деле бесплатно?
После освобождения места мы можем продолжать изменять значения массива и целого числа, почему это возможно после свободного пространства? Нам не нужно повторно использовать malloc?
«Указатели - действительно сложная штука в C». Сначала да. Но прочитайте хорошую книгу (K & R) и ** не ** продвигайтесь ни к чему другому, пока они не станут второй натурой. – Bathsheba
Прежде всего, [в C вы не должны бросать возврат 'malloc'] (http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc). И чтобы продолжить, вы используете [* undefined behavior *] (http://en.wikipedia.org/wiki/Undefined_behavior) в своем коде, так как используете неинициализированные переменные. Вам повезло, что программа не сработала при первом вызове 'printf'. –
Что касается неинициализированного поведения, неинициализированные нестатические локальные переменные имеют неопределенное значение (это будет казаться случайным), а использование неинициализированной нестатической локальной переменной приведет к [неопределенному поведению] (http://en.wikipedia.org/ вики/Undefined_behavior). –