kavinderrana121 Ответов: 2

Двойной указатель на узел очереди


Мое сомнение касается только указателя,здесь голова является ли двойной указатель для очереди, если мы используем *голова чем мы получаем доступ к местоположению(или адресу, переданному) внутри main, но когда мы используем просто голова чем мы пользуемся голова только в текущей функции которая будет содержать адрес указателя на Очередь теперь, когда мы делаем это head=&(*head)->Далее с тех пор как (*голова)->Далее является ли сам по себе адрес и когда мы его используем &усилитель; перед этим будет создан отдельный блок памяти ,который будет содержать адрес (*голова)->Далее и мы назначаем этот адрес главе у меня есть это сомнение потому что это как двухэтапный процесс мы не можем напрямую поставить (*голова)->Далее чтобы что-то болело внутри головы, нам нужно передать адрес адреса, для этого нам потребуется дополнительный блок, и когда цикл будет выполнен, скажем, n раз, чем будет n промежуточных блоков? Пожалуйста скажите мне прав я или нет и скажите правильную логику спасибо

void queue_push(Queue **head, int d, int p)
{
    Queue *q = queue_new(d, p);

    while (*head && (*head)->priority < p) {
        head = &(*head)->next;
    }

    q->next = *head;
    *head = q;
}



сомнение номер 2

В функции
Graph *G = malloc(sizeof(*G));

Он выделяет блок памяти для одного блока, который будет содержать указатель на G
как насчет других элементов в структуре нет выделения памяти для них внутри структуры для их указателя (я беру по отношению к структуре графа)
Код взят из хорошей книги
Пожалуйста, помогите мне

Что я уже пробовал:

#include <stdio.h>
   #include <stdlib.h>
   #include <assert.h>

   typedef struct Queue Queue;

   struct Queue {
       int data;
       int priority;
       Queue *next;
   };

   Queue *queue_new(int d, int p)
   {
       Queue *n = malloc(sizeof(*n));

       n->data = d;
       n->priority = p;
       n->next = NULL;

       return n;
   }

   int queue_pop(Queue **head)
   {
       assert(*head);

       Queue *old = *head;
       int res = old->data;

       *head = (*head)->next;
       free(old);

       return res;
   }

   void queue_remove(Queue **head, int data)
   {
       while (*head && (*head)->data != data) {
           head = &(*head)->next;
       }

       if (*head) queue_pop(head);
   }

   void queue_push(Queue **head, int d, int p)
   {
       Queue *q = queue_new(d, p);

       while (*head && (*head)->priority < p) {
           head = &(*head)->next;
       }

       q->next = *head;
       *head = q;
   }


   int queue_empty(Queue *head)
   {
       return (head == NULL);
   }

   void queue_print(const Queue *q)
   {
       while (q) {
           printf("%d[%d] ", q->data, q->priority);
           q = q->next;
       }

       puts("$");
   }

   typedef struct Graph Graph;
   typedef struct Edge Edge;

   struct Edge {
       int vertex;
       int weight;
       Edge *next;
   };

   struct Graph {
       int v;
       Edge **edge;
       int *dist;
       int *path;
   };

   Graph *graph_new(int v)
   {
       Graph *G = malloc(sizeof(*G));

       G->v = v;
       G->edge = calloc(v, sizeof(*G->edge));
       G->dist = calloc(v, sizeof(*G->dist));
       G->path = calloc(v, sizeof(*G->path));

       return G;
   }

   void graph_delete(Graph *G)
   {
       if (G) {
           for (int i = 0; i < G->v; i++) {
               Edge *e = G->edge[i];

               while (e) {
                   Edge *old = e;

                   e = e->next;
                   free(old);
               }
           }

           free(G->edge);
           free(G->dist);
           free(G->path);
           free(G);
       }
   }

   Edge *edge_new(int vertex, int weight, Edge *next)
   {
       Edge *e = malloc(sizeof(*e));

       e->vertex = vertex;
       e->weight = weight;
       e->next = next;

       return e;
   }

   void graph_edge(Graph *G, int u, int v, int w)
   {
       G->edge[u] = edge_new(v, w, G->edge[u]);
       G->edge[v] = edge_new(u, w, G->edge[v]);
   }

   void dijkstra(const Graph *G, int s)
   {
       Queue *queue = NULL;

       for (int i = 0; i < G->v; i++) G->dist[i] = -1;
       G->dist[s] = 0;

       queue_push(&queue, s, 0);

       while (!queue_empty(queue)) {
           int v = queue_pop(&queue);
           Edge *e = G->edge[v];

           while (e) {
               int w = e->vertex;
               int d = G->dist[v] + e->weight;

               if (G->dist[w] == -1) {
                   G->dist[w] = d;
                   G->path[w] = v;

                   queue_push(&queue, w, d);
               }

               if (G->dist[w] > d) {
                   G->dist[w] = d;
                   G->path[w] = v;

                   queue_remove(&queue, w);
                   queue_push(&queue, w, d);
               }

               e = e->next;
           }
       }
   }

   int main()
   {
       int t;

       scanf("%d", &t);

       while (t--) {
           Graph *G;
           int v, e, s;

           scanf("%d %d", &v, &e);

           G = graph_new(v);

           for (int i = 0; i < e; i++) {
               int u, v, w;

               scanf("%d %d %d", &u, &v, &w);
               graph_edge(G, u - 1, v - 1, w);
           }

           scanf("%d", &s);
           dijkstra(G, s - 1);

           for (int i = 0; i < G->v; i++) {
               if (i != s - 1) {
                   printf("%d ", G->dist[i]);
               }
           }

           puts("");
           graph_delete(G);
       }

       return 0;
   }

2 Ответов

Рейтинг:
2

CPallini

Давайте попробуем немного экспериментального доказательства. Программа

#include <stdio.h>
#include <stdlib.h>

struct Queue
{
  int data;
  int priority;
  struct Queue *next;
};

void dump_pointers( struct Queue ** phead)
{
  printf("-- dump_pointers --\n");
  printf("phead=%p, *phead=%p &(*phead)=%p\n", phead, *phead, &(*phead));
}

void dump_sizes( struct Queue *p)
{
  printf("-- dump_sizes --\n");
  printf("sizeof(*p)=%lu\n", sizeof(*p));
  printf("sizeof(p->data)=%lu\n", sizeof(p->data));
  printf("sizeof(p->priority)=%lu\n", sizeof(p->priority));
  printf("sizeof(p->next)=%lu\n", sizeof(p->next));
}

int main()
{
  struct Queue * head = (struct Queue *) malloc(sizeof(*head));
  printf("head = %p\n", head);
  dump_pointers( &head);
  dump_sizes( head );
  free(head);
  return 0;
}


Выход:
head = 0x826010
-- dump_pointers --
phead=0x7ffc5a7e5020, *phead=0x826010 &(*phead)=0x7ffc5a7e5020
-- dump_sizes --
sizeof(*p)=16
sizeof(p->data)=4
sizeof(p->priority)=4
sizeof(p->next)=8


Так:
  • Нет (конечно) никакой разницы между ними. phead и &(*phead).
  • Размер а struct равна сумме размеров его переменных-членов (если некоторые из переменных структуры являются указателями, то malloc не выделяет дополнительную память, чтобы они указывали на допустимую область памяти).


Рейтинг:
0

Rick York

Graph *G = malloc(sizeof(*G));
"Он выделяет блок памяти для одного блока, который будет содержать указатель на G"

Не совсем. Это выделение Графовой структуры и присвоение G адресу этой структуры. Это, конечно, читаемый код, но я думаю, что он скрывает то, что происходит на самом деле, особенно для начинающих. Я думаю, что это было бы лучше написано как:
Graph *g = malloc( sizeof( Graph ) );
Я думаю, что это показывает, что происходит гораздо яснее. Лично я предпочитаю использовать calloc, потому что он обнуляет выделенную память. Еще одна вещь, как вы можете видеть в решении г-на Паллини, приведение требуется в результате распределения, потому что оно возвращает указатель void. Это означает, что мой маленький пример должен быть записан как
Graph *g = (Graph *)malloc( sizeof( Graph ) );
Под категорией for what it's worth, вот небольшой макрос, который может упростить выделение памяти:
#define AllocateMemory(count,type)	(type*)calloc(count,sizeof(type))
чтобы использовать его в этом случае для одного экземпляра :
Graph *g = AllocateMemory( 1, Graph );
Как видите, никакого кастинга не требуется.