C 打印的边与节点不匹配

C 打印的边与节点不匹配,c,arrays,dictionary,nodes,edges,C,Arrays,Dictionary,Nodes,Edges,我有一个程序,它读取一个包含两列数字的文件,对它们进行排序,创建三个表,一个只包含节点(单独),一个包含所有边,另一个包含每个节点的边数。问题是,当我试图打印边缘时,它打印错误或者说找不到它们。通过一些gdb,我发现第一个数组很好,但第三个数组在末尾存储了一组随机数(或零)。任何帮助都将不胜感激。 文件如下所示(每条边的开始/结束节点): 代码如下所示: #include<stdio.h> #include<stdlib.h> #include<string.h&g

我有一个程序,它读取一个包含两列数字的文件,对它们进行排序,创建三个表,一个只包含节点(单独),一个包含所有边,另一个包含每个节点的边数。问题是,当我试图打印边缘时,它打印错误或者说找不到它们。通过一些gdb,我发现第一个数组很好,但第三个数组在末尾存储了一组随机数(或零)。任何帮助都将不胜感激。 文件如下所示(每条边的开始/结束节点):

代码如下所示:

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



int mapcmp(const void *a,const void *b){
  return ( *(int*)a - *(int*)b );
}

int mapdoublesize(int** map,int nodes){
    int* new_array=malloc(nodes*2*sizeof(int));
    if(new_array==NULL){
        printf("Error allocating memory\n");
        abort();
    }
    nodes*=2;
    for(int i=0;i<nodes;i++){
        new_array[i]=(*map)[i];
    }

    free(*map);
    *map=new_array;
    return nodes;
}

typedef struct {
    int start;
    int end;   
} path;

int cmp(const void *a,const void *b){
    int l=((path*)a)->start;
    int r=((path*)b)->start;

    if(l>r)
        return 1;
    if(l<r)
        return -1;
    if(l==r)
        return 0;
  }

int doublesize(path** array,int n){
    path* new_array=malloc(n*2*sizeof(path));
    if(new_array==NULL){
        printf("Error allocating memory\n");
        abort();
    }

    for(int i=0;i<n;i++){
        new_array[i]=(*array)[i];
    }
    free(*array);
    *array=new_array;
    n*=2;
    return n;

}


int main()
{
    int maxsize=10;
    int test;
    path* array=malloc(maxsize*sizeof(path));
    if(array==NULL) {
        printf("Error allocating memory\n");
        abort();
    }


    FILE* fd=fopen("Wiki-Vote.txt","r");
    if(fd==NULL) {
        printf("Error opening file\n");
        abort();
    }
    char buff[200];
    int counter=0;

    char c;
  while(fgets(buff,200,fd)) {

        c=buff[0];
        if(c=='#') {
            continue;
        }
    sscanf(buff,"%d%d",&array[counter].start,&array[counter].end);
        counter++;
        if(counter==maxsize){
           maxsize=doublesize(&array,maxsize); 
    }

    }
  int i;
  maxsize=counter;
    counter=0;
    qsort(&array[0],maxsize,sizeof(path),cmp);




  counter=0;
  int nodes=10;
  int* map=malloc(nodes*sizeof(int));
  if(map==NULL){
    printf("Error allocating memory\n");
    abort();
  }

for(i=0;i<maxsize;i++){
  if(map[counter-1]==array[i].start)
    continue;
        map[counter]=array[i].start;
        counter++;
        if(counter==nodes){
          nodes=mapdoublesize(&map,nodes);
        }
}
int j;
for(i=0;i<maxsize;i++){
  for(j=0;j<counter;j++){
    if(map[j]==array[i].end)
      break;
  }
  if(j!=counter)
    continue;
  map[counter]=array[i].end;
  counter++;
  if(counter==nodes)
    nodes=mapdoublesize(&map,nodes);
}

nodes=counter;
qsort(&map[0],nodes,sizeof(int),mapcmp);


  int* arraynodes=malloc(nodes*sizeof(int));
  int* arrayedges=malloc(maxsize*sizeof(int));
  if(arraynodes==NULL||arrayedges==NULL){
    printf("Error allocating memory\n");
    abort();
  }
  counter=1;

  arraynodes[0]=0;
  for(i=0;i<maxsize;i++){
    arrayedges[i]=array[i].end;
    if(array[i].start!=array[i+1].start){
      arraynodes[counter]=i;
      counter++;
    }
  }


int x;
  printf("give number to search: "); 
  scanf("%d",&x);
  for(i=0;i<nodes;i++){
    if(x==map[i]){
      printf("found \n");
      break;
    }

  }
  if(i==nodes){
    printf("not found \n");
    abort();
  }

  for(j=arraynodes[i];j<arraynodes[i+1];j++){
    printf("%d\n",arrayedges[j]);
  }

  free(arraynodes);
  free(arrayedges);
  free(map);
    fclose(fd);
    free(array);
        return 0;
}

#包括
#包括
#包括
int mapcmp(常数无效*a,常数无效*b){
返回(*(int*)a-*(int*)b);
}
int-mapdoublesize(int**map,int节点){
int*new_数组=malloc(nodes*2*sizeof(int));
if(新数组==NULL){
printf(“分配内存时出错”);
中止();
}
节点*=2;
对于(int i=0;istart;
int r=((路径*)b)->开始;
如果(l>r)
返回1;
如果(lCore)回答:
我理解您的意图,您希望
arraynodes
为每个节点索引保留该节点的边开始的边列表中的偏移量

迭代边列表,每次起点更改时,都将当前偏移量存储在
阵列节点中。这是有缺陷的,因为并非所有节点都是边的起点。因此,如果边列表中有一条来自节点5->7的边,然后是一条来自6->7的边,则将从节点5注册起点的更改到6,但您将在
阵列节点
的开头存储当前偏移量,而不是存储第5个节点的偏移量

要解决此问题,请执行以下操作:在边列表中保留一个偏移量,初始值为零。迭代节点,对于每个节点,将当前偏移量存储到
arraynodes
。然后增加偏移量,只要当前偏移量处的边的起点等于当前节点。这样
arraynodes
将告诉您e的值ach节点索引,在该索引处存储从该节点开始的边列表中的边

  /**
   * Assumption: Edges are sorted by their starting point.
   */

  int edge_count = maxsize;
  int edge_offset = 0;

  /**
   * For each node:
   *
   * - Store current edge_offset in arraynodes
   * - Increment edge_offset as long as the start point
  *    of the edge at that offset matches the current node.
   */
  for (int i = 0; i < nodes; i++) {
    int current_node = map[i];
    arraynodes[i] = edge_offset;

    while (edge_offset < edge_count && array[edge_offset].start == current_node) {
      edge_offset++;
    }
  }

  /**
   * Copy end-points of edges to arrayedges.
   *
   * You don't really need this, you could also directly
   * access the end-points in your output loop ...
   */
  for (int i = 0; i < edge_count; i++) {
    arrayedges[i] = array[i].end;
  }
  • 缓冲区溢出:初始化映射时,当映射已满时,希望将其大小加倍。但是,在
    mapdoublesize
    中,当您将数据从旧映射复制到新映射时,您会迭代整个新映射,因此此循环的后半部分将读取旧映射的边界:
  • 缓冲区溢出:在输出循环中,如果
    i
    是最后一个节点,则对
    arraynodes[i+1]
    的访问将超出界限:
  • for(j=arraynodes[i];j

    我不能保证我发现了所有内存安全问题。很可能还有更多问题。我建议您改进程序的结构和文档编制:将程序分解为执行一个步骤的较小函数,并记录此步骤的假设和先决条件(即,您正在访问的阵列的边界是什么?)。请给出清晰描述其用途的变量名称,不要重复使用变量。这将使您更容易发现此类错误。此外,我建议您使用工具检查内存安全问题。GCC和Clang都有一个名为ASAN的功能,该功能将自动将调试代码插入到二进制文件中,以检测错误d运行程序时报告内存安全问题。可以通过使用
    -fsanize=address
    ()编译来启用此功能。另一个具有类似作用域的工具是Valgrind()。当然,这些程序无法找到所有错误,因为它们只对实际执行的代码进行动态分析。如果程序的某个分支中存在当前执行未达到的错误,则不会被检测到。因此,您仍然无法仔细查看您的程序。

    了解您的错误可能会有所帮助你的输入格式。你是什么意思?我现在明白了,我很困惑,因为你发布的示例使第一行“边缘节点”看起来像是输入格式的一部分。这是一个世界级的答案!如果可以,我会投两次票
      /**
       * Assumption: Edges are sorted by their starting point.
       */
    
      int edge_count = maxsize;
      int edge_offset = 0;
    
      /**
       * For each node:
       *
       * - Store current edge_offset in arraynodes
       * - Increment edge_offset as long as the start point
      *    of the edge at that offset matches the current node.
       */
      for (int i = 0; i < nodes; i++) {
        int current_node = map[i];
        arraynodes[i] = edge_offset;
    
        while (edge_offset < edge_count && array[edge_offset].start == current_node) {
          edge_offset++;
        }
      }
    
      /**
       * Copy end-points of edges to arrayedges.
       *
       * You don't really need this, you could also directly
       * access the end-points in your output loop ...
       */
      for (int i = 0; i < edge_count; i++) {
        arrayedges[i] = array[i].end;
      }
    
      counter = 0;
      int nodes = 10;
      int *map = malloc(nodes * sizeof(int));
      if (map == NULL) {
        printf("Error allocating memory\n");
        abort();
      }
    
      for (i = 0; i < maxsize; i++) {
        if (map[counter - 1] == array[i].start)
          continue;
    
      nodes *= 2;
      for (int i = 0; i < nodes; i++) {
        new_array[i] = (*map)[i];
      }
    
      for (i = 0; i < maxsize; i++) {
        arrayedges[i] = array[i].end;
        if (array[i].start != array[i + 1].start) {
    
    for (j = arraynodes[i]; j < arraynodes[i + 1]; j++) {