I’m grappling with an issue in my code where a .DOT files nodes are being counted multiple times, especially when there are duplicates with the same name. I want to ensure that each node is counted only once, regardless of whether nodes with identical names exist. I tried using “return NULL” instead of “return node”, but it ended up triggering a memory error. Here are my codes, the output and the .DOT file:
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "parser.h"
#include "graph.h"
#include <getopt.h>
void print_help() {
printf("Usage: ./pagerank [options] <file>n");
printf("Perform pagerank computations for a given file in the DOT formatnn");
printf("Options:n");
printf(" -h Show this help messagen");
printf(" -r N Simulate N steps of the random surfern");
printf(" -m N Simulate N steps of the Markov chainn");
printf(" -s Compute and print statistics of the graphn");
printf(" -p P Set the boredom probability to P%% (default 10%%)n");
}
void compute_statistics(const char *filename) {
graph_t *graph = parse_graph(filename);
if (!graph) {
fprintf(stderr, "Error: Unable to parse the graph from file %sn", filename);
exit(1);
}
printf("%s:n", graph->name);
printf("- num nodes: %un", graph->count);
unsigned num_edges = 0;
unsigned min_in_degree = UINT_MAX, max_in_degree = 0;
unsigned min_out_degree = UINT_MAX, max_out_degree = 0;
for (unsigned i = 0; i < graph->count; i++) {
node_t *node = graph->nodes[i];
num_edges += node->num_edges;
if (node->num_edges < min_out_degree) min_out_degree = node->num_edges;
if (node->num_edges > max_out_degree) max_out_degree = node->num_edges;
unsigned in_degree = 0;
for (unsigned j = 0; j < graph->count; j++) {
for (unsigned k = 0; k < graph->nodes[j]->num_edges; k++) {
if (graph->nodes[j]->out_edges[k] == node) {
in_degree++;
}
}
}
if (in_degree < min_in_degree) min_in_degree = in_degree;
if (in_degree > max_in_degree) max_in_degree = in_degree;
}
printf("- num edges: %un", num_edges);
printf("- indegree: %u - %un", min_in_degree, max_in_degree);
printf("- outdegree: %u - %un", min_out_degree, max_out_degree);
free_graph(graph);
}
int main(int argc, char *const *argv) {
int opt;
int statistics_flag = 0;
while ((opt = getopt(argc, argv, "hr:m:sp:")) != -1) {
switch (opt) {
case 'h':
print_help();
exit(0);
case 's':
statistics_flag = 1;
break;
}
}
if (optind >= argc) {
fprintf(stderr, "Expected argument after optionsn");
exit(1);
}
if (optind < argc && argv[optind][0] == '-') {
optind++;
}
if (statistics_flag) {
compute_statistics(argv[optind]);
exit(0);
}
return 0;
}
graph.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "graph.h"
graph_t *init_graph(const char *name) {
graph_t *graph = malloc(sizeof(graph_t));
if (!graph) {
fprintf(stderr, "Not enough memory to allocate for graph %sn", name);
exit(1);
}
graph->nodes = NULL;
graph->count = 0;
graph->name = calloc(strlen(name)+1 ,sizeof(char));
strcpy(graph->name,name);
return graph;
}
void free_graph(graph_t *graph) {
while (graph->count--){
node_t *node = graph->nodes[graph->count];
if (node->num_edges)
free(node->out_edges);
free(node->name);
free(node);
}
free(graph->nodes);
free(graph->name);
free(graph);
graph = NULL;
}
node_t *get_node_from_graph(graph_t *graph, const char *name) {
unsigned tmp = graph->count;
while (tmp--) {
node_t *node = graph->nodes[tmp];
if(!strcmp (node -> name, name)){
return node;
}
}
node_t *node = malloc(sizeof(node_t));
node->out_edges = NULL;
node->num_edges = 0;
node->name = calloc(strlen(name)+1,sizeof(char));
strcpy ( node->name , name);
graph->nodes = realloc(graph->nodes, (graph->count + 1) * sizeof(node_t *));
graph->nodes[graph->count++] = node;
return node;
}
void add_edge_to_node(node_t *source, node_t *target) {
source->out_edges = realloc(source->out_edges, (source->num_edges + 1) * sizeof(node_t *));
source->out_edges[source->num_edges++] = target;
}
graph.h:
#ifndef GRAPH_H
#define GRAPH_H
typedef struct node {
struct node **out_edges;
unsigned num_edges;
char *name;
} node_t;
typedef struct graph {
node_t **nodes;
unsigned count;
char *name;
} graph_t;
graph_t *init_graph(const char *);
void free_graph(graph_t *);
node_t *get_node_from_graph(graph_t *, const char *);
void add_edge_to_node(node_t *, node_t *);
#endif
parser.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "parser.h"
#include "graph.h"
graph_t *parse_graph(const char *filename) {
FILE *file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Given filename matches no file!n");
exit(1);
}
char s_name[256];
char t_name[256];
// Read the header of the DOT file
if (fscanf(file, " digraph %255s {", s_name) != 1) {
fprintf(stderr, "Error while reading graph namen");
exit(1);
}
graph_t *graph = init_graph(s_name);
// Clear the names before starting to read edges
memset(s_name, 0, sizeof(s_name));
memset(t_name, 0, sizeof(t_name));
// Read edges until the end of the graph
while (fscanf(file, " %255[^-]->%255[^;];", s_name, t_name) == 2) {
node_t *s_node = get_node_from_graph(graph, s_name);
node_t *t_node = get_node_from_graph(graph, t_name);
add_edge_to_node(s_node, t_node);
// Clear the names after reading
memset(s_name, 0, sizeof(s_name));
memset(t_name, 0, sizeof(t_name));
}
fclose(file);
return graph;
}
parser.h:
#ifndef PARSER_H
#define PARSER_H
#include "graph.h"
graph_t *parse_graph(const char *filename);
#endif
My dot file:
digraph Graph {
C -> d ;
d -> Git ;
d -> Git ;
d -> guide ;
d -> forum ;
d -> leaderboard ;
leaderboard -> d ;
leaderboard -> Git ;
leaderboard -> Git ;
guide -> forum ;
forum -> guide ;
forum -> d ;
}
The Output I get (with a debug state):
Adding new node: C
Adding new node: d
Adding new node:
d
Adding new node: Git
Adding new node: guide
Adding new node: forum
Adding new node: leaderboard
Adding new node:
leaderboard
Adding new node:
guide
Adding new node:
forum
Graph:
- num nodes: 10
- num edges: 12
- indegree: 0 – 4
- outdegree: 0 – 5
Output I need to get:
Graph:
- num nodes: 6
- num edges: 12
- indegree: 0 – 4
- outdegree: 0 – 5
Any suggestions on how to fix this?
Tagore is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.