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