C 旅行商意外分段故障
我正试图实现我自己的深度优先搜索算法来解决C99中的旅行商问题,但我遇到了一个意想不到的分段错误 我有一小部分节点(大致)对应于英国的一些地方,它们之间的路径是对称的。问题出现在C 旅行商意外分段故障,c,segmentation-fault,traveling-salesman,C,Segmentation Fault,Traveling Salesman,我正试图实现我自己的深度优先搜索算法来解决C99中的旅行商问题,但我遇到了一个意想不到的分段错误 我有一小部分节点(大致)对应于英国的一些地方,它们之间的路径是对称的。问题出现在newNode()方法的早期,在该方法中,我创建了一个新节点并设置其初始状态。这涉及到为节点创建一个路径数组,该数组将指定连接的节点及其之间的“距离”,其中每个路径的节点元素初始化为NULL。这些数组比我目前实现的示例图所需的要大得多(请参见MAX\u path),因此以后很容易扩展 在这种情况下,路径数组可以包含16个
newNode()
方法的早期,在该方法中,我创建了一个新节点并设置其初始状态。这涉及到为节点创建一个路径数组,该数组将指定连接的节点及其之间的“距离”,其中每个路径的节点元素初始化为NULL。这些数组比我目前实现的示例图所需的要大得多(请参见MAX\u path
),因此以后很容易扩展
在这种情况下,路径
数组可以包含16个元素。初始化此数组的FOR循环在i=3
时引发分段错误。我完全找不到原因。我在代码下面添加了一些来自gdb
的输出。希望它能有所帮助,或者你可能更喜欢使用自己的方法
谢谢,;任何帮助都将不胜感激
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NODES 4
#define MAX_PATHS 16
typedef struct _node_t node_t;
typedef struct _path_t path_t;
struct _node_t
{
char name[64];
struct _path_t* paths;
};
struct _path_t
{
struct _node_t* node;
int dist;
};
node_t* nodes[NODES];
node_t* newNode(char* name)
{
node_t* toReturn = (node_t*) malloc(sizeof(node_t*));
if (toReturn == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
printf("toReturn (%p)\n", toReturn);
strcpy(toReturn->name, name);
toReturn->paths = (path_t*) malloc(sizeof(path_t) * MAX_PATHS);
if (toReturn->paths == NULL)
{
perror("malloc");
exit(EXIT_FAILURE);
}
printf("toReturn->paths (%p)\n", toReturn->paths);
for (int i = 0; i < MAX_PATHS; i++)
toReturn->paths[i].node = NULL; /* !!! */
return toReturn;
}
void addPath(node_t* node1, node_t* node2, int dist)
{
int i = 0;
while (i < MAX_PATHS)
{
if (node1->paths[i].node == NULL)
{
node1->paths[i].node = node2;
node1->paths[i].dist = dist;
break;
}
i++;
}
if (i == MAX_PATHS)
{
fprintf(stderr, "Ran out of paths!!\n");
exit(EXIT_FAILURE);
}
i = 0;
while (i < MAX_PATHS)
{
if (node2->paths[i].node == NULL)
{
node2->paths[i].node = node1;
node2->paths[i].dist = dist;
break;
}
i++;
}
if (i == MAX_PATHS)
{
fprintf(stderr, "Ran out of paths!!\n");
exit(EXIT_FAILURE);
}
}
int getNodeIndex(node_t* node)
{
for (int i = 0; i < NODES; i++)
if (nodes[i] == node)
return i;
return -1;
}
void depthFirstSearch(node_t* node, int* visited, int depth, int length)
{
printf("%s\n", node->name);
int i = 0; /* Path pointer */
int thisVisited[NODES];
memcpy(thisVisited, visited, sizeof(int) * NODES);
/* Set this node as visited */
visited[getNodeIndex(node)] = 1;
/* Now traverse all connected nodes that haven't been visited */
while (node->paths[i].node != NULL)
{
if (visited[getNodeIndex(node->paths[i].node)] == 0)
depthFirstSearch(node->paths[i].node, thisVisited, depth + 1,
node->paths[i].dist);
i++;
}
for (int j = 0; j < depth; j++)
putchar(' ');
}
int main(int argc, char** argv)
{
nodes[0] = newNode("Liverpool");
nodes[1] = newNode("London");
nodes[2] = newNode("Manchester");
nodes[3] = newNode("Norwich");
addPath(nodes[0], nodes[1], 212);
addPath(nodes[0], nodes[2], 34);
addPath(nodes[1], nodes[2], 208);
addPath(nodes[1], nodes[3], 114);
addPath(nodes[2], nodes[3], 191);
int visited[NODES] = {0};
depthFirstSearch(nodes[0], visited, 0, 0);
return EXIT_SUCCESS;
}
在FOR循环之前:
(gdb) p toReturn->paths[0]
$18 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[1]
$19 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[2]
$20 = {node = 0x602030, dist = 0} // (I don't understand this value here.)
(gdb) p toReturn->paths[3]
$21 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[4]
$22 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[5]
$23 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[6]
$24 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[7]
$25 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[8]
$26 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[9]
$27 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[10]
$28 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[11]
$29 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[12]
$30 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[13]
$31 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[14]
$32 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[15]
$33 = {node = 0x0, dist = 0}
(gdb) p *toReturn
$36 = {
name = "Liverpool", '\000' <repeats 15 times>, "\021\001", '\000' <repeats 37 times>, paths = 0x602030}
FOR循环之前的返回状态:
(gdb) p toReturn->paths[0]
$18 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[1]
$19 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[2]
$20 = {node = 0x602030, dist = 0} // (I don't understand this value here.)
(gdb) p toReturn->paths[3]
$21 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[4]
$22 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[5]
$23 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[6]
$24 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[7]
$25 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[8]
$26 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[9]
$27 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[10]
$28 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[11]
$29 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[12]
$30 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[13]
$31 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[14]
$32 = {node = 0x0, dist = 0}
(gdb) p toReturn->paths[15]
$33 = {node = 0x0, dist = 0}
(gdb) p *toReturn
$36 = {
name = "Liverpool", '\000' <repeats 15 times>, "\021\001", '\000' <repeats 37 times>, paths = 0x602030}
这看起来不对。您需要分配
节点的大小
而不是节点*
。当我们这样做时,.这些比预期的要糟糕得多。@Brian你是什么意思?getNodeIndex()
中的失败案例(return-1;
)从未处理过,只是取消了引用。不管它是否是segfault的来源,都要处理它。我的意思是,意外的segfault可能是一个真正的麻烦——比预期的segfault更糟。;)赞成。理想情况下,控件永远不会到达(return-1)语句,但无论如何,我已经用一条错误消息和exit()替换了它。。。是的,谢谢,我想就是这样。犯这样一个小错误是多么烦人啊!所以在这种情况下不使用malloc()会警告我吗?是的,应该是这样。许多学生犯的新手错误使用malloc(sizeof(*toReturn))
可能会使其更为明显(并且无需更改node\u t
的名称,或者toReturn的类型更改时)。
node_t* toReturn = (node_t*) malloc(sizeof(node_t*));