我在C中创建了一个图形结构。下面给出了图形的结构定义。
typedef struct _GNODE_ {
int nodeNumber; // vertex/node number
int adjNum; // number of adjacent nodes
struct _GNODE_ **adjacent; // array of pointers to adjacent nodes
} _GNODE_ ;
typedef struct _GRAPH_ {
int vc; // number of vertices
char *name; // graph name
int **AM; // adjacency matrix
_GNODE_ **node; // array of pointer to each vertices
} _GRAPH_ ;
其中 _GNODE _ 是图表中节点的结构。
函数 readGraphFromTxt(char * fileName,_GRAPH_ * graph)读取包含图形邻接矩阵的文本文件,并调用另一个名为 createGraphFromAM(_GRAPH_ * graph)的函数创建图形结构。
int readGraphFromTxt(char *filename , _GRAPH_ *graph){
FILE *fp;
fp = fopen(filename, "r");
int vc;
int **AM;
char *gname;
if(fp != NULL){
char graphName[100];
fgets(graphName, 99, fp );
gname = (char *)malloc(sizeof(char)*101);
strncpy(gname , graphName, 99);
fgets(graphName, 99, fp );
fscanf(fp , "%d\n" , &vc);
AM = (int **) malloc(sizeof(int*) * vc);
for(int i=0; i<vc; i++){
AM[i] = (int *)malloc(sizeof(int) * vc);
if(fscanf(fp, "%s" , graphName) ==EOF) break;
for(int j=0; j<vc; j++){
AM[i][j] = graphName[j] - '0';
}
}
}
if(AM != NULL) graph->AM = AM;
if(gname != NULL ) graph->name = gname;
graph->vc = vc;
createGraphFromAM(graph);
fclose(fp);
return vc;
}
void createGraphFromAM(_GRAPH_ *graph) {
graph->node = (_GNODE_ **)malloc(sizeof(_GNODE_) * graph->vc) ; // array of pointers to different nodes
for (int i=0; i<graph->vc ; i++){
graph->node[i] = (_GNODE_ *)malloc(sizeof(_GNODE_));
graph->node[i]->adjNum=0;
graph->node[i]->nodeNumber = i; // node number
graph->node[i]->adjacent = (_GNODE_ **)malloc(sizeof(_GNODE_)) ; // because allocating 0 byte is tricky
}
for (int i=0; i<graph->vc ; i++){
for (int j=0; j<graph->vc ; j++){
if(graph->AM[i][j]==1){ // check for adjacency between i and j
graph->node[i]->adjNum++; // if adjacent increment number of adjacent nodes number
graph->node[i]->adjacent = (_GNODE_ **)realloc( graph->node[i]->adjacent , sizeof(_GNODE_) * (graph->node[i]->adjNum+1)); // reallocate the memory to hold new adjacent member
graph->node[i]->adjacent[graph->node[i]->adjNum-1] = graph->node[j]; // points to another node
}
}
graph->node[i]->adjacent[graph->node[i]->adjNum] = NULL; // set last adjacent node to NULL
}
}
函数 freeGraph(_GRAPH_ * graph)应该解除分配给图形的所有内存。 但是在调用此函数时,程序会遇到SEGMENTATION FAULT 。
void freeGraph(_GRAPH_ *graph){
// free graph
for (int i=0; i<graph->vc; i++) {
// free each node data
printf("\nLoop: %d\n", i);
// free each adjacent node
for (int k=0; k<graph->node[i]->adjNum; k++){
if(graph->node[i]->adjacent[k]!=NULL){
free(graph->node[i]->adjacent[k]);
}
}
if(graph->node[i]->adjacent!=NULL) {
free(graph->node[i]->adjacent);
}
free(graph->node[i]);
}
free(graph->node);
for(int i=0; i<graph->vc; i++)
if(graph->AM[i]!=NULL) free(graph->AM[i]);
free(graph->AM);
free(graph->name);
free(graph);
}
名为 printAllGraphNodeNumber(const _GRAPH_ * graph)的函数,用于打印所有节点编号及其相邻节点编号。
void printAllGraphNodeNumber(const _GRAPH_ *graph) {
printf("NODES IN THE GRAPH: ");
for (int i=0; i<graph->vc ; i++) {
printf("\nNode Number : %d\n|-----> Adjacent Nodes: ",graph->node[i]->nodeNumber);
for (int j=0; j<graph->node[i]->adjNum; j++){
printf("%d , ", graph->node[i]->adjacent[j]->nodeNumber );
}
}
}
示例文件的内容&#34; Graph01.txt&#34;是: 最大顶点数为:20
one
AM
10
0100010011
1000110100
0000100001
0000000010
0110000100
1100000001
0000000001
0100100010
1001000101
1010011010
答案 0 :(得分:1)
我通过删除函数 freeGraph()中注释为释放每个相邻节点的代码来解决此问题。结果代码如下:
void freeGraph(_GRAPH_ *graph){
// free graph
for (int i=0; i<graph->vc; i++) {
// free each node data
printf("\nLoop: %d\n", i);
// free each adjacent node
/*
for (int k=0; k<graph->node[i]->adjNum; k++){
if(graph->node[i]->adjacent[k]!=NULL){
free(graph->node[i]->adjacent[k]);
}
}*/
if(graph->node[i]->adjacent!=NULL) {
free(graph->node[i]->adjacent);
}
free(graph->node[i]);
}
free(graph->node);
for(int i=0; i<graph->vc; i++)
if(graph->AM[i]!=NULL) free(graph->AM[i]);
free(graph->AM);
free(graph->name);
// commenting this out : because this is not dynamically allocated
// free(graph);
}
我这样做的原因是因为graph->node[i]->adjacent[k]
是指向图的不同节点的指针,这些节点最后将被free(graph->node[i])
释放。
我使用 Valgrind 进行了检查,效果非常好。显示健康清单的统计数据。所有分配都被释放。我想我很高兴。
PS:我仍然认为它不是最佳解决方案。但这就是我解决问题的方法。希望其他任何人都能提供更好的答案。答案 1 :(得分:1)
这是对您的代码的改编。我已经清理了我在问题评论中提出的许多观点。特别是:
data
中读取。您可以通过在命令行上指定要读取的文件来覆盖它。我还修改了代码,以便readGraphFromTxt()
返回一个已分配的指针,以便freeGraph()
可以正确地释放它。
主要修复方法是确保每个malloc()
被释放一次。在您诊断时,您试图释放邻接列表指向的节点,这是不正确的行为。这些节点应该被集体释放,因为它们是集体分配的。
我整理了印刷品(至少按照我的标准)。
我使用GitHub中提供的文件stderr.c
和stderr.h
来简化错误报告。当错误报告很简单时,它不太可能被省略。我在几个地方作弊并使用assert()
而不是正式的错误测试和消息。
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stderr.h"
typedef struct Node
{
int nodeNumber;
int adjNum;
struct Node **adjacent;
} Node;
typedef struct Graph
{
int vc;
char *name;
int **AM;
Node **node;
} Graph;
static void createGraphFromAM(Graph *graph);
static Graph *readGraphFromTxt(const char *filename)
{
FILE *fp = fopen(filename, "r");
if (fp == 0)
err_syserr("failed to open file %s for reading\n", filename);
Graph *graph = malloc(sizeof(*graph));
if (graph == 0)
err_syserr("failed to allocate %zu bytes\n", sizeof(*graph));
char line[100];
if (fgets(line, sizeof(line), fp) == 0)
err_error("premature EOF - no graph name\n");
line[strcspn(line, "\n")] = '\0';
char *gname = strdup(line);
if (fgets(line, sizeof(line), fp) == 0)
err_error("premature EOF - no auxilliary info\n");
int vc = -1;
if (fscanf(fp, "%d", &vc) != 1)
err_error("format error: didn't get an integer\n");
if (vc < 1 || vc > 20)
err_error("size of graph out of control: %d\n", vc);
int **AM = (int **)malloc(sizeof(int *) * vc);
if (AM == 0)
err_syserr("failed to allocate %zu bytes\n", sizeof(int *) * vc);
for (int i = 0; i < vc; i++)
{
AM[i] = (int *)malloc(sizeof(int) * vc);
if (AM[i] == 0)
err_syserr("failed to allocate %zu bytes\n", sizeof(int) * vc);
if (fscanf(fp, "%s", line) == EOF)
err_error("premature EOF - not enough lines of data for the adjacency matrix\n");
if (strlen(line) < (size_t)vc)
err_error("Adjacency matrix line is too short (got [%s] (%zu); wanted %d)\n",
line, strlen(line), vc);
for (int j = 0; j < vc; j++)
{
assert(line[j] == '0' || line[j] == '1');
AM[i][j] = line[j] - '0';
}
}
graph->AM = AM;
graph->name = gname;
graph->vc = vc;
graph->node = 0;
createGraphFromAM(graph);
fclose(fp);
return graph;
}
/* How many times does val appear in array arr of size num? */
static inline size_t val_count(size_t num, const int arr[num], int val)
{
assert(arr != 0);
size_t count = 0;
for (const int *end = arr + num; arr < end; arr++)
{
if (*arr == val)
count++;
}
return count;
}
static void createGraphFromAM(Graph *graph)
{
graph->node = (Node **)malloc(sizeof(*graph->node) * graph->vc);
if (graph->node == 0)
err_syserr("failed to allocate %zu bytes\n", sizeof(*graph->node) * graph->vc);
for (int i = 0; i < graph->vc; i++)
{
graph->node[i] = (Node *)malloc(sizeof(Node));
if (graph->node[i] == 0)
err_syserr("failed to allocate %zu bytes\n", sizeof(Node));
graph->node[i]->adjNum = val_count(graph->vc, graph->AM[i], 1);
graph->node[i]->nodeNumber = i;
size_t adj_size = sizeof(Node *) * (graph->node[i]->adjNum + 1);
graph->node[i]->adjacent = (Node **)malloc(adj_size);
if (graph->node[i]->adjacent == 0)
err_syserr("failed to allocate %zu bytes\n", adj_size);
}
for (int i = 0; i < graph->vc; i++)
{
Node *node = graph->node[i];
int adj = 0;
for (int j = 0; j < graph->vc; j++)
{
if (graph->AM[i][j] == 1)
node->adjacent[adj++] = graph->node[j];
}
node->adjacent[node->adjNum] = NULL;
}
}
static void freeGraph(Graph *graph)
{
for (int i = 0; i < graph->vc; i++)
{
free(graph->node[i]->adjacent);
free(graph->node[i]);
}
free(graph->node);
for (int i = 0; i < graph->vc; i++)
free(graph->AM[i]);
free(graph->AM);
free(graph->name);
free(graph);
}
static void printAllGraphNodeNumber(const Graph *graph)
{
assert(graph != 0);
printf("Nodes in the graph %s: %d\n", graph->name, graph->vc);
for (int i = 0; i < graph->vc; i++)
{
printf("Node: %d - Adjacent Nodes: ", graph->node[i]->nodeNumber);
const char *pad = "";
for (int j = 0; j < graph->node[i]->adjNum; j++)
{
printf("%s%d", pad, graph->node[i]->adjacent[j]->nodeNumber);
pad = ", ";
}
putchar('\n');
}
}
int main(int argc, char **argv)
{
err_setarg0(argv[0]);
const char *filename = "data";
if (argc == 2)
filename = argv[1];
Graph *graph = readGraphFromTxt(filename);
if (graph != 0)
{
printAllGraphNodeNumber(graph);
freeGraph(graph);
}
return 0;
}
问题中提供的内容的副本:
one
AM
10
0100010011
1000110100
0000100001
0000000010
0110000100
1100000001
0000000001
0100100010
1001000101
1010011010
Nodes in the graph one: 10
Node: 0 - Adjacent Nodes: 1, 5, 8, 9
Node: 1 - Adjacent Nodes: 0, 4, 5, 7
Node: 2 - Adjacent Nodes: 4, 9
Node: 3 - Adjacent Nodes: 8
Node: 4 - Adjacent Nodes: 1, 2, 7
Node: 5 - Adjacent Nodes: 0, 1, 9
Node: 6 - Adjacent Nodes: 9
Node: 7 - Adjacent Nodes: 1, 4, 8
Node: 8 - Adjacent Nodes: 0, 3, 7, 9
Node: 9 - Adjacent Nodes: 0, 2, 5, 6, 8
升级到macOS High Sierra 10.13后,我(再一次)没有Valgrind。但是,其他一些工具让我放心,这可能是正确的。