执行我的程序时出现奇怪的转储核心错误 (C)
Weird dumpcore error while executing my program (C)
我制作了一个从文件中读取数字的程序,它应该用读取的数字制作一个列表。
我不确定 while(fscanf ... 等)。我可以做什么样的循环来读取所有数字直到文件末尾?
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct node{
int info;
struct node *link;
}Tnode;
typedef Tnode *Tlist;
Tlist CreateList();
Tnode *CreateNode(int x);
Tlist InsertAtEnd(Tlist list,int x);
void PrintList(Tlist list);
void PrintInfo(int nodeinf);
int main(int argc, char** argv) {
int x,i;
FILE *pf=fopen("file1.txt","r");
assert(pf!=NULL);
Tlist list;
list=CreateList();
while(fscanf(pf,"%d",&x)==1){
list=InsertAtEnd(list,x);
}
PrintList(list);
return (EXIT_SUCCESS);
}
Tnode *CreateNode(int x){
Tnode *newnode;
newnode=malloc(sizeof(Tnode));
assert(newnode!=NULL);
newnode->info=x;
newnode->link=NULL;
return newnode;
}
Tlist CreateList(){
return NULL;
}
Tlist InsertAtEnd(Tlist list,int x){
Tnode *newnode,*tmp;
newnode=CreateNode(x);
tmp=list;
//CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp==NULL)
tmp=newnode;
else{//NEL CASO IN CUI LA LISTA NON E' VUOTA
while(tmp->link!=NULL){
tmp=tmp->link;
}
tmp->link=newnode;
}
return list;
}
void PrintInfo(int nodeinf){
printf("%d",nodeinf);
}
void PrintList(Tlist list){
Tnode *node;
node=list;
while (node->link!=NULL){
PrintInfo(node->info);
node=node->link;
}
return;
}
当我构建它时,它没有给我任何错误。然后当我 运行 它显示
0 [main] simulazione_1 669 cygwin_exception::open_stackdumpfile: Dumping stack trace to simulazione_1.exe.stackdump
RUN FAILED (exit value 35.584, total time: 1s)
这是什么错误。我的代码有什么问题?
函数InsertAtEnd
无效。当列表最初为空时,函数 returns NULL 因为指针 list
在函数中没有改变。
改变的是指针tmp
。
使用您的方法,函数看起来像下面的方式
Tlist InsertAtEnd( Tlist list, int x )
{
Tnode *newnode = CreateNode(x);
if ( list == NULL )
{
list = newnode;
}
else
{
Tnode *tmp = list;
while ( tmp->link != NULL )
{
tmp = tmp->link;
}
tmp->link = newnode;
}
return list;
}
另外函数PrintList
也不正确。应该这样定义
void PrintList( Tlist list )
{
for ( Tnode *node = list; node != NULL; node = node->link )
{
PrintInfo(node->info);
}
}
首先是错误(这里有 两个 严重错误):
首先,您犯了一个错误:您猜对了,当列表为空时(只有一个 NULL
指针),您必须将初始指针更改为指向第一个节点的指针,但是当你对它进行编码时,你没有正确地考虑它并且 return 原始传递的指针(继续指向 NULL
):
Tlist InsertAtEnd(Tlist list,int x){
Tnode *newnode,*tmp;
newnode=CreateNode(x);
tmp=list;
//CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp==NULL)
tmp=newnode;
您必须将 list
指针更改为 return 正确的值,如:
list=newnode;
或更好:
return newnode;
其次,在print函数中,需要继续while
循环,直到节点没有next
元素,(while(node->link != NULL)
) (这将在打印最后一个元素 之前结束循环 ,更糟糕的是,这就是导致程序失败的原因,因为您向它传递了一个初始 NULL
指针因为您没有正确填充列表,并且当 node
本身是 NULL
时您尝试访问 node->link
,这是一个错误,它是导致程序崩溃的原因),所以您必须检查指针本身何时为 NULL
(如 while(node != NULL)
),导致:
void PrintList(Tlist list) {
Tnode *node = list; /* idem. */
while (node != NULL) { /* why not use a for() loop here? */
PrintInfo(node->info);
node = node->link;
}
return;
}
或更好:
void PrintList(Tlist list) {
Tnode *node;
for (node = list; node != NULL; node = node->link) {
PrintInfo(node->info);
}
return;
}
断言宏:
assert
宏是一个调试宏,你用错了它。它向您显示代码失败的行(这很好),以及您传递给它的表达式(这也很好)。但它有一个你没有考虑到的缺点:在生产代码中,通常 #define NDEBUG 1
只是为了消除你在代码中所做的所有断言(所有断言都是有条件地编译的)。这有一个问题,通过这样做,你代码中的所有断言都会神奇地消失,但这包括你在传递给它的参数中所做的所有测试(这不好).我已经尝试通过一组宏来重写您的所有断言,这些宏将节省键入时间,并且还可以让您跟踪代码中哪里有错误。由于这些宏中没有代码可以有条件地编译它们,因此您可以放心,代码将出现在最终的生产代码中:
#define F(_fmt) __FILE__":%d: " _fmt, __LINE__
这将展开:
printf(F("Error: %s has not been opened\n"), file);
进入:
printf(__FILE__":%d: " "Error: %s has not been opened\n", __LINE__, file);
或者,假设该语句位于文件 pru.c
的第 112 行:
printf("pru.c" ":%d: " "Error: %s has not been opened\n", 112, file);
这将导致(假设文件是 "File1.txt"
):
pru.c:112: Error: File1.txt has not been opened
为了节省您的击键次数,我还定义了一个 ERR(fmt, ...)
宏来扩展为 fprintf(stderr, ...)
调用。
易读性
您必须提高代码的易读性,以使其更具可读性。好像您输入代码的每个 space 都会向您收费。
所有这些修改后,您修改后的代码如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define F(_fmt) __FILE__":%d: "_fmt, __LINE__
#define ERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
typedef struct node{
int info;
struct node *link;
}Tnode;
typedef Tnode *Tlist;
Tlist CreateList();
Tnode *CreateNode(int x);
Tlist InsertAtEnd(Tlist list, int x);
void PrintList(Tlist list);
void PrintInfo(int nodeinf);
int main(int argc, char** argv)
{
int x,i;
char *file_name = "file1.txt";
FILE *pf=fopen(file_name, "r");
if (!pf) {
ERR(F("%s: %s\n"), file_name, strerror(errno));
exit(EXIT_FAILURE);
}
Tlist list = CreateList(); /* it's good to initialize in declarations */
while(fscanf(pf, "%d", &x) == 1) {
list = InsertAtEnd(list, x);
}
PrintList(list);
return (EXIT_SUCCESS);
}
Tnode *CreateNode(int x)
{
Tnode *newnode = malloc(sizeof(Tnode)); /* better initialize in declaration */
if (!newnode) {
ERR(F("malloc: %s\n"), strerror(errno));
exit(EXIT_FAILURE);
}
newnode->info = x;
newnode->link = NULL;
return newnode;
}
Tlist CreateList()
{
return NULL;
}
Tlist InsertAtEnd(Tlist list, int x)
{
Tnode *newnode = CreateNode(x), /* idem. */
*tmp = list;
// CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp == NULL) {
return newnode; /* return here, you have nothing else to do */
}
// NEL CASO IN CUI LA LISTA NON E' VUOTA
while(tmp->link != NULL) {
tmp = tmp->link;
}
tmp->link = newnode;
return list;
}
void PrintInfo(int nodeinf) {
printf("%d\n", nodeinf); /* you lacked a \n here */
}
void PrintList(Tlist list) {
Tnode *node = list; /* idem. */
while (node != NULL) { /* why not use a for() loop here? */
PrintInfo(node->info);
node = node->link;
}
return;
}
我制作了一个从文件中读取数字的程序,它应该用读取的数字制作一个列表。
我不确定 while(fscanf ... 等)。我可以做什么样的循环来读取所有数字直到文件末尾?
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct node{
int info;
struct node *link;
}Tnode;
typedef Tnode *Tlist;
Tlist CreateList();
Tnode *CreateNode(int x);
Tlist InsertAtEnd(Tlist list,int x);
void PrintList(Tlist list);
void PrintInfo(int nodeinf);
int main(int argc, char** argv) {
int x,i;
FILE *pf=fopen("file1.txt","r");
assert(pf!=NULL);
Tlist list;
list=CreateList();
while(fscanf(pf,"%d",&x)==1){
list=InsertAtEnd(list,x);
}
PrintList(list);
return (EXIT_SUCCESS);
}
Tnode *CreateNode(int x){
Tnode *newnode;
newnode=malloc(sizeof(Tnode));
assert(newnode!=NULL);
newnode->info=x;
newnode->link=NULL;
return newnode;
}
Tlist CreateList(){
return NULL;
}
Tlist InsertAtEnd(Tlist list,int x){
Tnode *newnode,*tmp;
newnode=CreateNode(x);
tmp=list;
//CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp==NULL)
tmp=newnode;
else{//NEL CASO IN CUI LA LISTA NON E' VUOTA
while(tmp->link!=NULL){
tmp=tmp->link;
}
tmp->link=newnode;
}
return list;
}
void PrintInfo(int nodeinf){
printf("%d",nodeinf);
}
void PrintList(Tlist list){
Tnode *node;
node=list;
while (node->link!=NULL){
PrintInfo(node->info);
node=node->link;
}
return;
}
当我构建它时,它没有给我任何错误。然后当我 运行 它显示
0 [main] simulazione_1 669 cygwin_exception::open_stackdumpfile: Dumping stack trace to simulazione_1.exe.stackdump
RUN FAILED (exit value 35.584, total time: 1s)
这是什么错误。我的代码有什么问题?
函数InsertAtEnd
无效。当列表最初为空时,函数 returns NULL 因为指针 list
在函数中没有改变。
改变的是指针tmp
。
使用您的方法,函数看起来像下面的方式
Tlist InsertAtEnd( Tlist list, int x )
{
Tnode *newnode = CreateNode(x);
if ( list == NULL )
{
list = newnode;
}
else
{
Tnode *tmp = list;
while ( tmp->link != NULL )
{
tmp = tmp->link;
}
tmp->link = newnode;
}
return list;
}
另外函数PrintList
也不正确。应该这样定义
void PrintList( Tlist list )
{
for ( Tnode *node = list; node != NULL; node = node->link )
{
PrintInfo(node->info);
}
}
首先是错误(这里有 两个 严重错误):
首先,您犯了一个错误:您猜对了,当列表为空时(只有一个 NULL
指针),您必须将初始指针更改为指向第一个节点的指针,但是当你对它进行编码时,你没有正确地考虑它并且 return 原始传递的指针(继续指向 NULL
):
Tlist InsertAtEnd(Tlist list,int x){
Tnode *newnode,*tmp;
newnode=CreateNode(x);
tmp=list;
//CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp==NULL)
tmp=newnode;
您必须将 list
指针更改为 return 正确的值,如:
list=newnode;
或更好:
return newnode;
其次,在print函数中,需要继续while
循环,直到节点没有next
元素,(while(node->link != NULL)
) (这将在打印最后一个元素 之前结束循环 ,更糟糕的是,这就是导致程序失败的原因,因为您向它传递了一个初始 NULL
指针因为您没有正确填充列表,并且当 node
本身是 NULL
时您尝试访问 node->link
,这是一个错误,它是导致程序崩溃的原因),所以您必须检查指针本身何时为 NULL
(如 while(node != NULL)
),导致:
void PrintList(Tlist list) {
Tnode *node = list; /* idem. */
while (node != NULL) { /* why not use a for() loop here? */
PrintInfo(node->info);
node = node->link;
}
return;
}
或更好:
void PrintList(Tlist list) {
Tnode *node;
for (node = list; node != NULL; node = node->link) {
PrintInfo(node->info);
}
return;
}
断言宏:
assert
宏是一个调试宏,你用错了它。它向您显示代码失败的行(这很好),以及您传递给它的表达式(这也很好)。但它有一个你没有考虑到的缺点:在生产代码中,通常 #define NDEBUG 1
只是为了消除你在代码中所做的所有断言(所有断言都是有条件地编译的)。这有一个问题,通过这样做,你代码中的所有断言都会神奇地消失,但这包括你在传递给它的参数中所做的所有测试(这不好).我已经尝试通过一组宏来重写您的所有断言,这些宏将节省键入时间,并且还可以让您跟踪代码中哪里有错误。由于这些宏中没有代码可以有条件地编译它们,因此您可以放心,代码将出现在最终的生产代码中:
#define F(_fmt) __FILE__":%d: " _fmt, __LINE__
这将展开:
printf(F("Error: %s has not been opened\n"), file);
进入:
printf(__FILE__":%d: " "Error: %s has not been opened\n", __LINE__, file);
或者,假设该语句位于文件 pru.c
的第 112 行:
printf("pru.c" ":%d: " "Error: %s has not been opened\n", 112, file);
这将导致(假设文件是 "File1.txt"
):
pru.c:112: Error: File1.txt has not been opened
为了节省您的击键次数,我还定义了一个 ERR(fmt, ...)
宏来扩展为 fprintf(stderr, ...)
调用。
易读性
您必须提高代码的易读性,以使其更具可读性。好像您输入代码的每个 space 都会向您收费。
所有这些修改后,您修改后的代码如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#define F(_fmt) __FILE__":%d: "_fmt, __LINE__
#define ERR(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__)
typedef struct node{
int info;
struct node *link;
}Tnode;
typedef Tnode *Tlist;
Tlist CreateList();
Tnode *CreateNode(int x);
Tlist InsertAtEnd(Tlist list, int x);
void PrintList(Tlist list);
void PrintInfo(int nodeinf);
int main(int argc, char** argv)
{
int x,i;
char *file_name = "file1.txt";
FILE *pf=fopen(file_name, "r");
if (!pf) {
ERR(F("%s: %s\n"), file_name, strerror(errno));
exit(EXIT_FAILURE);
}
Tlist list = CreateList(); /* it's good to initialize in declarations */
while(fscanf(pf, "%d", &x) == 1) {
list = InsertAtEnd(list, x);
}
PrintList(list);
return (EXIT_SUCCESS);
}
Tnode *CreateNode(int x)
{
Tnode *newnode = malloc(sizeof(Tnode)); /* better initialize in declaration */
if (!newnode) {
ERR(F("malloc: %s\n"), strerror(errno));
exit(EXIT_FAILURE);
}
newnode->info = x;
newnode->link = NULL;
return newnode;
}
Tlist CreateList()
{
return NULL;
}
Tlist InsertAtEnd(Tlist list, int x)
{
Tnode *newnode = CreateNode(x), /* idem. */
*tmp = list;
// CASO IN CUI LA LISTA E' ANCORA VUOTA
if(tmp == NULL) {
return newnode; /* return here, you have nothing else to do */
}
// NEL CASO IN CUI LA LISTA NON E' VUOTA
while(tmp->link != NULL) {
tmp = tmp->link;
}
tmp->link = newnode;
return list;
}
void PrintInfo(int nodeinf) {
printf("%d\n", nodeinf); /* you lacked a \n here */
}
void PrintList(Tlist list) {
Tnode *node = list; /* idem. */
while (node != NULL) { /* why not use a for() loop here? */
PrintInfo(node->info);
node = node->link;
}
return;
}