Указатели и динамическая память на C и C ++

0

Несколько дней назад мне пришлось использовать 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" указатель, прежде чем пытаться дать ему значение?

  • 2
    указатель на указатель.
  • 1
    Вам нужно передать int ** p, если вы хотите вернуть адрес выделенной памяти.
Показать ещё 6 комментариев
Теги:
pointers
dynamic-memory-allocation

6 ответов

6
Лучший ответ

Если вы хотите переназначить, на что указывает указатель на C, вы должны использовать int**, то есть указатель на указатель.

Это связано с тем, что указатели копируются по значению в качестве аргументов, поэтому, если требуется, чтобы изменения, сделанные в указателе указателя, были видимыми вне области действия функции, вам нужен другой уровень косвенности.

  • 3
    Или верните новый указатель из функции. Я бы предпочел сделать это.
2

это

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)
1
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;
}
  • 0
    ошибка в * p = 7 здесь
  • 0
    @ nikpel7 Нет, это действительно. p является int * .
Показать ещё 1 комментарий
1

Для первого вызова 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");
  }
}
1

В 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");
  }
}
1
  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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню