这个程序如何找段异常

这个程序怎么找段错误?
用哈希表写了个诗句接龙的程序。。
可是还有一个点超时(时间在100MS以内)。一个点段错误。
不太会排除段错误。
所以想在这里问下。段错误该怎么找。。
这个程序什么地方可能有段错误。。。
顺便问下时间还有什么地方可以改进。。。

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

#define lnmax 100
#define snmax 1000
#define max_length 80
#define find_first -1
typedef struct node poem;
struct node{
char *line;
int next_segment;
};

poem poems[snmax+1][lnmax+1];
int sn,ln,first;
char *hashtable[5000];
int usedtable[5000];
int indextable[5000];
void read();
void printsegment(int);
void printfirst(int);
void printall();
int hash_key(char *);
void hash_insert(int);
int hash_find(char *);
int issame(char *,char *);

int main(){
int count=1;
int i,j,k;
for(;;){
memset(usedtable,0,5000);
read();
if(sn*ln==0) break;
if(count>1) printf("\n");
for(i=0;i<sn;i++)
poems[i][ln-1].next_segment=-1;
for(i=0;i<sn;i++){
k=hash_find(poems[i][0].line);
if(k==find_first)
first=i;
else
poems[k][ln-1].next_segment=i;

}
printf("Scenario #%d\n",count);
printall();
for(i=0;i<sn;i++)
for(j=0;j<ln;j++)
free(poems[i][j].line);
count++;
}
return 0;
}

void read(){
int i,j;
scanf("%d %d",&sn,&ln);
getchar();
for(i=0;i<sn;i++){
for(j=0;j<ln;j++){
poems[i][j].line=(char *)malloc(81);
gets(poems[i][j].line);
}
hash_insert(i);
}
}

void printsegment(int now){
int i,j;
for(j=1;j<ln;j++)
printf("%s\n",poems[now][j].line);
}

void printfirst(int now){
int i,j;
for(j=0;j<ln;j++)
printf("%s\n",poems[now][j].line);

}

void printall(){
int now;
now=first;
printfirst(now);
now=poems[now][ln-1].next_segment;
while(poems[now][ln-1].next_segment!=-1){
printsegment(now);
now=poems[now][ln-1].next_segment;
}
printsegment(now);

}

int hash_key(char *p){
char key1,key2,key3,key4,key5,key6;
int key;
if(strlen(p)==0) return 0;
key1=p[strlen(p)];key2=p[strlen(p)/2];key3=p[strlen(p)/3];key6=p[0];
key=((key1*key2*key3*key4)%4999);
return key;
}

void hash_insert(int index){
char *p=poems[index][ln-1].line;
int key;
key=hash_key(p);
while(usedtable[key])
key++;
hashtable[key]=p;
indextable[key]=index;
usedtable[key]=1;
}

int hash_find(char *p){
  int key;
key=hash_key(p);
if(!usedtable[key]) 
return -1;
while(!issame(p,hashtable[key])) {
++key;
if(!usedtable[key]) 
return -1;
}
return indextable[key];
}

int issame(char *p1,char *p2){
if(strcmp(p1,p2)==0) return 1;
return 0;
}



------解决方案--------------------
linux下可以-g形式编译,用gdb接管进程,然后具体情况具体分析
unix下也是-g形式编译,dbx接管进程,当然有些os可以直接用dbx抓core分析,命令不同于lin

我没看你程序,帮你随便跑了下,以自己的为准
(gdb) s
printsegment (now=-1) at test14.c:72
72 for(j=1;j<ln;j++)
(gdb) s
73 printf("%s\n",poems[now][j].line);
(gdb) s
------解决方案--------------------
Windows:
崩溃的时候进入调试,按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史。双击某一行可将光标定位到此次调用的源代码处。
Linux:
进程意外退出会在当前目录下产生形如‘core.数字’的文件比如‘core.1234’
使用命令
gdb 运行程序名 core.数字
进入gdb然后使用bt命令
可以查看进程意外退出前函数调用的堆栈