Область действия, массивы и куча - PullRequest
0 голосов
/ 10 июля 2009

Итак, у меня есть этот массив. К нему нужно получить доступ за пределами этой функции. Я ударил указатель на него в пару, которая помещается в deque. Но как только я выхожу из области видимости, локальный стек исчезает, массив становится недействительным, и у меня только что появился бесполезный указатель, верно?

Итак, я пытаюсь поместить этот массив в кучу, выходящую за рамки видимости, где он будет оставаться, пока я не удалю его позже. Но у меня проблемы с этим. Сейчас g ++ выкачивает ошибки о недопустимом преобразовании из int в int *.

void randomFunction(int x, int y, int width, int height)
{
  int **blah[4] = {x, y, width, height};
  std::pair <foobar*, int* > tempPair (foobar1, blah);
  randomDeque.push_front(tempPair);
}

Я также попытался инициализировать его так:

int *blah[4] = new int[4];

... и он говорит, что массив должен быть инициализирован инициализатором в скобках.

Я действительно не привык работать с указателями. Что я делаю не так?

Ответы [ 4 ]

2 голосов
/ 10 июля 2009

Есть две проблемы. Во-первых, действительно, вы запутались в указателях / массивах:

int a[4]; // this is an array of 4 integers, a is the name of the array
int *a[4]; // This is an array of 4 *pointers* to int

Итак, ваша декларация:

int **blah[4];

Определить массив из 4 указателей на массив указателей. Может быть, вы смущены следующим фактом (я знаю, что я был, когда я узнал C). Если вы объявите переменную:

int *a;

Это объявление указателя на целое число. Но если у вас есть переменная a, которая является указателем, вы получите то, на что она указывает (целое число здесь), используя * a:

*a = 1; // a is a pointer (i.e. an address), *a is the value pointed to by a.

То есть * в объявлении используется для объявления указателя, но * в выражениях используется для определения значения.

Но ваша вторая проблема не имеет ничего общего с указателем. Речь идет об управлении ресурсами (память одна, но файл, блокировки - другие). Все, что размещено в стеке, больше не существует, когда оно находится вне области видимости. В чистом C у вас действительно есть только одно решение: выделение в куче с помощью malloc и последующее освобождение. Так что вы бы сделали что-то вроде:

// foo is a struct
foo *init_foo()
{
    foo* tmp;
    tmp = malloc(sizeof(*tmp));
    // initialize tmp

    return tmp;
}

И тогда вы очистите его с помощью другой функции:

foo *a;
a = init_foo();
// do stuff
clean_foo(a);

Пример: дескриптор FILE * и fopen / fclose (помимо выделения вещей, есть некоторые вещи, связанные с ОС для обработки файла). Другое решение заключается в использовании alloca, который не является стандартным C, но поддерживается многими инструментальными цепочками.

В C ++ вы можете использовать умные указатели, которые используют, например, подсчет ссылок для управления ресурсами. Я менее знаком с C ++, и я уверен, что люди будут участвовать в этой части. Идея с подсчетом ссылок заключается в том, что он по-прежнему дает некоторые преимущества автоматических указателей (вам не нужно вызывать delete самостоятельно, что чрезвычайно подвержено ошибкам для нетривиальных проектов), но при этом он не основан исключительно на области. Один интеллектуальный указатель на основе подсчета ссылок - shared_ptr в boost.

1 голос
/ 10 июля 2009

Я не уверен, правильно ли я понял, что вы хотите сделать, но если вы хотите вернуть ссылку на массив int, который будет действителен после возврата randomFunction, хороший способ сделать это с помощью Boost :

#include <boost/shared_ptr.hpp>
#include <vector>

boost::shared_ptr<std::vector<int> > randomFunction(int x, int y, int width, int height)
{
  boost::shared_ptr<std::vector<int> > blahPtr(new std::vector<int>(4));
  (*blahPtr)[0] = x;
  (*blahPtr)[1] = y;
  (*blahPtr)[2] = width;
  (*blahPtr)[3] = height;
  return blahPtr;
}

Вам не нужно помнить о delete ing blahPtr - когда все его копии выйдут из области видимости, Boost автоматически удалит ваш объект std::vector, а стандартная библиотека C ++ удалит базовый массив.

1 голос
/ 10 июля 2009

Вся концепция выглядит странно для меня. Если вы объявите массив в стеке, он не будет существовать вне области вашей функции. Если вы выделяете его с помощью «new» - убедитесь, что вы «удалите» его как-нибудь, иначе это утечка памяти ! Правильный код с «новым»:

int *blah = new int[4];
...
// don't forget to:
delete [] blah;
0 голосов
/ 10 июля 2009

Похоже, вы хотите массив 4x4, и в этом случае вы должны создать его следующим образом (непроверенный код из головы):

int **blah = new int* [4];
for(int i = 0; i < 4; ++i)
{
    *blah[i] = new int[4];
}

В качестве альтернативы вы можете создать одномерный массив и рассматривать его как двумерный массив:

int *blah = new int[16];
#define ELEM(x,y) w*4+h
blah[ELEM(1,1)] = 123;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...