У вас действительно большой беспорядок в ваших руках. Внесение вклада указателей typedef
, но в основном потому, что вы не можете выделить указатели nv
, а вместо этого выделите тот же указатель listAdj
, а затем сразу же перезаписать указатель с помощью NULL
, создав 100 утечек памяти. [1150 ]
Подумайте об этом:
for (i = 0; i < nv; i++) {
graph->listAdj = (TypePointer*) malloc(sizeof(TypePointer));
}
(Нет необходимости разыгрывать возвращение malloc
, это не нужно. См .: Я разыгрываю результат malloc? и ... ВСЕГДА проверяйте КАЖДОЕ распределение)
graph->listAdj
- это одиночный указатель, который содержит адрес для вновь выделенного блока памяти на каждой итерации, который затем перезаписывается при каждом последующем выделении.
Далее вы пытаетесь разыменовать перезаписанный указатель и установить несуществующие указатели на NULL
, например:
for (i = 0; i < nv; i++) {
graph->listAdj[i] = NULL;
}
Вы пытались выделить только один graph->listAdj
(хотя и 100 раз) , а не nv
указатели, как вы предполагали. Вы должны выделить память для nv
указателей сразу.
Теперь давайте начнем с самого начала и очистим все, удалив ВСЕ typedef
с, и просто используя int
для bool
, например
#include
#include
typedef struct aux {
int vDest;
int weight;
struct aux *next;
} TypeEdge;
typedef struct {
TypeEdge **listAdj;
int numVertices;
int numEdges;
} TypeGraph;
Теперь всем, кто смотрит на ваш код, совершенно очевидно, что listAdj
является указателем на указатель с по TypeEdge
. Там нет догадок или необходимости искать позже, задаваясь вопросом, что TypePointer
300 строк спустя, TypeEdge
это TypeEdge
, не более того.
Когда вы initializeGraph
, вам нужно выделить все nv
указатели, это один вызов malloc
, а не в цикле. Затем вы можете зациклить указатели, установив их все NULL
, например
int initializeGraph (TypeGraph *graph, int nv)
{
if (nv < 0)
return 0;
graph->numVertices = nv;
graph->numEdges = 0;
int i;
if ((graph->listAdj = malloc(sizeof *graph->listAdj * nv)) == NULL) {
perror ("malloc-graph->listAdj");
return 0;
}
for (i = 0; i < nv; i++)
(graph->listAdj)[i] = NULL;
return 1;
}
Далее, когда вы insertEdge()
, вы должны обработать случай, когда вы вставляете первое ребро для этой вершины, или вам нужно выполнить итерацию до конца списка и вставить туда. Вам также необходимо настроить способ итерации до конца, чтобы не пытаться получить доступ к actual->next
, если actual
равно NULL
. Собрав это вместе, вы можете сделать:
TypeEdge *insertEdge (int v1, int v2, int weight, TypeGraph *graph)
{
if (v1 < 0 || v1 > graph->numVertices ||
v2 < 0 || v2 > graph->numVertices) {
return NULL;
}
TypeEdge *actual = graph->listAdj[v1];
while (actual && actual->next)
actual = actual->next;
TypeEdge *pNew = malloc(sizeof *pNew);
if (!pNew) {
perror ("malloc-pNew");
return NULL;
}
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = NULL;
if (!actual)
graph->listAdj[v1] = pNew;
else
actual->next = pNew;
return (pNew);
}
( примечание: как тип возвращаемого значения функции был изменен на TypeEdge *
с void
, так что вы получите значимый возврат) это может указывать на Успех / Неудачу вашей попытки вставить ребро. Никогда не выделяйте в функции void
без возможности указать вызывающей функции, было ли выделение (и остаток критических шагов) успешным или неудачным)
[ 1161] Пока ваш main()
пытается insertEdge()
, он не дает никаких указаний на то, что произошло. Если у вас нет какого-либо способа проверки правильности вставленного края, это заставляет задуматься. Просто напишите короткий набор функций print
для обработки вывода списка ребер для каждой вершины, которая их имеет, например,
void prnedge (const TypeEdge *e)
{
do
printf (" %3d %3d\n", e->vDest, e->weight);
while ((e = e->next));
}
void print_edge (const TypeEdge *e, int edge)
{
printf ("\nedge %d\n", edge);
prnedge (e);
}
void print_graph (const TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
print_edge (g->listAdj[i], i);
}
Если вы выделили память, вы должны иметь возможность также освободить эту память. Аналогичный короткий набор функций может обрабатывать освобождение каждого списка, например
void freelist (TypeEdge *l)
{
while (l) {
TypeEdge *victim = l;
l = l->next;
free (victim);
}
}
void free_graphlists (TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
freelist (g->listAdj[i]);
free (g->listAdj);
}
Который вы можете назвать в main()
как:
int main (void) {
TypeGraph graph;
int result = initializeGraph (&graph, 100);
if (result) {
insertEdge (2, 3, 1, &graph);
insertEdge (2, 4, 1, &graph);
}
print_graph (&graph);
free_graphlists (&graph);
return 0;
}
В целом, вы можете сделать:
#include
#include
typedef struct aux {
int vDest;
int weight;
struct aux *next;
} TypeEdge;
typedef struct {
TypeEdge **listAdj;
int numVertices;
int numEdges;
} TypeGraph;
int initializeGraph (TypeGraph *graph, int nv)
{
if (nv < 0)
return 0;
graph->numVertices = nv;
graph->numEdges = 0;
int i;
if ((graph->listAdj = malloc(sizeof *graph->listAdj * nv)) == NULL) {
perror ("malloc-graph->listAdj");
return 0;
}
for (i = 0; i < nv; i++)
(graph->listAdj)[i] = NULL;
return 1;
}
TypeEdge *insertEdge (int v1, int v2, int weight, TypeGraph *graph)
{
if (v1 < 0 || v1 > graph->numVertices ||
v2 < 0 || v2 > graph->numVertices) {
return NULL;
}
TypeEdge *actual = graph->listAdj[v1];
while (actual && actual->next)
actual = actual->next;
TypeEdge *pNew = malloc(sizeof *pNew);
if (!pNew) {
perror ("malloc-pNew");
return NULL;
}
pNew->vDest = v2;
pNew->weight = weight;
pNew->next = NULL;
if (!actual)
graph->listAdj[v1] = pNew;
else
actual->next = pNew;
return (pNew);
}
void prnedge (const TypeEdge *e)
{
do
printf (" %3d %3d\n", e->vDest, e->weight);
while ((e = e->next));
}
void print_edge (const TypeEdge *e, int edge)
{
printf ("\nedge %d\n", edge);
prnedge (e);
}
void print_graph (const TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
print_edge (g->listAdj[i], i);
}
void freelist (TypeEdge *l)
{
while (l) {
TypeEdge *victim = l;
l = l->next;
free (victim);
}
}
void free_graphlists (TypeGraph *g)
{
for (int i = 0; i < g->numVertices; i++)
if (g->listAdj[i])
freelist (g->listAdj[i]);
free (g->listAdj);
}
int main (void) {
TypeGraph graph;
int result = initializeGraph (&graph, 100);
if (result) {
insertEdge (2, 3, 1, &graph);
insertEdge (2, 4, 1, &graph);
}
print_graph (&graph);
free_graphlists (&graph);
return 0;
}
Пример использования / вывода [ 1173]
$ ./bin/edgetype
edge 2
3 1
4 1
Использование памяти / проверка ошибок
В любом написанном вами коде, который динамически выделяет память, у вас есть 2 обязанности в отношении любого выделенный блок памяти: (1) всегда сохраняет указатель на начальный адрес для блока памяти, поэтому (2) его можно освободить , когда он больше не нужен. [ 1167]
Крайне важно, чтобы вы использовали программу проверки ошибок памяти, чтобы убедиться, что вы не пытаетесь получить доступ к памяти или писать за пределами / за пределами выделенного блока, пытаться прочитать или основать условный переход на неинициализированном значении и, наконец, , чтобы подтвердить, что вы освобождаете всю выделенную память.
Для Linux valgrind
- нормальный выбор. Для каждой платформы есть похожие проверки памяти. Все они просты в использовании, просто запустите вашу программу через него.
$ valgrind ./bin/edgetype
==21679== Memcheck, a memory error detector
==21679== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==21679== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==21679== Command: ./bin/edgetype
==21679==
edge 2
3 1
4 1
==21679==
==21679== HEAP SUMMARY:
==21679== in use at exit: 0 bytes in 0 blocks
==21679== total heap usage: 3 allocs, 3 frees, 832 bytes allocated
==21679==
==21679== All heap blocks were freed -- no leaks are possible
==21679==
==21679== For counts of detected and suppressed errors, rerun with: -v
==21679== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.
Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.
grep google *.php
если Вы хотите охватить много каталогов:
find . -name \*.php -print0 | xargs -0 grep -n -H google
(как объяснено в комментариях,-H полезен, если xargs придумывает только один остающийся файл),
Вы не должны делать
$ *.php | grep
Это означает, "запускает первую программу PHP, с названием остальных подстановочный знак как параметры, и затем выполняет grep на выводе".
Это должно быть:
$ grep -n -H "google" *.php
-n
флаг говорит этому делать номера строки, и -H
флаг говорит этому отображать имя файла, даже если существует только файл. Grep примет значение по умолчанию к показу имен файлов, если будет несколько искавших файлов, но Вы, вероятно, хотите удостовериться, что вывод последователен независимо от сколько соответствующих файлов, там.
Используйте "человека grep" для наблюдения других функций.
for i in $(ls *.php); do grep -n --with-filename "google" $i; done;
find . -name "*.php" -print | xargs grep -n "searchstring"
Пожалуйста, ознакомьтесь с подтверждением на http://betterthangrep.com . Эквивалент того, что вы пытаетесь сделать:
ack google --php