Использование структуры с двойным указателем и ее памятью - PullRequest
2 голосов
/ 27 июля 2011

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

struct item {
    int val;
    int *vectOfInt;
    struct item *next;
};

void relItem(struct item **currItem) {
    struct item *temp;
    int *intTemp;

    temp = *currItem;
    intTemp = (*currItem)->vectOfInt;
    *currItem = (*currItem)->next;
    free(temp);
    free(intTemp);
}

int main() {
    int array[] = {0, 1, 2, 3, 4, 5};
    struct item *list = NULL;

    list = (struct item*) malloc(sizeof(struct item));
    list->val = 0;
    list->vectOfInt = array;
    list->next = NULL;

    relItem(&list);

    return 0;
}

РЕДАКТИРОВАТЬ: код для комментария:

struct item {
    int val;
    struct item *next;
};

void edit(struct item *currItem) {
    currItem->val = 2;
}

int main() {
    struct item *list = NULL;
    list = (struct item*) malloc(sizeof(struct item));
    list->val = 0;
    list->next = NULL;

    edit(list);

    //list-val == 2

    return 0;
}
  • Как я могу сделать то же самое, не используя двойной указатель на структуру?

  • Можете ли вы объяснить, почему и как это работает (обас указателем и двойным указателем)?

  • Я не понимаю, как структура представлена ​​в основной памяти (например, int a[5]; в памяти a указатель напервое расположение буфера, выделенного для массива a[5])

каково равное представление для инициализированной структуры с указателем (struct item *s)?

Ответы [ 5 ]

2 голосов
/ 27 июля 2011

-Вы должны использовать двойной указатель, так как вам нужно изменить указатель на вашу структуру, и вызов по ссылке не разрешен в C.

-Это не будет работать с одним указателем.Потому что вы хотите изменить указатель на ваш объект.Вы делаете это с помощью оператора *currItem = (*currItem)->next; Чтобы изменить его навсегда, вам нужно использовать указатель на него.Что заставляет вас использовать двойной указатель.

Подумайте об этом так:

у вас есть целочисленная переменная a, которую вы хотите, чтобы функция изменила свое значение.Вы просто вызываете эту функцию с указателем на переменную a, например:

void changeTheValue(int *x)
{
    *x = 7;
}
void main()
{
   int a = 5;
   changeTheValue(&a);
}

, и в вашем случае вы хотите изменить значение указателя и просто передать его указатель наФункция. (двойной указатель) просто так. Если вы хотите изменить значение чего-либо с помощью функции, вам нужно передать указатель на функцию.

- Когда вы вызываете malloc, вам нужен пробел из него.И вы заявляете, что вы хотите пространство размером с размер вашей структуры.(Например, когда вы это сделали здесь list = (struct item*) malloc(sizeof(struct item));), и malloc выделяет пространство размером с вашу структуру.Если размер вашей структуры составляет 1 байт, то у вас есть 1-байтовое пространство, если это 4, то у вас есть последовательные 4 байта.Видите, это то, как ваша структура хранится в памяти.Если вы объявляете переменную структуры или массив и т. Д., То ваша структура сохраняется в памяти, как (не знаю, хорошая ли это метафора) как массив.Сначала идет первый член, а затем второй ...

скажем, если у вас есть структура

struct myStruct
{
    int a;
    float b;
    char c;
};

, то память выглядит как


a


b


c

ps: вы делаете недопустимый вызов free на линии free(intTemp); вы * освобождаете * переменную, котораяВы не * Malloc * Ed.

2 голосов
/ 27 июля 2011
Как я могу сделать то же самое, не используя двойной указатель на структуру?

Вы должны использовать двойной указатель.

Не могли бы вы объяснить, почему и как это работает (как с указателем, так и с двойным указателем)?

Необходим двойной указатель. Ваша структура данных является указателем на структуру. Затем вы вызываете функцию, которая должна изменить этот указатель. Поскольку параметры передаются по значению, вы должны передать указатель на указатель.

Я не понимаю, как структура представлена ​​в основной памяти.

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

1 голос
/ 27 июля 2011

Этот код может работать в целости и сохранности без двойных указателей:

void relItem (struct item * currItem) {...}

Вызовите его с помощью relItem (список)

Освобождение указателя не меняет его значения.Функции, которые принимают двойные указатели в качестве параметров, обычно используются, когда вы хотите изменить указатель (например, выделить его или сделать NULL).

Просто будьте осторожны при освобождении (intTemp), он падает, потому что вы освобождаете память отстек.

1 голос
/ 27 июля 2011

Вы можете думать об этом так: ваша структура данных представляет собой односвязный список, где каждый узел имеет тип T = struct item *. Вы передаете свой список вокруг его головы, то есть его первого узла. Потребители могут взять голову и перебрать весь список, посмотрев на T.next, а значение NULL означает, что вы в конце.

Функция relItem удаляет первый узел из списка. Поскольку он манипулирует самим списком, вы должны передать ему указатель на заголовок списка, т.е. Наконец, T = NULL следует интерпретировать (и проверять на!) Как пустой список без узлов.

1 голос
/ 27 июля 2011
  1. Если вы хотите изменить значение list (и вы хотите) в другой функции, вы должны указать ее адрес, поскольку все параметры в C передаются по значению, а не по ссылке.
  2. Вы передаете адрес указателю, потому что хотите изменить указатель.
  3. int a [5] не является структурой, но массив, структуры и массив представлены в C какблок памяти.Когда вы ссылаетесь на член структуры, вы на самом деле ссылаетесь на смещение от расположения структуры.

A.Вы освобождаете vertorOfInts, когда он был выделен не в куче (с помощью malloc), а в стеке (int array[] = {0, 1, 2, 3, 4, 5}; - локальное выделение), это недопустимо и приведет к аварийному завершению вашей программы (вероятно, к)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...