Функции получают двоичную копию своих входов для локально ограниченных переменных. Таким образом, вспомогательная функция не может изменить значение, с которым она была вызвана, только ее локальная копия.
void f(int n)
{
n = 2;
}
int main()
{
int n = 1;
f(n);
return 0;
}
Несмотря на то же имя, n
в f
является локальным для вызова f
. Таким образом, n
в main
никогда не меняется.
Путь обойти это пройти мимо указателя:
int f(int *n)
{
*n = 2;
}
int main()
{
int n = 1;
f(&n);
// now we also see n == 2.
return 0;
}
Обратите внимание, что, опять-таки, n
в f
является локальным, так что если мы изменили указатель n
в f
, это не будет иметь никакого влияния на main
Перспектива. Если бы мы хотели изменить адрес n
в main
, нам пришлось бы передать адрес указателя.
void f1(int* nPtr)
{
nPtr = malloc(sizeof int);
*nPtr = 2;
}
void f2(int** nPtr)
{
// since nPtr is a pointer-to-a-pointer,
// we have to dereference it once to
// reach the "pointer-to-int"
// typeof nPtr = (int*)*
// typeof *nPtr = int*
*nPtr = malloc(sizeof int);
// deref once to get to int*, deref that for int
**nPtr = 2;
}
int main()
{
int *nPtr = NULL;
f1(nPtr); // passes 'NULL' to param 1 of f1.
// after the call, our 'nPtr' is still NULL
f2(&nPtr); // passes the *address* of our nPtr variable
// nPtr here should no-longer be null.
return 0;
}
---- EDIT: Что касается собственности распределений ----
Принадлежность указателей грязный может червей; стандартная библиотека C имеет функцию strdup
, которая возвращает указатель на копию строки. Программисту остается понять, что указатель выделяется malloc
и, как ожидается, будет выпущен диспетчеру памяти по вызову free
.
Этот подход становится более обременительным, поскольку указываемая вещь становится более сложной. Например, если вы получаете структуру каталогов, вы можете понять, что каждая запись является выделенным указателем, за который вы отвечаете за освобождение.
dir = getDirectory(dirName);
for (i = 0; i < numEntries; i++) {
printf("%d: %s\n", i, dir[i]->de_name);
free(dir[i]);
}
free(dir);
Если это была операция файл, который вы бы немного удивлены, если библиотека не обеспечивает close
функцию и сделали вас рушить дескриптор файла по своему усмотрению.
Многие современные библиотеки склонны брать на себя ответственность за свои ресурсы и обеспечивать соответствующие функции получения и освобождения, например. для открытия и закрытия соединения MySQL:
// allocate a MySQL descriptor and initialize it.
MYSQL* conn = mysql_init(NULL);
DoStuffWithDBConnection(conn);
// release everything.
mysql_close(conn);
LibEvent имеет, например,
bufferevent_new();
выделить буфер событий и
bufferevent_free();
, чтобы освободить его, несмотря на то, что она делает это немного больше, чем таНос() и свободный(), но при наличии у вас вызывать эти функции, они обеспечивают четко определенный и понятный API, который берет на себя ответственность за знание таких вещей.
Это является основой для концепции, известной как "RAII" в C++
О, так точно противоположно тому, что я делал. Думаю, я все время указывал на 'n', объявленный в основной функции, а не наоборот. Благодаря! Это все фиксировало. – user3290954
Я отредактировал ответ, чтобы включить объяснение от указателя к указателю, надеюсь, что это поможет. Что касается права собственности на указатели, это целая червь червей, и я добавлю редактирование, отвечая на эту часть вопроса. – kfsone