我编写了一个程序来将一组数据从文件读取到链表中。程序从文件中读取一行,标记该行,将其存储到节点中,然后移动到下一行。每次这样做时,我都会打印节点的内容。我遇到的问题是,当程序运行时,它会在文件中的两行之一停止并崩溃。它在一条线上停止的频率高于另一条线。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
typedef struct prefectNode
{
char *name; // prefect name
char *type; // prefect type
char *used;
struct free// structure storing the prefect's free sessions on particular days
{
char M[9];
char T[9];
char W[9];
char S[9];
char F[9];
} fses; // free sessions available to prefect;
struct prefectNode *nextPtr;// a pointer to the next node
} pNode;// Self-Referential structure used to store information about a prefect
typedef pNode *ptrNode;// Synonym for a pointer to a self-referential structure
void induct(ptrNode *list, char l[]);// induct is called when information is being retrieved from file.
void induct(ptrNode *list, char l[])
{
ptrNode curPtr = NULL;// pointer to the current node
ptrNode newPtr = malloc(sizeof(pNode));// creating new node
if (newPtr != NULL)
{
newPtr->name = strtok(l, ",");
newPtr->type = strtok(NULL, ",");
char *sesh = strtok(NULL, " ");
char c = sesh[0];
printf("%sn%sn", newPtr->name, newPtr->type);
int i = 0, j = 0;
for (i = 0; i < strlen(sesh); i++)
{
char c = sesh[i];
if (c == 'M')
{
newPtr->fses.M[j] = sesh[i + 1];
printf("M%c", newPtr->fses.M[j]);
}
if (c == 'T')
{
newPtr->fses.T[j] = sesh[i + 1];
printf("T%c", newPtr->fses.T[j]);
}
if (c == 'W')
{
newPtr->fses.W[j] = sesh[i + 1];
printf("W%c", newPtr->fses.W[j]);
}
if (c == 'S')
{
newPtr->fses.S[j] = sesh[i + 1];
printf("S%c", newPtr->fses.S[j]);
}
if (c == 'F')
{
newPtr->fses.F[j] = sesh[i + 1];
printf("F%c", newPtr->fses.F[j]);
}
i = i + 2;
j++;
}
newPtr->nextPtr = NULL;
curPtr = *list;
if (curPtr == NULL)
{
newPtr->nextPtr = *list;
*list = newPtr;
}
else
{
while (curPtr->nextPtr != NULL)
{
curPtr = curPtr->nextPtr;
}
curPtr->nextPtr = newPtr;
}
}
else
{
printf("no memory");
}
}
char ln[200];
FILE *fp;
int main()
{
ptrNode start = NULL;
fp = fopen("thefile.txt", "r");
if (fp == NULL)
{
printf("File not found.");
}
else
{
while (!feof(fp))
{
fgets(ln, sizeof(ln), fp);
induct(&start, ln);
printf("nn");
}
}
fclose(fp);
getch();
return 0;
}
下面是输入文件的外观示例:
Denelia Alvaranga,R,M7_T4_T5_T6
Sainna Christian,R,M4_M5_M6_T1_T2_T3_F5_F6
Kashielle Clarke,R,F1_T4_W4_F4_T5_W5_S5_W6_S6_M7_W7
Candice Gordon,R,M1_M2_M3_S3_T7
Alphene Groves,R,M2_T5_S7_W3
T-Anna Johnson,R,M7
Vanessa Lewis,R,M1_M2_M3_S3_T4_W4_S4_T5_S5_T6_S6
当我到达第 9 行时,程序崩溃(更频繁):
Rhoni-Ann Parkins,R,W1_S1_W2_S2_W3_S3_M4_T4_S4_F4_M5_T5_F5_M6_T6_F6_T7_F7
或第 37 行:
Ashleigh Graham,N6A
主要问题
您的主要问题之一是j
失控 - 它在首次初始化后永远不会归零。 罗尼-安惹麻烦,因为她有很多空闲时间;阿什利惹麻烦,因为她没有空闲时间。 使用 Rhoni-Ann,j
达到 18,但您索引的数组最多只能达到 9。 您需要重新访问代码的整个部分。 您需要读取日字母后面的数字,并使用它代替j
值。 您还应该验证该值是否足够小(值为 9
会导致再次溢出;只有 0..8 是正常的),并报告日期字母是否无效。 另请注意,分配内存时空间不会清零。 不清楚你之后要做什么,但是你在M
、T
等数组中没有有效的字符串。
修订后的代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct prefectNode
{
char *name; // prefect name
char *type; // prefect type
char *used;
struct free// structure storing the prefect's free sessions on particular days
{
char M[9];
char T[9];
char W[9];
char S[9];
char F[9];
} fses; // free sessions available to prefect;
struct prefectNode *nextPtr;// a pointer to the next node
} pNode;// Self-Referential structure used to store information about a prefect
typedef pNode *ptrNode;// Synonym for a pointer to a self-referential structure
void induct(ptrNode *list, char l[]);// induct is called when information is being retrieved from file.
void induct(ptrNode *list, char l[])
{
ptrNode curPtr = *list; // pointer to the current node
ptrNode newPtr = calloc(sizeof(*newPtr), 1);// creating new node
if (newPtr != NULL)
{
newPtr->name = strdup(strtok(l, ","));
newPtr->type = strdup(strtok(NULL, ","));
printf("Prefect: %s, type %sn", newPtr->name, newPtr->type);
char *sesh = strtok(NULL, " ");
if (sesh == NULL)
{
fprintf(stderr, "No free sessions for %sn", newPtr->name);
free(newPtr->name);
free(newPtr->type);
free(newPtr);
return;
}
int i = 0, j = 0;
int len = strlen(sesh);
for (i = 0; i < len; i++)
{
char c = sesh[i];
if (c == 'M')
{
newPtr->fses.M[j] = sesh[i + 1];
printf("M%c", newPtr->fses.M[j]);
}
if (c == 'T')
{
newPtr->fses.T[j] = sesh[i + 1];
printf("T%c", newPtr->fses.T[j]);
}
if (c == 'W')
{
newPtr->fses.W[j] = sesh[i + 1];
printf("W%c", newPtr->fses.W[j]);
}
if (c == 'S')
{
newPtr->fses.S[j] = sesh[i + 1];
printf("S%c", newPtr->fses.S[j]);
}
if (c == 'F')
{
newPtr->fses.F[j] = sesh[i + 1];
printf("F%c", newPtr->fses.F[j]);
}
printf("(j=%d)n", j);
i = i + 2;
j++;
}
newPtr->nextPtr = NULL;
curPtr = *list;
if (curPtr == NULL)
{
newPtr->nextPtr = *list;
*list = newPtr;
}
else
{
while (curPtr->nextPtr != NULL)
{
curPtr = curPtr->nextPtr;
}
curPtr->nextPtr = newPtr;
}
}
else
{
printf("no memoryn");
}
}
static void free_node(pNode *node)
{
if (node != 0)
{
free(node->name);
free(node->type);
free(node);
}
}
static void free_list(pNode *node)
{
while (node != 0)
{
pNode *next = node->nextPtr;
free_node(node);
node = next;
}
}
static void print_sessions(const char *dow, const char *ses)
{
printf(" %s:", dow);
for (int i = 0; i < 9; i++)
{
if (ses[i] != ' ')
printf(" %c", ses[i]);
}
}
static void print_node(const pNode *node)
{
printf("%s [%s]", node->name, node->type);
print_sessions("Mon", node->fses.M);
print_sessions("Tue", node->fses.T);
print_sessions("Wed", node->fses.W);
print_sessions("Thu", node->fses.S);
print_sessions("Fri", node->fses.F);
putchar('n');
}
static void print_list(const char *tag, pNode *list)
{
printf("%s:n", tag);
while (list != NULL)
{
print_node(list);
list = list->nextPtr;
}
}
int main(void)
{
FILE *fp;
char ln[200];
ptrNode start = NULL;
const char filename[] = "thefile.txt";
fp = fopen(filename, "r");
if (fp == NULL)
{
fprintf(stderr, "File %s not found.n", filename);
}
else
{
while (fgets(ln, sizeof(ln), fp) != 0)
{
size_t len = strlen(ln);
if (len > 0)
ln[len-1] = ' ';
printf("[%s]n", ln);
induct(&start, ln);
}
fclose(fp);
print_list("After data read", start);
free_list(start);
}
return 0;
}
在valgrind
下运行的示例
==54054== Memcheck, a memory error detector
==54054== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==54054== Using Valgrind-3.12.0.SVN and LibVEX; rerun with -h for copyright info
==54054== Command: xyz
==54054==
[Denelia Alvaranga,R,M7_T4_T5_T6]
Prefect: Denelia Alvaranga, type R
M7(j=0)
T4(j=1)
T5(j=2)
T6(j=3)
[Sainna Christian,R,M4_M5_M6_T1_T2_T3_F5_F6]
Prefect: Sainna Christian, type R
M4(j=0)
M5(j=1)
M6(j=2)
T1(j=3)
T2(j=4)
T3(j=5)
F5(j=6)
F6(j=7)
[Kashielle Clarke,R,F1_T4_W4_F4_T5_W5_S5_W6_S6_M7_W7]
Prefect: Kashielle Clarke, type R
F1(j=0)
T4(j=1)
W4(j=2)
F4(j=3)
T5(j=4)
W5(j=5)
S5(j=6)
W6(j=7)
S6(j=8)
M7(j=9)
W7(j=10)
[Candice Gordon,R,M1_M2_M3_S3_T7]
Prefect: Candice Gordon, type R
M1(j=0)
M2(j=1)
M3(j=2)
S3(j=3)
T7(j=4)
[Alphene Groves,R,M2_T5_S7_W3]
Prefect: Alphene Groves, type R
M2(j=0)
T5(j=1)
S7(j=2)
W3(j=3)
[T-Anna Johnson,R,M7]
Prefect: T-Anna Johnson, type R
M7(j=0)
[Vanessa Lewis,R,M1_M2_M3_S3_T4_W4_S4_T5_S5_T6_S6]
Prefect: Vanessa Lewis, type R
M1(j=0)
M2(j=1)
M3(j=2)
S3(j=3)
T4(j=4)
W4(j=5)
S4(j=6)
T5(j=7)
S5(j=8)
T6(j=9)
S6(j=10)
[Rhoni-Ann Parkins,R,W1_S1_W2_S2_W3_S3_M4_T4_S4_F4_M5_T5_F5_M6_T6_F6_T7_F7]
Prefect: Rhoni-Ann Parkins, type R
W1(j=0)
S1(j=1)
W2(j=2)
S2(j=3)
W3(j=4)
S3(j=5)
M4(j=6)
T4(j=7)
S4(j=8)
F4(j=9)
M5(j=10)
T5(j=11)
F5(j=12)
M6(j=13)
T6(j=14)
F6(j=15)
T7(j=16)
F7(j=17)
[Ashleigh Graham,N6A ]
Prefect: Ashleigh Graham, type N6A
No free sessions for Ashleigh Graham
After data read:
Denelia Alvaranga [R] Mon: 7 Tue: 4 5 6 Wed: Thu: Fri:
Sainna Christian [R] Mon: 4 5 6 Tue: 1 2 3 Wed: Thu: Fri: 5 6
Kashielle Clarke [R] Mon: Tue: 7 4 5 Wed: 4 5 6 Thu: 7 5 6 Fri: 1 4
Candice Gordon [R] Mon: 1 2 3 Tue: 7 Wed: Thu: 3 Fri:
Alphene Groves [R] Mon: 2 Tue: 5 Wed: 3 Thu: 7 Fri:
T-Anna Johnson [R] Mon: 7 Tue: Wed: Thu: Fri:
Vanessa Lewis [R] Mon: 1 2 3 Tue: 4 5 Wed: 6 4 Thu: 3 4 5 Fri: 6
Rhoni-Ann Parkins [R] Mon: 4 Tue: 5 6 4 Wed: 1 5 3 6 7 Thu: 1 2 3 4 Fri:
==54054==
==54054== HEAP SUMMARY:
==54054== in use at exit: 26,297 bytes in 186 blocks
==54054== total heap usage: 297 allocs, 111 frees, 37,503 bytes allocated
==54054==
==54054== LEAK SUMMARY:
==54054== definitely lost: 0 bytes in 0 blocks
==54054== indirectly lost: 0 bytes in 0 blocks
==54054== possibly lost: 0 bytes in 0 blocks
==54054== still reachable: 0 bytes in 0 blocks
==54054== suppressed: 26,297 bytes in 186 blocks
==54054==
==54054== For counts of detected and suppressed errors, rerun with: -v
==54054== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
"抑制"内存是在Mac OS X(10.11.3)上运行的伪影。 我正在使用 GCC 5.3.0。 代码是干净的 - 它释放它分配的所有内存。(这就是"绝对丢失"、"间接丢失"、"可能丢失"和"仍然可以到达"的零的含义。
请注意,尽管使用了 valgrind
,但它并没有抱怨"越界"内存访问,但您可以看到 j
被打印并达到 Rhoni-Ann 的 'j=17'。 你绝对没有在你想要的地方写作——每个省长的输出与你的输入不匹配,因为j
失控了。 碰巧的是,当您在 64 位系统上写入j
设置为 17
的 newPtr->fses.F[j]
时,您仍在分配的内存范围内,因为struct free
占用 45 个字节,但填充到 48 个字节以对齐 8 字节指针nextPtr
,因此F[17]
在指针内(您随后会覆盖)。 如果使用 32 位编译器进行编译,则情况可能会有所不同。 (我收到一些"条件跳转或移动取决于未初始化的值"错误,但没有像我预期的那样"越界"写入。
其他问题:
- 请参阅[
while (!feof(file))
总是错误的],了解为什么您的输入循环有缺陷。 - 如果无法打开文件,则不应尝试关闭该文件。
- 您应该向
stderr
报告错误,而不是stdout
。 - 您应该使用换行符结束消息,以便看到它们。
fp
和ln
都应该是main
中的局部变量。
您- 覆盖了存储的名称,因为您没有创建字符串的副本以包含在结构中 - 它们都指向数组
ln
。 - 不要将
used
元素设置为已知值。