在屏幕上打印链表时程序崩溃
Program crashes when printing a linked list on screen
我不知道为什么我可以毫无问题地读取 LABEL 中的链表 : 1 ;但程序只是崩溃并在 LABEL 中打印 grabage : 0 ;
换句话说,为什么链表在 lecture 函数内部工作正常,但在外部却不行?
这是我的代码:
/* including libraries */
#define V 20
typedef struct DATA{
char* NomP;char* NomA;
struct DATA *Next;
}DATA;
// Prototypes .
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = MALLOC(sizeof (DATA)); int len = lecture_data(fs,HEAD);
print_data(HEAD,len); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA *ROOT)
{
char cNom[V],cArticle[V];
int eofs=0;int i=0;
while(!eofs)
{
DATA *Data = MALLOC(sizeof (DATA));
fscanf(fs,"%s %s",cNom,cArticle);
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if( i==0 )
{
Data -> Next = NULL ;
ROOT = Data ;
}
else
{
DATA* Ptr = ROOT ;
while( (Ptr->Next) != NULL )
{
Ptr = (Ptr -> Next);
}
Data -> Next = NULL ;
Ptr -> Next = Data ;
}
i++;
eofs = feof(fs) ;
// check ferror(fs) here
}
puts("Start of reading :");
print_data(ROOT,len); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
这是打印函数:
void print_data(DATA *L_ROOT,int len)
{
int i = 0 ;
DATA* LINK;
LINK = L_ROOT;
while( LINK != NULL )
{
printf("%d : DATA->NomA : %s\n",i,LINK->NomA);
printf("%d : DATA->NomP : %s\n",i,LINK->NomP);
LINK = LINK -> Next ;
i++;
}
}
您在 main 函数中为列表的根分配数据,并将其传递给该函数,以便它可以填充列表,但是第一次分配元素时,您会覆盖 ROOT 指针值。
这会让你失去函数与外界之间的唯一联系(因为 return 值只是一个数字),所以 main() 中的 HEAD 值指向没有任何意义(因为你的函数从不使用它),而列表仍然分配在某个外部没有人指向的内存位置,这意味着它丢失了。 运行 valgrind 应该能够识别这一点。
您可以通过将 (i==0) 大小写从 -
更改为
ROOT = Data ;
进入
ROOT->next = Data ;
但请确保稍后忽略根节点的数据。
p.s。 - 使用大写变量和类型被认为不是一个好主意(它主要为宏保留)。它还使您的代码看起来像在大喊:)
(主要)问题是 lecture_data
没有使用它的输入参数 (ROOT
) 来存储链表,return 也没有使用内部生成的列表.处理此问题的正确方法是让 ROOT
引用调用作用域的参数,以便它可以根据需要更新它的引用。
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = NULL;
int len = lecture_data(fs, &HEAD);
print_data(HEAD); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA **ROOT)
{
char cNom[V],cArticle[V];
int i=0;
DATA *current = *ROOT; // grab the passed in reference
while(!feof(fs))
{
if(fscanf(fs,"%s %s",cNom,cArticle) <= 0) // This call is only successful if the return value is > 0
{
// check ferror(fs) here
continue; // Can also "break;" here, essentially, it's eof already
}
DATA *Data = MALLOC(sizeof (DATA));
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if(NULL == current) // ROOT was uninitialized before the call
{
Data -> Next = NULL;
*ROOT = Data;
}
else
{ // We don't need to iterate the list in every step.
Data->Next = current->Next; // This part allows the function to insert nodes in the middle / end of an existing list
current->Next = Data;
current = Data;
}
i++;
}
puts("Start of reading :");
print_data(ROOT); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
注意:print_data
没有对 len
参数做任何事情,所以根本不需要传递它。
就列表中的 "empty" 个节点而言,此解决方案并不浪费(与要忽略的空头相反),并且既适用于从头开始初始化列表,也适用于您需要的情况追加/插入现有列表。
我不知道为什么我可以毫无问题地读取 LABEL 中的链表 : 1 ;但程序只是崩溃并在 LABEL 中打印 grabage : 0 ; 换句话说,为什么链表在 lecture 函数内部工作正常,但在外部却不行? 这是我的代码:
/* including libraries */
#define V 20
typedef struct DATA{
char* NomP;char* NomA;
struct DATA *Next;
}DATA;
// Prototypes .
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = MALLOC(sizeof (DATA)); int len = lecture_data(fs,HEAD);
print_data(HEAD,len); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA *ROOT)
{
char cNom[V],cArticle[V];
int eofs=0;int i=0;
while(!eofs)
{
DATA *Data = MALLOC(sizeof (DATA));
fscanf(fs,"%s %s",cNom,cArticle);
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if( i==0 )
{
Data -> Next = NULL ;
ROOT = Data ;
}
else
{
DATA* Ptr = ROOT ;
while( (Ptr->Next) != NULL )
{
Ptr = (Ptr -> Next);
}
Data -> Next = NULL ;
Ptr -> Next = Data ;
}
i++;
eofs = feof(fs) ;
// check ferror(fs) here
}
puts("Start of reading :");
print_data(ROOT,len); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
这是打印函数:
void print_data(DATA *L_ROOT,int len)
{
int i = 0 ;
DATA* LINK;
LINK = L_ROOT;
while( LINK != NULL )
{
printf("%d : DATA->NomA : %s\n",i,LINK->NomA);
printf("%d : DATA->NomP : %s\n",i,LINK->NomP);
LINK = LINK -> Next ;
i++;
}
}
您在 main 函数中为列表的根分配数据,并将其传递给该函数,以便它可以填充列表,但是第一次分配元素时,您会覆盖 ROOT 指针值。
这会让你失去函数与外界之间的唯一联系(因为 return 值只是一个数字),所以 main() 中的 HEAD 值指向没有任何意义(因为你的函数从不使用它),而列表仍然分配在某个外部没有人指向的内存位置,这意味着它丢失了。 运行 valgrind 应该能够识别这一点。
您可以通过将 (i==0) 大小写从 -
更改为ROOT = Data ;
进入
ROOT->next = Data ;
但请确保稍后忽略根节点的数据。
p.s。 - 使用大写变量和类型被认为不是一个好主意(它主要为宏保留)。它还使您的代码看起来像在大喊:)
(主要)问题是 lecture_data
没有使用它的输入参数 (ROOT
) 来存储链表,return 也没有使用内部生成的列表.处理此问题的正确方法是让 ROOT
引用调用作用域的参数,以便它可以根据需要更新它的引用。
int main(void)
{
char FileName[V];
puts("Data file ? : ");gets(FileName);
FILE* fs = fopen(FileName,"r"); // Check if fs is NULL
DATA *HEAD = NULL;
int len = lecture_data(fs, &HEAD);
print_data(HEAD); //LABEL : 0
return 0;
}
int lecture_data(FILE *fs,DATA **ROOT)
{
char cNom[V],cArticle[V];
int i=0;
DATA *current = *ROOT; // grab the passed in reference
while(!feof(fs))
{
if(fscanf(fs,"%s %s",cNom,cArticle) <= 0) // This call is only successful if the return value is > 0
{
// check ferror(fs) here
continue; // Can also "break;" here, essentially, it's eof already
}
DATA *Data = MALLOC(sizeof (DATA));
Data->NomA = MALLOC(strlen(cArticle)+1);
Data->NomP = MALLOC(strlen(cNom)+1);
strcpy(Data->NomA,cArticle);
strcpy(Data->NomP,cNom);
if(NULL == current) // ROOT was uninitialized before the call
{
Data -> Next = NULL;
*ROOT = Data;
}
else
{ // We don't need to iterate the list in every step.
Data->Next = current->Next; // This part allows the function to insert nodes in the middle / end of an existing list
current->Next = Data;
current = Data;
}
i++;
}
puts("Start of reading :");
print_data(ROOT); // LABEL : 1
puts("End Of Reading ");
fclose(fs);
return i;
}
注意:print_data
没有对 len
参数做任何事情,所以根本不需要传递它。
就列表中的 "empty" 个节点而言,此解决方案并不浪费(与要忽略的空头相反),并且既适用于从头开始初始化列表,也适用于您需要的情况追加/插入现有列表。