2
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct ll
{
    char data[50];
    struct ll *next;
    struct ll *prev;
};
typedef struct ll node;

main()
{
    node *head;node *temp1;node *temp2;
    head = (node *)malloc(sizeof(node));
    temp1 = head;
    FILE *p;
    int n;
    char s[50];
    p = fopen("studentRecords.txt","r");
    while((fscanf(p, "%s", s)) != EOF)
    {
        strcpy(head->data, s);
        head->next = (node *)malloc(sizeof(node));
        head->next = head->next->prev;
        head = head->next;
    }
    head = NULL;
    fclose(p);
    for(temp2 = temp1; temp2->next != NULL; temp2 = temp2->next)
        printf("%s\n", temp2->data);
}

当我运行上面的代码时,输​​出是分段错误。我该如何纠正?我有学生的记录作为studentRecords.txt文件中的字符串。

4

4 回答 4

1

您在next初始化之前使用:

head->next = (node *)malloc(sizeof(node));
head->next = head->next->prev;             /* head->next->prev is garbage. */
head = head->next;                         /* Now `head` points nowhere. */

稍后您最终会取消引用该垃圾值。此外,您正在覆盖刚刚从malloc.

于 2012-08-20T17:41:20.040 回答
0

这里的主要问题是声明: head->next = head->next->prev;. head->next->prev尚未初始化,因此当您head->next在下一条语句中将其分配给它时,它不会指向任何有用的东西。当您稍后尝试取消引用此值时,您的程序就会崩溃。你的意思可能是head->next->prev = head;.

也就是说,您的代码中还有许多其他值得评论的地方:

  1. 使用int main(void)而不是main().
  2. 不要malloc在 C 中将返回值强制转换,这是不必要的并且可以隐藏错误。
  3. malloc检查和的返回值fopen
  4. 如果您用于fscanf读取数据,请注意说明%s符只会读取直到遇到空白(在跳过初始空白之后),这可能是您想要的,也可能不是您想要的。此外,为了防止缓冲区溢出,您需要确保不会读取太多数据,%s因此始终使用最大字段宽度,即%49s. fgets并且sscanf通常是更好的方法。
  5. 不要忘记free()动态分配内存。
于 2012-08-20T17:59:33.090 回答
0
head->next = head->next->prev;

这是不正确的!head->next->prev指向“上帝甚至知道”的内存块,然后将其分配给head->next.

它将破坏其中有用的消息head->next并将其替换为垃圾。

于 2012-08-20T17:49:42.983 回答
0

您必须首先初始化头指针:

head = (node *)malloc(sizeof(node));
head->prev = NULL;
head->next = NULL;

要阅读我建议使用 fgets() 的文件:

p = fopen("studentRecords.txt","r");
while(!feof(p))
{
    fgets(head->data, 50, p);

通常你分配一个更大的缓冲区(比如 1K,内存通常很便宜),将一行读入缓冲区并检查它是否有效且长度合适。如果不是,您可以发出信息性错误(“第 XXX 行,值 'yyy' 太长”)并中止,或忽略该行并继续。您还可以使用 strdup() 来完全避免该问题,使用带有 *data 的结构而不是 data[50]。您实际上可能会以这种方式最终节省内存。

使用具有较短缓冲区的 fget 可能会导致 52 个字符的行被读取为两个错误记录而没有任何警告。

最后,这里的代码太紧凑了——你再次没有初始化指针:

    head->next = (node *)malloc(sizeof(node));
    head->next->prev = NULL;
    head->next->next = NULL;

一旦你在临时缓冲区中有你的行,你应该做的是创建一个新节点,完全初始化它,然后将它作为新的头:

    newNode = (node *)malloc(sizeof(node));
    newNode->prev = NULL;
    newNode->next = head;
    head->prev    = newNode;
    // A 
    strncpy(head->data, temp, 50);
    head->data[49] = 0x0;
    // B
    // head->data = strdup(temp);
    head = newNode;

一体式的 head->next = (node*)... 可能看起来很漂亮,但它往往很快就会成为阅读、维护和调试的地狱。而且编译器通常会在很短的时间内输出您梦寐以求的更优化的代码。

于 2012-08-20T17:44:36.447 回答