【问题标题】:Dynamic allocation of list in STL and element insertion [closed]STL中列表的动态分配和元素插入[关闭]
【发布时间】:2017-03-05 13:14:00
【问题描述】:

下面的代码应该读取一个图中的多个节点,然后在动态分配的相邻节点列表中引入一定数量的边。由于某种原因,当在read_graf() 中调用add_edge() 函数时程序停止,并且IDE(又名cb)打开stl_list 的主文件。谁能指出问题?谢谢!

代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<list>
#define grafMAX 101

FILE *fin = fopen("grafin.txt","r");
FILE *fout = fopen("grafout.txt","w");

struct Graf{
    int nrV;
    std::list <int> *ad;
};

void init_graf(Graf g, int nr){
    g.nrV = nr;
    g.ad = new std::list <int> [g.nrV];//(std::list <int> *)malloc(g.nrV * sizeof(std::list <int>));
}

void add_edge(Graf g, int n1, int n2){
    g.ad[n1].push_back(n2);
    g.ad[n2].push_back(n1);
}

inline int min(const int a, const int b){
    if(a < b)
        return a;
    return b;
}

void read_graf(Graf g){
    int n,m;
    fscanf(fin,"%d%d",&n,&m);
    init_graf(g,n);
    while(m){
        int x,y;
        fscanf(fin,"%d%d",&x,&y);
        add_edge(g,x,y);
        --m;
    }
}

这是一个输入:

10 - # of nodes
11 - # of edges to be read
1 2
1 3
1 10
2 4
3 4
3 5
5 6
5 7
6 7
7 8
7 9

【问题讨论】:

  • 不确定您的 IDE 的功能,但您是否尝试过一个调试器来进入该特定函数调用?例如,它可能会因空值而崩溃。

标签: c++ list c++11 stl


【解决方案1】:

您正在将 Graf 按值传递给函数。这意味着所有更改都针对您传递的参数的副本。原件不变。

如果您希望更改在函数外部可见,则应传递对Graf 的引用,例如void init_graf(Graf&amp; g, int nr)

【讨论】:

  • 我仍然遇到同样的错误,即使我通过引用传递了值。
【解决方案2】:

在我开始之前,这是两种 C 编码风格的奇怪组合,只需投入少量 C++ 即可访问 List 类。这从来都不是一个好主意。您的大部分代码都是用 C 编写的,因此您应该使用通过 malloc 获得的 C 数组。如果你想使用 C++ 列表类,那么这个程序应该使用 C++ 类和包含文件和结构重写。

关于你的问题...

当您调用 init_graf 时,您通过值传递 Graf G,因此当 init_graf 返回时,由 init_graf 完成的任何初始化都将丢失。您需要在 C 中通过引用传递它,以便更新它。

稍后,当您调用 add_edge 时,g 仍未初始化,因此“ad”字段仍未初始化,因此 g.ad[n1] 将取消引用错误指针,从而导致异常并且您的程序将停止:

void add_edge(Graf g, int n1, int n2){
    g.ad[n1].push_back(n2);
    g.ad[n2].push_back(n1);

为了解决这个问题,init_graf 应该得到一个指向 Graf 结构的指针,同样地 add_edge 应该得到一个指向 g 的指针。这是您删除使用类列表的解决方案(使其成为真正的 C 程序)。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
// #include<list>
#define grafMAX 101

FILE *fin = fopen("grafin.txt","r");
FILE *fout = fopen("grafout.txt","w");

struct Edge {
     int startNode;
     int endNode; 
};

struct Graf{
    int  nrV;      
    int  edgeCount; // Added to keep track of number allocated
    Edge *ad;
};

void init_graf(Graf *g, int nr){
    g->nrV       = 0;
    g->edgeCount = nr; 
    g->ad = malloc(graphMax*sizeof(Edge));
}

void add_edge(Graf *g, int n1, int n2){
    // Check array bound before adding a new edge
    if (g->nrV < g->edgeCount) {
       // Add the edge to the edge array and increment nrV
       g->ad[g->nrV].startNode = n1;
       g->ad[g->nrV].endNode   = n2;
       g->nrV++;
    }
}

inline int min(const int a, const int b){
    if(a < b)
        return a;
    return b;
}

void read_graf(Graf *g){
    int n,m;
    fscanf(fin,"%d%d",&n,&m);
    init_graf(g,n);
    while(m){
        int x,y;
        fscanf(fin,"%d%d",&x,&y);
        add_edge(g,x,y);
        --m;
    }
}

如果您真的想使用 C++,那么 Bo 建议使用 & 通过引用传递 Graf 参数的建议很棒,但是我建议您然后重新构建程序以使用类而不是结构,并使用 C++ 标头而不是 C标头(例如 cstdio 而不是 stdio.h)

【讨论】:

  • 这看起来像一个完美的 C 程序。但是,问题标记为 C++ 和 STL。 :-)
  • 谢谢博。我同意它被标记为 C++,但我认为提问者只是试图将 C++ 列表添加到 C 程序中,所以我建议使用 C 数组,而不是试图将 C++ 类中的硬塞到其他 C 程序中。如果他真的想要 C++,我建议重写它并使用标准的 C++ 头文件、类而不是结构等。
  • 感谢 ScottK 的建议。我知道我的编码风格(或者我喜欢称之为我的编码风格)有点混乱,因为我正在从 C 过渡到 C++。即使 C++ 带来了新的和强大的机制 (OOP),我仍然喜欢一些 C 语法元素,例如指向文件和 scanf 和 printf 的指针,因为它们让我比流更能控制我正在读/写的内容。这只是一个意见。
  • 没问题 SongBird,C 有一些很棒的特性,它们都可以在 C++ 中使用。我已经向学生教授了 C++,我认为学习 C++ 的最佳方法是不依赖任何 C 头文件(作为开始)。切换到使用 C++ 头文件,并开始将结构定义为类而不是结构。类接受相同的语法,但允许您更多地控制添加方法和构造函数。如果有帮助,我可以为您发布一个等效的 C++,但也许您应该先自己尝试一下。祝你好运!
  • @ScottK 我猜想在 C++ 等效项中,您会创建一个 Graf 类,并且您已经将上述所有功能实现为公共方法。您还将语法从 C 更改为 C++(从 scanf 更改为流等)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 2019-11-30
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
相关资源
最近更新 更多