簡體   English   中英

C 鏈表問題,將鏈表打印到文件時出現段錯誤

[英]C linked list problem, segfault when printing the list to a file

我正在嘗試編寫和使用鏈表。 當嘗試將列表打印到文件時,第一個字符串被鏈接到最后一個節點並導致段錯誤。

我已經嘗試過調試,但它讓我無處可去。

它僅使用printListToFile(...)readstl(...)發生。

編碼

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

#define test "ijm digidimdimadam jjsklva /s4t\t \nmjam \nla kookaracha la kookaracha\n"
/*a method that creates a "blank" node, declares a the next node and points it to NULL, the char array is already initialized.*/
struct Node *makeNode();
struct Node *makeFullNode(struct Node *Next, char *Ptr);
struct Node *readFile(char *path);
struct Node *readstl(char*);
void printList(struct Node *head);
void insertToList(struct Node *node, char *str);
void printListToFile(char *path, struct Node *head);

int main(int argc, char *argv[])
{
    struct Node *head;
    head = (struct Node *)malloc(sizeof(struct Node));
    printf("this is mmn 23 Q3, a func that stores a file in a linked list and then prints it.\n");/*
    printf("%s\n",argv[1]);
    if (argc == 2) {    */
        head = readFile("tester1.txt");
        printList(head);
        printListToFile("test.tmp", head);
        insertToList(head->next, test);
        printf("head");
        free(head);
    /*}
    else if (argc > 2) {
        printf("Too many arguments supplied.\n");
    } else {
        printf("One argument expected.\n");
    }*/
    return 0;
}

struct Node *makeNode()
{
    struct Node *node;
    node = (struct Node *)malloc(sizeof(struct Node));
    if (node == NULL) {
        printf("memory allocation failed\n");
        return NULL;
    }
    node->next = NULL;
    return node;
}

/*a method that creates a node with all values, declares a the next node and points it to the next node recieved
and changes the char array to the one recieved.*/
struct Node *makeFullNode(struct Node *Next, char Ptr[])
{
    struct Node *node;
    node = (struct Node *)malloc(sizeof(struct Node));
    node->next = (struct Node *)malloc(sizeof(struct Node));
    node->ptr[NICE] = Ptr[NICE];
    node->next = Next;
    return node;
}

/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readFile(char *path)
{
    FILE *fptr;
    struct Node *curr, *head;
    curr = (struct Node *)malloc(sizeof(struct Node));
    head = (struct Node *)malloc(sizeof(struct Node));
    if (curr == NULL || head == NULL) {
        printf("memory allocation failed\n");
        return NULL;
    }
    curr = head;
    fptr = fopen(path,"r");
    if (fptr == NULL) {
        printf("error - failed to open file\n");
        exit(0);
        return NULL;
    }
    while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
    {
        curr->next = makeNode();
        curr = curr->next;  
    }
    if(ferror(fptr))/*checking if the loop ended for the right reason*/
    {
        printf("error - failed to read file\nthis is what we got so far\n");
    }
    printf("file succesfully read\n");
    fclose(fptr);
    free(curr);
    return head;
}

/*the method that reads the file into the list into the char array of each node and returns the head of the list */
struct Node *readstl(char *path)/*!!!problem!!!*/
{
    FILE *fptr;
    int i, len;
    struct Node *head;
    head = (struct Node *)malloc(sizeof(struct Node));
    fptr = fopen("readstrtofile.tmp", "w");
    if (fptr == NULL) {
        printf("error - failed to open file\n");
        exit(0);
        return NULL;
    }   
    len = strlen(path);
    for (i = 0; i < len && fputc(*(path + i), fptr) != EOF; i++);
    if (ferror(fptr))/*checking if the loop ended for the right reason*/
    {   
        printf("error - failed to read into file\nthis is what we got so far\n");
    }
    fclose(fptr);
    head = readFile("readstrtofile.tmp");
    remove("readstrtofile.tmp");
    return head;
}

/*a method that prints the recieved list depending on the list to have the equal length rows.
as specified in mmn 12 tab creating uneven rows is acceptable therefor when ever there is tab in the file
the rows will appear uneven as to tab takes a place of one char but prints to 8  blank spaces in ubuntu   */
void printList(struct Node *head)
{
    struct Node *curr;
    curr = (struct Node *)malloc(sizeof(struct Node));
    if (head == NULL) {
        printf("empty list\n");
        return;
    }
    if (curr==NULL) {
        printf("memory allocation failed\n");
        return;
    }
    printf("this is the list printed nicely\n");
    curr = head;
    printf("%s\n", curr->ptr);
    while (curr->next != NULL) {
        curr = curr->next;
        printf("%s\n", curr->ptr);
    }
    printf("\n/********************/\n");
}

/* a method that creates a new file named path and prints a list to it */
void printListToFile(char *path,struct Node *head)/*!!!problem!!!*/
{
    struct Node *curr;
    char c;
    int i;
    FILE *fptr;
    curr = (struct Node *)malloc(sizeof(struct Node));
    if (curr == NULL) {
        printf("memory allocation failed\n");
        exit(0);
    }
    curr = head;
    fptr = fopen(path, "w+");
    if (fptr == NULL) {
        printf("error - failed to open file\n");
        exit(0);
    }
    if (head == NULL) {
        printf("empty list\n");
        exit(0);
    }
    printf("this is the file %s printed nicely\n",path);
    curr = head;
    while (curr->next != NULL) {
        printf("new node -> ptr -> %s\n",curr->ptr);
        /*if(sizeof(curr->ptr)/sizeof(char)<=NICE)
        {*/
            for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);   
            printf("puting %s to file %s\n",curr->ptr,path);
            curr = curr->next;
            printf("bolili\n");
        /*}
        else
        {
            printf("lilibo\n");
            break;
        }*/
    }
    printf("\n/********************/\n");
}

/* a method that recievs a string turns it into a list and inserts it into another list */
void insertToList(struct Node *node, char *str)
{
    struct Node *tail, *head;
    tail = (struct Node *)malloc(sizeof(struct Node));
    head = (struct Node *)malloc(sizeof(struct Node));
    if (tail == NULL || head == NULL) {
        printf("memory allocation failed\n");
        return;
    }
    head = readstl(str);/*reading the string to a node*/
    printList(head);
    printf("\n/***********in insert*********/\n");
    tail = head;
    while (tail->next) {
        tail = tail->next;
    }/*getting tto the last node to connect it*/
    strcpy(tail->ptr, node->next->ptr);/*connecting the lists*/
    tail->next = node->next->next;
    strcpy(node->ptr, head->ptr);
    node->next = head->next;
    printf("inserted string successfully\n");
}

/* a method that returns the size of the list*/
unsigned int sizeOfList(struct Node *head)
{
    struct Node *tmp;
    int size;
    if (!(head))
        return 0;
    size = 1;
    tmp = (struct Node *)malloc(sizeof(struct Node));
    tmp = head;
    while ((tmp = tmp->next))
        size++;
    return size;
}

header 文件

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

#define NICE 80
#define debug "\n/****************/\n"

/*the node structure of a the list which contains a string the size we choose is nice 
to print by and a pointer to the next node in the list. */
struct Node {
    char ptr[NICE];
    struct Node *next;
};

/*makeNode - a method that returns a newely created node and sets all values to NULL values.*/
struct Node *makeNode();

/*makeFullNode - a method that return a newely created node with values set to params as listed below.
@param Next - tho ptr to the next node desired.
@param Ptr - the string that will go into the node ptr.*/
struct Node *makeFullNode(struct Node *Next, char *Ptr);

/*readFile - a method that reads a file into a linked list returning the head to that list.
it reads the file using fgets and a const to decide what size the node strings should be.
@param path - the name of the file to open.
@return the head of the list.*/
struct Node *readFile(char *path);

/*readstl - a method that reads a string into a linked list returning the head to that list.
it prints the list to a tmp file then reads the file using readFile.
@param path - the string to read.
@return the head of the list.*/
struct Node *readstl(char*);

/*printList - a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
@param head - the head of the linked list.*/
void printList(struct Node *head);

/*insertToList - a method that inserts a string into list.
it creates a new list using readstl the connects the nodes using the basic method.
@param node - the node to override.
@param str - the string to insert.*/
void insertToList(struct Node *node, char *str);

/*a method that prints the list to stdout.
it goes in loop on the nodes each time printing the node->ptr.
@param head - the head of the linked list.*/
void printListToFile(char *path,struct Node *head);

/*sizeOfList - a method that returns how many node are in the list.
it goes in a while loop incresing counter by 1 each iteration.
@param head - the head of the list to measure.
@return the size of the list.*/
unsigned int sizeOfList(struct Node *head);

我認為是這一行:

for(i=0;i<NICE && (c = fputc(curr->ptr[i],fptr)) != EOF;i++);

如果一切順利,為什么fputc會返回 EOF? 它將嘗試在ptr數組后面寫入字符。 fputc的手冊頁:

fputc()、putc() 和 putchar() 將寫入為 unsigned char 的字符在錯誤時返回到 int 或 EOF。

這意味着,只要fputc不返回錯誤代碼,您的循環就會寫入。 但是您可能想要的是寫 80 個( NICE不是一個好的常量名稱)或strlen(curr->ptr)字符。 假設基於您的 readFile function,您希望這兩件事都作為限制。 我建議將此行重寫為:

int len = strnlen(curr->ptr, 80);
if (fwrite(curr->ptr, 1, len, fptr) < 0) {
    printf("error writing file");
}

或者如果字符串總是 null 終止:

if (fputs(curr->ptr, fptr) < 0) {
    printf("error writing file");
}

ptr也不是數組的好名字。 一段時間后,它可能會使人們甚至您感到困惑,試圖理解代碼。 更好的名稱是valuetext (甚至arr會更好,因為它不是指針)。

readFile中,您有一個循環,您可以在其中讀取一行並將其放入curr->ptr中,然后創建一個新curr並將其鏈接到前一個curr

這會在您不需要的列表末尾創建一個額外的空curr ,因此您稍后將其釋放。 不幸的是,前一個節點的next指針仍然指向你剛剛釋放的空節點。

在不重構循環的情況下解決此問題的最簡單方法是保留前一個節點的記錄,如下所示:

struct Node* prev = NULL;
while (fgets(curr->ptr, NICE, fptr))/*if fgets returns NULL it means that we either reached EOF or error, both a reason to end the loop*/
{
    curr->next = makeNode();
    prev = curr;
    curr = curr->next;  
}

free(curr);
if (prev != NULL) 
{
    prev->next = NULL;
}
else
{
    head = NULL; // For the empty file case. head == curr in this case
}
// The other clean up stuff

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM