Несколько дней назад мне пришлось использовать C, и, работая с указателями, я немного удивился.
Пример в C:
#include <stdio.h>
#include <stdlib.h>
void GetPointer(int* p) {
p = malloc( sizeof(int) );
if(p) {
*p = 7;
printf("IN GetPointer: %d\n",*p);
} else {
printf("MALLOC FAILED IN GetPointer\n");
}
}
void GetPointer2(int* p) {
if(p) {
*p = 8;
printf("IN GetPointer2: %d\n",*p);
} else {
printf("INVALID PTR IN GetPointer2");
}
}
int* GetPointer3(void) {
int* p = malloc(sizeof(int));
if(p) {
*p = 9;
printf("IN GetPointer3: %d\n",*p);
} else {
printf("MALLOC FAILED IN GetPointer3\n");
}
return p;
}
int main(int argc, char** argv) {
(void) argc;
(void) argv;
int* ptr = 0;
GetPointer(ptr);
if(!ptr) {
printf("NOPE\n");
} else {
printf("NOW *PTR IS: %d\n",*ptr);
free(ptr);
}
int* ptr2 = malloc(sizeof(int));
GetPointer2(ptr2);
if(ptr2) {
printf("NOW *PTR2 IS: %d\n",*ptr2);
free(ptr2);
}
int* ptr3 = GetPointer3();
if(ptr3) {
printf("NOW *PTR3 IS: %d\n",*ptr3);
free(ptr3);
}
return 0;
}
Выход:
IN GetPointer: 7
NOPE
IN GetPointer2: 8
NOW *PTR2 IS: 8
IN GetPointer3: 9
NOW *PTR3 IS: 9
В этом примере первый указатель будет иметь только "значение" внутри метода GetPointer
. Почему использование malloc
inside длится только для времени жизни метода?
Я попробовал это в C++ и получил то же поведение. Я думал, что это сохранит свою ценность, но нет. Я нашел путь, хотя:
void GetPointer(int*& p) {
p = new int;
if(p) {
*p = 7;
printf("IN GetPointer: %d\n",*p);
} else {
printf("MALLOC FAILED IN GetPointer\n");
}
}
В CI не может сделать этот трюк. Есть ли способ сделать то же самое в C или мне нужно быть осторожным и "malloc" указатель, прежде чем пытаться дать ему значение?
Если вы хотите переназначить, на что указывает указатель на C, вы должны использовать int**
, то есть указатель на указатель.
Это связано с тем, что указатели копируются по значению в качестве аргументов, поэтому, если требуется, чтобы изменения, сделанные в указателе указателя, были видимыми вне области действия функции, вам нужен другой уровень косвенности.
это
void GetPointer(int* p) {
p = malloc( sizeof(int) );
if(p) {
*p = 7;
printf("IN GetPointer: %d\n",*p);
} else {
printf("MALLOC FAILED IN GetPointer\n");
}
}
ничего не делает от создания утечки памяти.
причина, по которой он ничего не делает, заключается в том, что вы передаете копию указателя на функцию (int * p), если вы хотите изменить то, что p указывает на то, что вам нужно передать адрес указателя.
void GetPointer(int** p)
void GetPointer(int** pp) {
int *p = malloc( sizeof(int) );
if(p) {
*p = 7;
printf("IN GetPointer: %d\n",*p);
} else {
printf("MALLOC FAILED IN GetPointer\n");
}
*pp = p;
}
p
является int *
.
Для первого вызова GetPointer вам нужно передать указатель на указатель на int. (в отличие от C++, который позволяет передавать ссылку с помощью оператора & в сигнатуре функции, C всегда передает вещи по значению, что означает, что ваш код передает копию ptr
в функцию GetPointer
.) Вам необходимо пройти адрес этого указателя (то есть местоположение в памяти, где хранится указатель ptr
так что код внутри метода GetPointer может помещать что-то в это место, тем самым модифицируя сам ptr
.
т.е. вызов должен быть:
GetPointer(&ptr);
и функции должны выглядеть так:
void GetPointer(int** p) {
*p = malloc( sizeof(int) );
if(*p) {
**p = 7;
printf("IN GetPointer: %d\n",**p);
} else {
printf("MALLOC FAILED IN GetPointer\n");
}
}
В void GetPointer(int* p)
вы теряете указатель, указывающий на динамическую память, как только вы выходите из функционального блока.
Попробуйте использовать указатель на подход указателя:
GetPointer(int ** p) {
*p = malloc( sizeof(int) );
if(*p) {
**p = 7;
printf("IN GetPointer: %d\n",**p);
} else {
printf("MALLOC FAILED IN GetPointer\n");
}
}
p = malloc( sizeof(int) );
malloc( sizeof(int));
вернет указатель, который затем будет присвоен p
. Но p
является локальным для GetPointer
, поскольку сам указатель передается по значению.
+----+
| |
xx +----+ malloc returns this block
+----+
| |
xx +----+ local variable p is assigned this block
+----+
| 7 |
xx +----+ p modifies value of this block
Функция заканчивается и, следовательно, p
оставляет позади утечку памяти
+----+
| 7 |
xx +----+ No one points to it anymore
Для GetPointer2
и GetPointer3
вы делаете malloc
,
+----+
| |
yy +----+ malloc returns some other block